Merge branch 'InstallManagerService-completion' into 'master'
InstallManagerService completion This is a collection of fixes to finalize `InstallManagerService` now that !300 is merged. See merge request !318
This commit is contained in:
commit
de238f3f5f
@ -85,14 +85,13 @@ import org.fdroid.fdroid.data.App;
|
|||||||
import org.fdroid.fdroid.data.AppProvider;
|
import org.fdroid.fdroid.data.AppProvider;
|
||||||
import org.fdroid.fdroid.data.InstalledAppProvider;
|
import org.fdroid.fdroid.data.InstalledAppProvider;
|
||||||
import org.fdroid.fdroid.data.RepoProvider;
|
import org.fdroid.fdroid.data.RepoProvider;
|
||||||
import org.fdroid.fdroid.installer.Installer;
|
|
||||||
import org.fdroid.fdroid.installer.InstallManagerService;
|
import org.fdroid.fdroid.installer.InstallManagerService;
|
||||||
|
import org.fdroid.fdroid.installer.Installer;
|
||||||
import org.fdroid.fdroid.installer.InstallerFactory;
|
import org.fdroid.fdroid.installer.InstallerFactory;
|
||||||
import org.fdroid.fdroid.installer.InstallerService;
|
import org.fdroid.fdroid.installer.InstallerService;
|
||||||
import org.fdroid.fdroid.net.Downloader;
|
import org.fdroid.fdroid.net.Downloader;
|
||||||
import org.fdroid.fdroid.net.DownloaderService;
|
import org.fdroid.fdroid.net.DownloaderService;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -530,11 +529,8 @@ public class AppDetails extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
cleanUpFinishedDownload();
|
cleanUpFinishedDownload();
|
||||||
|
|
||||||
Uri localUri =
|
|
||||||
Uri.fromFile(new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH)));
|
|
||||||
localBroadcastManager.registerReceiver(installReceiver,
|
localBroadcastManager.registerReceiver(installReceiver,
|
||||||
Installer.getInstallIntentFilter(localUri));
|
Installer.getInstallIntentFilter(intent.getData()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,34 +45,34 @@ public class DefaultInstaller extends Installer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
|
protected void installPackage(Uri localApkUri, Uri downloadUri, String packageName) {
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED);
|
||||||
|
|
||||||
Utils.debugLog(TAG, "DefaultInstaller uri: " + uri + " file: " + new File(uri.getPath()));
|
Utils.debugLog(TAG, "DefaultInstaller uri: " + localApkUri + " file: " + new File(localApkUri.getPath()));
|
||||||
|
|
||||||
Uri sanitizedUri;
|
Uri sanitizedUri;
|
||||||
try {
|
try {
|
||||||
sanitizedUri = Installer.prepareApkFile(context, uri, packageName);
|
sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName);
|
||||||
} catch (Installer.InstallFailedException e) {
|
} catch (Installer.InstallFailedException e) {
|
||||||
Log.e(TAG, "prepareApkFile failed", e);
|
Log.e(TAG, "prepareApkFile failed", e);
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
||||||
e.getMessage());
|
e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent installIntent = new Intent(context, DefaultInstallerActivity.class);
|
Intent installIntent = new Intent(context, DefaultInstallerActivity.class);
|
||||||
installIntent.setAction(DefaultInstallerActivity.ACTION_INSTALL_PACKAGE);
|
installIntent.setAction(DefaultInstallerActivity.ACTION_INSTALL_PACKAGE);
|
||||||
installIntent.putExtra(DefaultInstallerActivity.EXTRA_ORIGINATING_URI, originatingUri);
|
installIntent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri);
|
||||||
installIntent.setData(sanitizedUri);
|
installIntent.setData(sanitizedUri);
|
||||||
|
|
||||||
PendingIntent installPendingIntent = PendingIntent.getActivity(
|
PendingIntent installPendingIntent = PendingIntent.getActivity(
|
||||||
context.getApplicationContext(),
|
context.getApplicationContext(),
|
||||||
uri.hashCode(),
|
localApkUri.hashCode(),
|
||||||
installIntent,
|
installIntent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
|
||||||
sendBroadcastInstall(uri, originatingUri,
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_USER_INTERACTION,
|
||||||
Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent);
|
installPendingIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -38,18 +38,15 @@ import org.fdroid.fdroid.R;
|
|||||||
public class DefaultInstallerActivity extends FragmentActivity {
|
public class DefaultInstallerActivity extends FragmentActivity {
|
||||||
public static final String TAG = "AndroidInstallerAct";
|
public static final String TAG = "AndroidInstallerAct";
|
||||||
|
|
||||||
public static final String ACTION_INSTALL_PACKAGE = "org.fdroid.fdroid.INSTALL_PACKAGE";
|
static final String ACTION_INSTALL_PACKAGE = "org.fdroid.fdroid.installer.DefaultInstaller.action.INSTALL_PACKAGE";
|
||||||
public static final String ACTION_UNINSTALL_PACKAGE = "org.fdroid.fdroid.UNINSTALL_PACKAGE";
|
static final String ACTION_UNINSTALL_PACKAGE = "org.fdroid.fdroid.installer.DefaultInstaller.action.UNINSTALL_PACKAGE";
|
||||||
|
|
||||||
public static final String EXTRA_UNINSTALL_PACKAGE_NAME = "uninstallPackageName";
|
static final String EXTRA_UNINSTALL_PACKAGE_NAME = "org.fdroid.fdroid.installer.DefaultInstaller.extra.UNINSTALL_PACKAGE_NAME";
|
||||||
public static final String EXTRA_ORIGINATING_URI = "originatingUri";
|
|
||||||
|
|
||||||
private static final int REQUEST_CODE_INSTALL = 0;
|
private static final int REQUEST_CODE_INSTALL = 0;
|
||||||
private static final int REQUEST_CODE_UNINSTALL = 1;
|
private static final int REQUEST_CODE_UNINSTALL = 1;
|
||||||
|
|
||||||
private Uri installOriginatingUri;
|
private Uri downloadUri;
|
||||||
private Uri installUri;
|
|
||||||
|
|
||||||
private String uninstallPackageName;
|
private String uninstallPackageName;
|
||||||
|
|
||||||
// for the broadcasts
|
// for the broadcasts
|
||||||
@ -64,10 +61,9 @@ public class DefaultInstallerActivity extends FragmentActivity {
|
|||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
if (ACTION_INSTALL_PACKAGE.equals(action)) {
|
if (ACTION_INSTALL_PACKAGE.equals(action)) {
|
||||||
installUri = intent.getData();
|
Uri localApkUri = intent.getData();
|
||||||
installOriginatingUri = intent.getParcelableExtra(EXTRA_ORIGINATING_URI);
|
downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI);
|
||||||
|
installPackage(localApkUri);
|
||||||
installPackage(installUri, installOriginatingUri);
|
|
||||||
} else if (ACTION_UNINSTALL_PACKAGE.equals(action)) {
|
} else if (ACTION_UNINSTALL_PACKAGE.equals(action)) {
|
||||||
uninstallPackageName = intent.getStringExtra(EXTRA_UNINSTALL_PACKAGE_NAME);
|
uninstallPackageName = intent.getStringExtra(EXTRA_UNINSTALL_PACKAGE_NAME);
|
||||||
|
|
||||||
@ -78,7 +74,7 @@ public class DefaultInstallerActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
private void installPackage(Uri uri, Uri originatingUri) {
|
private void installPackage(Uri uri) {
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
throw new RuntimeException("Set the data uri to point to an apk location!");
|
throw new RuntimeException("Set the data uri to point to an apk location!");
|
||||||
}
|
}
|
||||||
@ -121,12 +117,11 @@ public class DefaultInstallerActivity extends FragmentActivity {
|
|||||||
startActivityForResult(intent, REQUEST_CODE_INSTALL);
|
startActivityForResult(intent, REQUEST_CODE_INSTALL);
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
Log.e(TAG, "ActivityNotFoundException", e);
|
Log.e(TAG, "ActivityNotFoundException", e);
|
||||||
installer.sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
||||||
"This Android rom does not support ACTION_INSTALL_PACKAGE!");
|
"This Android rom does not support ACTION_INSTALL_PACKAGE!");
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED);
|
||||||
Installer.ACTION_INSTALL_STARTED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void uninstallPackage(String packageName) {
|
protected void uninstallPackage(String packageName) {
|
||||||
@ -172,31 +167,29 @@ public class DefaultInstallerActivity extends FragmentActivity {
|
|||||||
* never executed on Androids < 4.0
|
* never executed on Androids < 4.0
|
||||||
*/
|
*/
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE);
|
||||||
Installer.ACTION_INSTALL_COMPLETE);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback on N for https://gitlab.com/fdroid/fdroidclient/issues/631
|
// Fallback on N for https://gitlab.com/fdroid/fdroidclient/issues/631
|
||||||
if ("N".equals(Build.VERSION.CODENAME)) {
|
if ("N".equals(Build.VERSION.CODENAME)) {
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE);
|
||||||
Installer.ACTION_INSTALL_COMPLETE);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (resultCode) {
|
switch (resultCode) {
|
||||||
case Activity.RESULT_OK:
|
case Activity.RESULT_OK:
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri,
|
||||||
Installer.ACTION_INSTALL_COMPLETE);
|
Installer.ACTION_INSTALL_COMPLETE);
|
||||||
break;
|
break;
|
||||||
case Activity.RESULT_CANCELED:
|
case Activity.RESULT_CANCELED:
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri,
|
||||||
Installer.ACTION_INSTALL_INTERRUPTED);
|
Installer.ACTION_INSTALL_INTERRUPTED);
|
||||||
break;
|
break;
|
||||||
case Activity.RESULT_FIRST_USER:
|
case Activity.RESULT_FIRST_USER:
|
||||||
default:
|
default:
|
||||||
// AOSP returns Activity.RESULT_FIRST_USER on error
|
// AOSP returns Activity.RESULT_FIRST_USER on error
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri,
|
||||||
Installer.ACTION_INSTALL_INTERRUPTED,
|
Installer.ACTION_INSTALL_INTERRUPTED,
|
||||||
getString(R.string.install_error_unknown));
|
getString(R.string.install_error_unknown));
|
||||||
break;
|
break;
|
||||||
|
@ -46,14 +46,13 @@ public class ExtensionInstaller extends Installer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
|
protected void installPackage(Uri localApkUri, Uri downloadUri, String packageName) {
|
||||||
Uri sanitizedUri;
|
Uri sanitizedUri;
|
||||||
try {
|
try {
|
||||||
sanitizedUri = Installer.prepareApkFile(context, uri, packageName);
|
sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName);
|
||||||
} catch (InstallFailedException e) {
|
} catch (InstallFailedException e) {
|
||||||
Log.e(TAG, "prepareApkFile failed", e);
|
Log.e(TAG, "prepareApkFile failed", e);
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage());
|
||||||
e.getMessage());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +60,7 @@ public class ExtensionInstaller extends Installer {
|
|||||||
// NOTE: Disabled for debug builds to be able to use official extension from repo
|
// NOTE: Disabled for debug builds to be able to use official extension from repo
|
||||||
ApkSignatureVerifier signatureVerifier = new ApkSignatureVerifier(context);
|
ApkSignatureVerifier signatureVerifier = new ApkSignatureVerifier(context);
|
||||||
if (!BuildConfig.DEBUG && !signatureVerifier.hasFDroidSignature(new File(sanitizedUri.getPath()))) {
|
if (!BuildConfig.DEBUG && !signatureVerifier.hasFDroidSignature(new File(sanitizedUri.getPath()))) {
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
||||||
"APK signature of extension not correct!");
|
"APK signature of extension not correct!");
|
||||||
}
|
}
|
||||||
Intent installIntent = new Intent(context, InstallExtensionDialogActivity.class);
|
Intent installIntent = new Intent(context, InstallExtensionDialogActivity.class);
|
||||||
@ -70,15 +69,15 @@ public class ExtensionInstaller extends Installer {
|
|||||||
|
|
||||||
PendingIntent installPendingIntent = PendingIntent.getActivity(
|
PendingIntent installPendingIntent = PendingIntent.getActivity(
|
||||||
context.getApplicationContext(),
|
context.getApplicationContext(),
|
||||||
uri.hashCode(),
|
localApkUri.hashCode(),
|
||||||
installIntent,
|
installIntent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
|
||||||
sendBroadcastInstall(uri, originatingUri,
|
sendBroadcastInstall(downloadUri,
|
||||||
Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent);
|
Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent);
|
||||||
|
|
||||||
// don't use broadcasts for the rest of this special installer
|
// don't use broadcasts for the rest of this special installer
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_COMPLETE);
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,8 +55,10 @@ import java.util.Set;
|
|||||||
* <li>for a {@link Uri} ID, use {@code Uri}, {@link Intent#getData()}
|
* <li>for a {@link Uri} ID, use {@code Uri}, {@link Intent#getData()}
|
||||||
* <li>for a {@code String} ID, use {@code urlString}, {@link Uri#toString()}, or
|
* <li>for a {@code String} ID, use {@code urlString}, {@link Uri#toString()}, or
|
||||||
* {@link Intent#getDataString()}
|
* {@link Intent#getDataString()}
|
||||||
* <li>for an {@code int} ID, use {@link String#hashCode()}
|
* <li>for an {@code int} ID, use {@link String#hashCode()} or {@link Uri#hashCode()}
|
||||||
* </ul></p>
|
* </ul></p>
|
||||||
|
* The implementations of {@link Uri#toString()} and {@link Intent#getDataString()} both
|
||||||
|
* include caching of the generated {@code String}, so it should be plenty fast.
|
||||||
*/
|
*/
|
||||||
public class InstallManagerService extends Service {
|
public class InstallManagerService extends Service {
|
||||||
public static final String TAG = "InstallManagerService";
|
public static final String TAG = "InstallManagerService";
|
||||||
@ -154,7 +156,7 @@ public class InstallManagerService extends Service {
|
|||||||
Apk apk = new Apk(intent.getParcelableExtra(EXTRA_APK));
|
Apk apk = new Apk(intent.getParcelableExtra(EXTRA_APK));
|
||||||
addToActive(urlString, app, apk);
|
addToActive(urlString, app, apk);
|
||||||
|
|
||||||
NotificationCompat.Builder builder = createNotificationBuilder(intent.getDataString(), apk);
|
NotificationCompat.Builder builder = createNotificationBuilder(urlString, apk);
|
||||||
notificationManager.notify(urlString.hashCode(), builder.build());
|
notificationManager.notify(urlString.hashCode(), builder.build());
|
||||||
|
|
||||||
registerDownloaderReceivers(urlString, builder);
|
registerDownloaderReceivers(urlString, builder);
|
||||||
@ -224,18 +226,18 @@ public class InstallManagerService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
// elsewhere called urlString
|
// elsewhere called urlString
|
||||||
Uri originatingUri = intent.getData();
|
Uri downloadUri = intent.getData();
|
||||||
|
String urlString = downloadUri.toString();
|
||||||
File localFile = new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH));
|
File localFile = new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH));
|
||||||
Uri localUri = Uri.fromFile(localFile);
|
Uri localApkUri = Uri.fromFile(localFile);
|
||||||
|
|
||||||
Utils.debugLog(TAG, "download completed of " + originatingUri
|
Utils.debugLog(TAG, "download completed of " + urlString + " to " + localApkUri);
|
||||||
+ " to " + localUri);
|
|
||||||
|
|
||||||
unregisterDownloaderReceivers(intent.getDataString());
|
unregisterDownloaderReceivers(urlString);
|
||||||
|
registerInstallerReceivers(downloadUri);
|
||||||
|
|
||||||
registerInstallerReceivers(localUri);
|
Apk apk = ACTIVE_APKS.get(urlString);
|
||||||
Apk apk = ACTIVE_APKS.get(originatingUri.toString());
|
InstallerService.install(context, localApkUri, downloadUri, apk.packageName);
|
||||||
InstallerService.install(context, localUri, originatingUri, apk.packageName);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BroadcastReceiver interruptedReceiver = new BroadcastReceiver() {
|
BroadcastReceiver interruptedReceiver = new BroadcastReceiver() {
|
||||||
@ -262,19 +264,18 @@ public class InstallManagerService extends Service {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerInstallerReceivers(Uri uri) {
|
private void registerInstallerReceivers(Uri downloadUri) {
|
||||||
|
|
||||||
BroadcastReceiver installReceiver = new BroadcastReceiver() {
|
BroadcastReceiver installReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Uri originatingUri = intent.getParcelableExtra(Installer.EXTRA_ORIGINATING_URI);
|
String downloadUrl = intent.getDataString();
|
||||||
|
|
||||||
switch (intent.getAction()) {
|
switch (intent.getAction()) {
|
||||||
case Installer.ACTION_INSTALL_STARTED:
|
case Installer.ACTION_INSTALL_STARTED:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
break;
|
break;
|
||||||
case Installer.ACTION_INSTALL_COMPLETE:
|
case Installer.ACTION_INSTALL_COMPLETE:
|
||||||
Apk apkComplete = removeFromActive(originatingUri.toString());
|
Apk apkComplete = removeFromActive(downloadUrl);
|
||||||
|
|
||||||
PackageManagerCompat.setInstaller(getPackageManager(), apkComplete.packageName);
|
PackageManagerCompat.setInstaller(getPackageManager(), apkComplete.packageName);
|
||||||
|
|
||||||
@ -286,31 +287,31 @@ public class InstallManagerService extends Service {
|
|||||||
|
|
||||||
// show notification if app details is not visible
|
// show notification if app details is not visible
|
||||||
if (!TextUtils.isEmpty(errorMessage)) {
|
if (!TextUtils.isEmpty(errorMessage)) {
|
||||||
App app = getAppFromActive(originatingUri.toString());
|
App app = getAppFromActive(downloadUrl);
|
||||||
String title = String.format(
|
|
||||||
getString(R.string.install_error_notify_title),
|
|
||||||
app.name);
|
|
||||||
|
|
||||||
// show notification if app details is not visible
|
// show notification if app details is not visible
|
||||||
if (AppDetails.isAppVisible(app.packageName)) {
|
if (AppDetails.isAppVisible(app.packageName)) {
|
||||||
cancelNotification(originatingUri.toString());
|
cancelNotification(downloadUrl);
|
||||||
} else {
|
} else {
|
||||||
notifyError(originatingUri.toString(), title, errorMessage);
|
String title = String.format(
|
||||||
|
getString(R.string.install_error_notify_title),
|
||||||
|
app.name);
|
||||||
|
notifyError(downloadUrl, title, errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
removeFromActive(downloadUrl);
|
||||||
localBroadcastManager.unregisterReceiver(this);
|
localBroadcastManager.unregisterReceiver(this);
|
||||||
break;
|
break;
|
||||||
case Installer.ACTION_INSTALL_USER_INTERACTION:
|
case Installer.ACTION_INSTALL_USER_INTERACTION:
|
||||||
PendingIntent installPendingIntent =
|
PendingIntent installPendingIntent =
|
||||||
intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI);
|
intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI);
|
||||||
|
|
||||||
Apk apkUserInteraction = getApkFromActive(originatingUri.toString());
|
Apk apkUserInteraction = getApkFromActive(downloadUrl);
|
||||||
// show notification if app details is not visible
|
// show notification if app details is not visible
|
||||||
if (AppDetails.isAppVisible(apkUserInteraction.packageName)) {
|
if (AppDetails.isAppVisible(apkUserInteraction.packageName)) {
|
||||||
cancelNotification(originatingUri.toString());
|
cancelNotification(downloadUrl);
|
||||||
} else {
|
} else {
|
||||||
notifyDownloadComplete(apkUserInteraction, originatingUri.toString(), installPendingIntent);
|
notifyDownloadComplete(apkUserInteraction, downloadUrl, installPendingIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -321,7 +322,7 @@ public class InstallManagerService extends Service {
|
|||||||
};
|
};
|
||||||
|
|
||||||
localBroadcastManager.registerReceiver(installReceiver,
|
localBroadcastManager.registerReceiver(installReceiver,
|
||||||
Installer.getInstallIntentFilter(uri));
|
Installer.getInstallIntentFilter(downloadUri));
|
||||||
}
|
}
|
||||||
|
|
||||||
private NotificationCompat.Builder createNotificationBuilder(String urlString, Apk apk) {
|
private NotificationCompat.Builder createNotificationBuilder(String urlString, Apk apk) {
|
||||||
|
@ -46,7 +46,7 @@ import java.security.NoSuchAlgorithmException;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Handles the actual install process. Subclasses implement the details.
|
||||||
*/
|
*/
|
||||||
public abstract class Installer {
|
public abstract class Installer {
|
||||||
final Context context;
|
final Context context;
|
||||||
@ -64,10 +64,14 @@ public abstract class Installer {
|
|||||||
public static final String ACTION_UNINSTALL_USER_INTERACTION = "org.fdroid.fdroid.installer.Installer.action.UNINSTALL_USER_INTERACTION";
|
public static final String ACTION_UNINSTALL_USER_INTERACTION = "org.fdroid.fdroid.installer.Installer.action.UNINSTALL_USER_INTERACTION";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as http://developer.android.com/reference/android/content/Intent.html#EXTRA_ORIGINATING_URI
|
* The URI where the APK was originally downloaded from. This is also used
|
||||||
* In InstallManagerService often called urlString
|
* as the unique ID representing this in the whole install process in
|
||||||
|
* {@link InstallManagerService}, there is is generally known as the
|
||||||
|
* "download URL" since it is the URL used to download the APK.
|
||||||
|
*
|
||||||
|
* @see Intent#EXTRA_ORIGINATING_URI
|
||||||
*/
|
*/
|
||||||
public static final String EXTRA_ORIGINATING_URI = "org.fdroid.fdroid.installer.Installer.extra.ORIGINATING_URI";
|
static final String EXTRA_DOWNLOAD_URI = "org.fdroid.fdroid.installer.Installer.extra.DOWNLOAD_URI";
|
||||||
public static final String EXTRA_PACKAGE_NAME = "org.fdroid.fdroid.installer.Installer.extra.PACKAGE_NAME";
|
public static final String EXTRA_PACKAGE_NAME = "org.fdroid.fdroid.installer.Installer.extra.PACKAGE_NAME";
|
||||||
public static final String EXTRA_USER_INTERACTION_PI = "org.fdroid.fdroid.installer.Installer.extra.USER_INTERACTION_PI";
|
public static final String EXTRA_USER_INTERACTION_PI = "org.fdroid.fdroid.installer.Installer.extra.USER_INTERACTION_PI";
|
||||||
public static final String EXTRA_ERROR_MESSAGE = "org.fdroid.fdroid.net.installer.Installer.extra.ERROR_MESSAGE";
|
public static final String EXTRA_ERROR_MESSAGE = "org.fdroid.fdroid.net.installer.Installer.extra.ERROR_MESSAGE";
|
||||||
@ -91,7 +95,7 @@ public abstract class Installer {
|
|||||||
localBroadcastManager = LocalBroadcastManager.getInstance(context);
|
localBroadcastManager = LocalBroadcastManager.getInstance(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri prepareApkFile(Context context, Uri uri, String packageName)
|
static Uri prepareApkFile(Context context, Uri uri, String packageName)
|
||||||
throws InstallFailedException {
|
throws InstallFailedException {
|
||||||
|
|
||||||
File apkFile = new File(uri.getPath());
|
File apkFile = new File(uri.getPath());
|
||||||
@ -229,7 +233,7 @@ public abstract class Installer {
|
|||||||
/**
|
/**
|
||||||
* Checks the APK file against the provided hash, returning whether it is a match.
|
* Checks the APK file against the provided hash, returning whether it is a match.
|
||||||
*/
|
*/
|
||||||
public static boolean verifyApkFile(File apkFile, String hash, String hashType)
|
static boolean verifyApkFile(File apkFile, String hash, String hashType)
|
||||||
throws NoSuchAlgorithmException {
|
throws NoSuchAlgorithmException {
|
||||||
if (!apkFile.exists()) {
|
if (!apkFile.exists()) {
|
||||||
return false;
|
return false;
|
||||||
@ -238,24 +242,23 @@ public abstract class Installer {
|
|||||||
return hasher.match(hash);
|
return hasher.match(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action,
|
void sendBroadcastInstall(Uri downloadUri, String action,
|
||||||
PendingIntent pendingIntent) {
|
PendingIntent pendingIntent) {
|
||||||
sendBroadcastInstall(uri, originatingUri, action, pendingIntent, null);
|
sendBroadcastInstall(downloadUri, action, pendingIntent, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action) {
|
void sendBroadcastInstall(Uri downloadUri, String action) {
|
||||||
sendBroadcastInstall(uri, originatingUri, action, null, null);
|
sendBroadcastInstall(downloadUri, action, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action, String errorMessage) {
|
void sendBroadcastInstall(Uri downloadUri, String action, String errorMessage) {
|
||||||
sendBroadcastInstall(uri, originatingUri, action, null, errorMessage);
|
sendBroadcastInstall(downloadUri, action, null, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action,
|
void sendBroadcastInstall(Uri downloadUri, String action,
|
||||||
PendingIntent pendingIntent, String errorMessage) {
|
PendingIntent pendingIntent, String errorMessage) {
|
||||||
Intent intent = new Intent(action);
|
Intent intent = new Intent(action);
|
||||||
intent.setData(uri);
|
intent.setData(downloadUri);
|
||||||
intent.putExtra(Installer.EXTRA_ORIGINATING_URI, originatingUri);
|
|
||||||
intent.putExtra(Installer.EXTRA_USER_INTERACTION_PI, pendingIntent);
|
intent.putExtra(Installer.EXTRA_USER_INTERACTION_PI, pendingIntent);
|
||||||
if (!TextUtils.isEmpty(errorMessage)) {
|
if (!TextUtils.isEmpty(errorMessage)) {
|
||||||
intent.putExtra(Installer.EXTRA_ERROR_MESSAGE, errorMessage);
|
intent.putExtra(Installer.EXTRA_ERROR_MESSAGE, errorMessage);
|
||||||
@ -263,20 +266,20 @@ public abstract class Installer {
|
|||||||
localBroadcastManager.sendBroadcast(intent);
|
localBroadcastManager.sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastUninstall(String packageName, String action, String errorMessage) {
|
void sendBroadcastUninstall(String packageName, String action, String errorMessage) {
|
||||||
sendBroadcastUninstall(packageName, action, null, errorMessage);
|
sendBroadcastUninstall(packageName, action, null, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastUninstall(String packageName, String action) {
|
void sendBroadcastUninstall(String packageName, String action) {
|
||||||
sendBroadcastUninstall(packageName, action, null, null);
|
sendBroadcastUninstall(packageName, action, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastUninstall(String packageName, String action,
|
void sendBroadcastUninstall(String packageName, String action,
|
||||||
PendingIntent pendingIntent) {
|
PendingIntent pendingIntent) {
|
||||||
sendBroadcastUninstall(packageName, action, pendingIntent, null);
|
sendBroadcastUninstall(packageName, action, pendingIntent, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastUninstall(String packageName, String action,
|
void sendBroadcastUninstall(String packageName, String action,
|
||||||
PendingIntent pendingIntent, String errorMessage) {
|
PendingIntent pendingIntent, String errorMessage) {
|
||||||
Uri uri = Uri.fromParts("package", packageName, null);
|
Uri uri = Uri.fromParts("package", packageName, null);
|
||||||
|
|
||||||
@ -290,6 +293,10 @@ public abstract class Installer {
|
|||||||
localBroadcastManager.sendBroadcast(intent);
|
localBroadcastManager.sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an {@link IntentFilter} for matching events from the install
|
||||||
|
* process based on the original download URL as a {@link Uri}.
|
||||||
|
*/
|
||||||
public static IntentFilter getInstallIntentFilter(Uri uri) {
|
public static IntentFilter getInstallIntentFilter(Uri uri) {
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
IntentFilter intentFilter = new IntentFilter();
|
||||||
intentFilter.addAction(Installer.ACTION_INSTALL_STARTED);
|
intentFilter.addAction(Installer.ACTION_INSTALL_STARTED);
|
||||||
@ -297,6 +304,7 @@ public abstract class Installer {
|
|||||||
intentFilter.addAction(Installer.ACTION_INSTALL_INTERRUPTED);
|
intentFilter.addAction(Installer.ACTION_INSTALL_INTERRUPTED);
|
||||||
intentFilter.addAction(Installer.ACTION_INSTALL_USER_INTERACTION);
|
intentFilter.addAction(Installer.ACTION_INSTALL_USER_INTERACTION);
|
||||||
intentFilter.addDataScheme(uri.getScheme());
|
intentFilter.addDataScheme(uri.getScheme());
|
||||||
|
intentFilter.addDataAuthority(uri.getHost(), String.valueOf(uri.getPort()));
|
||||||
intentFilter.addDataPath(uri.getPath(), PatternMatcher.PATTERN_LITERAL);
|
intentFilter.addDataPath(uri.getPath(), PatternMatcher.PATTERN_LITERAL);
|
||||||
return intentFilter;
|
return intentFilter;
|
||||||
}
|
}
|
||||||
@ -312,10 +320,20 @@ public abstract class Installer {
|
|||||||
return intentFilter;
|
return intentFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void installPackage(Uri uri, Uri originatingUri, String packageName);
|
/**
|
||||||
|
* @param localApkUri points to the local copy of the APK to be installed
|
||||||
|
* @param downloadUri serves as the unique ID for all actions related to the
|
||||||
|
* installation of that specific APK
|
||||||
|
* @param packageName package name of the app that should be installed
|
||||||
|
*/
|
||||||
|
protected abstract void installPackage(Uri localApkUri, Uri downloadUri, String packageName);
|
||||||
|
|
||||||
protected abstract void uninstallPackage(String packageName);
|
protected abstract void uninstallPackage(String packageName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This {@link Installer} instance is capable of "unattended" install and
|
||||||
|
* uninstall activities, without the system enforcing a user prompt.
|
||||||
|
*/
|
||||||
protected abstract boolean isUnattended();
|
protected abstract boolean isUnattended();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,10 @@ import android.net.Uri;
|
|||||||
* i.e., runs sequentially
|
* i.e., runs sequentially
|
||||||
* - no cancel operation is needed. Cancelling an installation
|
* - no cancel operation is needed. Cancelling an installation
|
||||||
* would be the same as starting uninstall afterwards
|
* would be the same as starting uninstall afterwards
|
||||||
|
* <p/>
|
||||||
|
* The download URL is only used as the unique ID that represents this
|
||||||
|
* particular apk throughout the whole install process in
|
||||||
|
* {@link InstallManagerService}.
|
||||||
*/
|
*/
|
||||||
public class InstallerService extends IntentService {
|
public class InstallerService extends IntentService {
|
||||||
|
|
||||||
@ -50,9 +54,8 @@ public class InstallerService extends IntentService {
|
|||||||
|
|
||||||
if (ACTION_INSTALL.equals(intent.getAction())) {
|
if (ACTION_INSTALL.equals(intent.getAction())) {
|
||||||
Uri uri = intent.getData();
|
Uri uri = intent.getData();
|
||||||
Uri originatingUri = intent.getParcelableExtra(Installer.EXTRA_ORIGINATING_URI);
|
Uri downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI);
|
||||||
|
installer.installPackage(uri, downloadUri, packageName);
|
||||||
installer.installPackage(uri, originatingUri, packageName);
|
|
||||||
} else if (ACTION_UNINSTALL.equals(intent.getAction())) {
|
} else if (ACTION_UNINSTALL.equals(intent.getAction())) {
|
||||||
installer.uninstallPackage(packageName);
|
installer.uninstallPackage(packageName);
|
||||||
}
|
}
|
||||||
@ -61,16 +64,16 @@ public class InstallerService extends IntentService {
|
|||||||
/**
|
/**
|
||||||
* Install an apk from {@link Uri}
|
* Install an apk from {@link Uri}
|
||||||
*
|
*
|
||||||
* @param context this app's {@link Context}
|
* @param context this app's {@link Context}
|
||||||
* @param uri {@link Uri} pointing to (downloaded) local apk file
|
* @param localApkUri {@link Uri} pointing to (downloaded) local apk file
|
||||||
* @param originatingUri {@link Uri} where the apk has been downloaded from
|
* @param downloadUri {@link Uri} where the apk has been downloaded from
|
||||||
* @param packageName package name of the app that should be installed
|
* @param packageName package name of the app that should be installed
|
||||||
*/
|
*/
|
||||||
public static void install(Context context, Uri uri, Uri originatingUri, String packageName) {
|
public static void install(Context context, Uri localApkUri, Uri downloadUri, String packageName) {
|
||||||
Intent intent = new Intent(context, InstallerService.class);
|
Intent intent = new Intent(context, InstallerService.class);
|
||||||
intent.setAction(ACTION_INSTALL);
|
intent.setAction(ACTION_INSTALL);
|
||||||
intent.setData(uri);
|
intent.setData(localApkUri);
|
||||||
intent.putExtra(Installer.EXTRA_ORIGINATING_URI, originatingUri);
|
intent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri);
|
||||||
intent.putExtra(Installer.EXTRA_PACKAGE_NAME, packageName);
|
intent.putExtra(Installer.EXTRA_PACKAGE_NAME, packageName);
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
|
@ -297,15 +297,15 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installPackage(final Uri uri, final Uri originatingUri, String packageName) {
|
protected void installPackage(final Uri localApkUri, final Uri downloadUri, String packageName) {
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED);
|
||||||
|
|
||||||
final Uri sanitizedUri;
|
final Uri sanitizedUri;
|
||||||
try {
|
try {
|
||||||
sanitizedUri = Installer.prepareApkFile(context, uri, packageName);
|
sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName);
|
||||||
} catch (Installer.InstallFailedException e) {
|
} catch (Installer.InstallFailedException e) {
|
||||||
Log.e(TAG, "prepareApkFile failed", e);
|
Log.e(TAG, "prepareApkFile failed", e);
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
||||||
e.getMessage());
|
e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -318,9 +318,9 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
@Override
|
@Override
|
||||||
public void handleResult(String packageName, int returnCode) throws RemoteException {
|
public void handleResult(String packageName, int returnCode) throws RemoteException {
|
||||||
if (returnCode == INSTALL_SUCCEEDED) {
|
if (returnCode == INSTALL_SUCCEEDED) {
|
||||||
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_COMPLETE);
|
sendBroadcastInstall(downloadUri, ACTION_INSTALL_COMPLETE);
|
||||||
} else {
|
} else {
|
||||||
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED,
|
||||||
"Error " + returnCode + ": "
|
"Error " + returnCode + ": "
|
||||||
+ INSTALL_RETURN_CODES.get(returnCode));
|
+ INSTALL_RETURN_CODES.get(returnCode));
|
||||||
}
|
}
|
||||||
@ -330,7 +330,7 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
try {
|
try {
|
||||||
boolean hasPermissions = privService.hasPrivilegedPermissions();
|
boolean hasPermissions = privService.hasPrivilegedPermissions();
|
||||||
if (!hasPermissions) {
|
if (!hasPermissions) {
|
||||||
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED,
|
||||||
context.getString(R.string.system_install_denied_permissions));
|
context.getString(R.string.system_install_denied_permissions));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -339,7 +339,7 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
null, callback);
|
null, callback);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "RemoteException", e);
|
Log.e(TAG, "RemoteException", e);
|
||||||
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED,
|
||||||
"connecting to privileged service failed");
|
"connecting to privileged service failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,13 @@ import org.fdroid.fdroid.FDroidApp;
|
|||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
import org.fdroid.fdroid.installer.Installer;
|
import org.fdroid.fdroid.installer.Installer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the confirmation prompt for when the user chooses to
|
||||||
|
* uninstall an app. This has to be implemented here for the privileged
|
||||||
|
* extension, it is only shown for {@link Installer} instances that can do
|
||||||
|
* installs and uninstalls without user prompts, which is detected via
|
||||||
|
* {@link Installer#isUnattended()}.
|
||||||
|
*/
|
||||||
public class UninstallDialogActivity extends FragmentActivity {
|
public class UninstallDialogActivity extends FragmentActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,14 +44,10 @@ import org.fdroid.fdroid.data.App;
|
|||||||
import org.fdroid.fdroid.data.NewRepoConfig;
|
import org.fdroid.fdroid.data.NewRepoConfig;
|
||||||
import org.fdroid.fdroid.installer.InstallManagerService;
|
import org.fdroid.fdroid.installer.InstallManagerService;
|
||||||
import org.fdroid.fdroid.installer.Installer;
|
import org.fdroid.fdroid.installer.Installer;
|
||||||
import org.fdroid.fdroid.installer.InstallerService;
|
|
||||||
import org.fdroid.fdroid.localrepo.LocalRepoManager;
|
import org.fdroid.fdroid.localrepo.LocalRepoManager;
|
||||||
import org.fdroid.fdroid.localrepo.SwapService;
|
import org.fdroid.fdroid.localrepo.SwapService;
|
||||||
import org.fdroid.fdroid.localrepo.peers.Peer;
|
import org.fdroid.fdroid.localrepo.peers.Peer;
|
||||||
import org.fdroid.fdroid.net.Downloader;
|
|
||||||
import org.fdroid.fdroid.net.DownloaderService;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -773,26 +769,10 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
public void install(@NonNull final App app) {
|
public void install(@NonNull final App app) {
|
||||||
final Apk apk = ApkProvider.Helper.find(this, app.packageName, app.suggestedVersionCode);
|
final Apk apk = ApkProvider.Helper.find(this, app.packageName, app.suggestedVersionCode);
|
||||||
String urlString = apk.getUrl();
|
Uri downloadUri = Uri.parse(apk.getUrl());
|
||||||
BroadcastReceiver downloadCompleteReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
String path = intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH);
|
|
||||||
handleDownloadComplete(new File(path), app.packageName, intent.getDataString());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
localBroadcastManager.registerReceiver(downloadCompleteReceiver,
|
|
||||||
DownloaderService.getIntentFilter(urlString, Downloader.ACTION_COMPLETE));
|
|
||||||
InstallManagerService.queue(this, app, apk);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleDownloadComplete(File apkFile, String packageName, String urlString) {
|
|
||||||
Uri originatingUri = Uri.parse(urlString);
|
|
||||||
Uri localUri = Uri.fromFile(apkFile);
|
|
||||||
|
|
||||||
localBroadcastManager.registerReceiver(installReceiver,
|
localBroadcastManager.registerReceiver(installReceiver,
|
||||||
Installer.getInstallIntentFilter(Uri.fromFile(apkFile)));
|
Installer.getInstallIntentFilter(downloadUri));
|
||||||
InstallerService.install(this, localUri, originatingUri, packageName);
|
InstallManagerService.queue(this, app, apk);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final BroadcastReceiver installReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver installReceiver = new BroadcastReceiver() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user