diff --git a/app/src/main/java/org/fdroid/fdroid/AppDetails.java b/app/src/main/java/org/fdroid/fdroid/AppDetails.java index 5eb446118..2f633bde2 100644 --- a/app/src/main/java/org/fdroid/fdroid/AppDetails.java +++ b/app/src/main/java/org/fdroid/fdroid/AppDetails.java @@ -85,14 +85,13 @@ import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.InstalledAppProvider; import org.fdroid.fdroid.data.RepoProvider; -import org.fdroid.fdroid.installer.Installer; import org.fdroid.fdroid.installer.InstallManagerService; +import org.fdroid.fdroid.installer.Installer; import org.fdroid.fdroid.installer.InstallerFactory; import org.fdroid.fdroid.installer.InstallerService; import org.fdroid.fdroid.net.Downloader; import org.fdroid.fdroid.net.DownloaderService; -import java.io.File; import java.util.Iterator; import java.util.List; @@ -530,11 +529,8 @@ public class AppDetails extends AppCompatActivity { @Override public void onReceive(Context context, Intent intent) { cleanUpFinishedDownload(); - - Uri localUri = - Uri.fromFile(new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH))); localBroadcastManager.registerReceiver(installReceiver, - Installer.getInstallIntentFilter(localUri)); + Installer.getInstallIntentFilter(intent.getData())); } }; diff --git a/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java b/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java index c6d73654f..b3bcf6218 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java @@ -45,34 +45,34 @@ public class DefaultInstaller extends Installer { } @Override - protected void installPackage(Uri uri, Uri originatingUri, String packageName) { - sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED); + protected void installPackage(Uri localApkUri, Uri downloadUri, String packageName) { + 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; try { - sanitizedUri = Installer.prepareApkFile(context, uri, packageName); + sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName); } catch (Installer.InstallFailedException e) { Log.e(TAG, "prepareApkFile failed", e); - sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED, + sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage()); return; } Intent installIntent = new Intent(context, DefaultInstallerActivity.class); installIntent.setAction(DefaultInstallerActivity.ACTION_INSTALL_PACKAGE); - installIntent.putExtra(DefaultInstallerActivity.EXTRA_ORIGINATING_URI, originatingUri); + installIntent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri); installIntent.setData(sanitizedUri); PendingIntent installPendingIntent = PendingIntent.getActivity( context.getApplicationContext(), - uri.hashCode(), + localApkUri.hashCode(), installIntent, PendingIntent.FLAG_UPDATE_CURRENT); - sendBroadcastInstall(uri, originatingUri, - Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent); + sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_USER_INTERACTION, + installPendingIntent); } @Override diff --git a/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstallerActivity.java b/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstallerActivity.java index 6e1e64ff4..06e7442d2 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstallerActivity.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstallerActivity.java @@ -38,18 +38,15 @@ import org.fdroid.fdroid.R; public class DefaultInstallerActivity extends FragmentActivity { public static final String TAG = "AndroidInstallerAct"; - public static final String ACTION_INSTALL_PACKAGE = "org.fdroid.fdroid.INSTALL_PACKAGE"; - public static final String ACTION_UNINSTALL_PACKAGE = "org.fdroid.fdroid.UNINSTALL_PACKAGE"; + static final String ACTION_INSTALL_PACKAGE = "org.fdroid.fdroid.installer.DefaultInstaller.action.INSTALL_PACKAGE"; + static final String ACTION_UNINSTALL_PACKAGE = "org.fdroid.fdroid.installer.DefaultInstaller.action.UNINSTALL_PACKAGE"; - public static final String EXTRA_UNINSTALL_PACKAGE_NAME = "uninstallPackageName"; - public static final String EXTRA_ORIGINATING_URI = "originatingUri"; + static final String EXTRA_UNINSTALL_PACKAGE_NAME = "org.fdroid.fdroid.installer.DefaultInstaller.extra.UNINSTALL_PACKAGE_NAME"; private static final int REQUEST_CODE_INSTALL = 0; private static final int REQUEST_CODE_UNINSTALL = 1; - private Uri installOriginatingUri; - private Uri installUri; - + private Uri downloadUri; private String uninstallPackageName; // for the broadcasts @@ -64,10 +61,9 @@ public class DefaultInstallerActivity extends FragmentActivity { Intent intent = getIntent(); String action = intent.getAction(); if (ACTION_INSTALL_PACKAGE.equals(action)) { - installUri = intent.getData(); - installOriginatingUri = intent.getParcelableExtra(EXTRA_ORIGINATING_URI); - - installPackage(installUri, installOriginatingUri); + Uri localApkUri = intent.getData(); + downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI); + installPackage(localApkUri); } else if (ACTION_UNINSTALL_PACKAGE.equals(action)) { uninstallPackageName = intent.getStringExtra(EXTRA_UNINSTALL_PACKAGE_NAME); @@ -78,7 +74,7 @@ public class DefaultInstallerActivity extends FragmentActivity { } @SuppressLint("InlinedApi") - private void installPackage(Uri uri, Uri originatingUri) { + private void installPackage(Uri uri) { if (uri == null) { 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); } catch (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!"); finish(); } - installer.sendBroadcastInstall(installUri, installOriginatingUri, - Installer.ACTION_INSTALL_STARTED); + installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED); } protected void uninstallPackage(String packageName) { @@ -172,31 +167,29 @@ public class DefaultInstallerActivity extends FragmentActivity { * never executed on Androids < 4.0 */ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - installer.sendBroadcastInstall(installUri, installOriginatingUri, - Installer.ACTION_INSTALL_COMPLETE); + installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE); break; } // Fallback on N for https://gitlab.com/fdroid/fdroidclient/issues/631 if ("N".equals(Build.VERSION.CODENAME)) { - installer.sendBroadcastInstall(installUri, installOriginatingUri, - Installer.ACTION_INSTALL_COMPLETE); + installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE); break; } switch (resultCode) { case Activity.RESULT_OK: - installer.sendBroadcastInstall(installUri, installOriginatingUri, + installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE); break; case Activity.RESULT_CANCELED: - installer.sendBroadcastInstall(installUri, installOriginatingUri, + installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED); break; case Activity.RESULT_FIRST_USER: default: // AOSP returns Activity.RESULT_FIRST_USER on error - installer.sendBroadcastInstall(installUri, installOriginatingUri, + installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, getString(R.string.install_error_unknown)); break; diff --git a/app/src/main/java/org/fdroid/fdroid/installer/ExtensionInstaller.java b/app/src/main/java/org/fdroid/fdroid/installer/ExtensionInstaller.java index 970b8f99f..adb61d16d 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/ExtensionInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/ExtensionInstaller.java @@ -46,14 +46,13 @@ public class ExtensionInstaller extends Installer { } @Override - protected void installPackage(Uri uri, Uri originatingUri, String packageName) { + protected void installPackage(Uri localApkUri, Uri downloadUri, String packageName) { Uri sanitizedUri; try { - sanitizedUri = Installer.prepareApkFile(context, uri, packageName); + sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName); } catch (InstallFailedException e) { Log.e(TAG, "prepareApkFile failed", e); - sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED, - e.getMessage()); + sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage()); return; } @@ -61,7 +60,7 @@ public class ExtensionInstaller extends Installer { // NOTE: Disabled for debug builds to be able to use official extension from repo ApkSignatureVerifier signatureVerifier = new ApkSignatureVerifier(context); 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!"); } Intent installIntent = new Intent(context, InstallExtensionDialogActivity.class); @@ -70,15 +69,15 @@ public class ExtensionInstaller extends Installer { PendingIntent installPendingIntent = PendingIntent.getActivity( context.getApplicationContext(), - uri.hashCode(), + localApkUri.hashCode(), installIntent, PendingIntent.FLAG_UPDATE_CURRENT); - sendBroadcastInstall(uri, originatingUri, + sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent); // 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 diff --git a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java index 9903ad188..9494fdacf 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java @@ -55,8 +55,10 @@ import java.util.Set; *
  • for a {@link Uri} ID, use {@code Uri}, {@link Intent#getData()} *
  • for a {@code String} ID, use {@code urlString}, {@link Uri#toString()}, or * {@link Intent#getDataString()} - *
  • for an {@code int} ID, use {@link String#hashCode()} + *
  • for an {@code int} ID, use {@link String#hashCode()} or {@link Uri#hashCode()} *

    + * 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 static final String TAG = "InstallManagerService"; @@ -154,7 +156,7 @@ public class InstallManagerService extends Service { Apk apk = new Apk(intent.getParcelableExtra(EXTRA_APK)); addToActive(urlString, app, apk); - NotificationCompat.Builder builder = createNotificationBuilder(intent.getDataString(), apk); + NotificationCompat.Builder builder = createNotificationBuilder(urlString, apk); notificationManager.notify(urlString.hashCode(), builder.build()); registerDownloaderReceivers(urlString, builder); @@ -224,18 +226,18 @@ public class InstallManagerService extends Service { @Override public void onReceive(Context context, Intent intent) { // 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)); - Uri localUri = Uri.fromFile(localFile); + Uri localApkUri = Uri.fromFile(localFile); - Utils.debugLog(TAG, "download completed of " + originatingUri - + " to " + localUri); + Utils.debugLog(TAG, "download completed of " + urlString + " to " + localApkUri); - unregisterDownloaderReceivers(intent.getDataString()); + unregisterDownloaderReceivers(urlString); + registerInstallerReceivers(downloadUri); - registerInstallerReceivers(localUri); - Apk apk = ACTIVE_APKS.get(originatingUri.toString()); - InstallerService.install(context, localUri, originatingUri, apk.packageName); + Apk apk = ACTIVE_APKS.get(urlString); + InstallerService.install(context, localApkUri, downloadUri, apk.packageName); } }; 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() { @Override public void onReceive(Context context, Intent intent) { - Uri originatingUri = intent.getParcelableExtra(Installer.EXTRA_ORIGINATING_URI); - + String downloadUrl = intent.getDataString(); switch (intent.getAction()) { case Installer.ACTION_INSTALL_STARTED: // nothing to do break; case Installer.ACTION_INSTALL_COMPLETE: - Apk apkComplete = removeFromActive(originatingUri.toString()); + Apk apkComplete = removeFromActive(downloadUrl); PackageManagerCompat.setInstaller(getPackageManager(), apkComplete.packageName); @@ -286,31 +287,31 @@ public class InstallManagerService extends Service { // show notification if app details is not visible if (!TextUtils.isEmpty(errorMessage)) { - App app = getAppFromActive(originatingUri.toString()); - String title = String.format( - getString(R.string.install_error_notify_title), - app.name); + App app = getAppFromActive(downloadUrl); // show notification if app details is not visible if (AppDetails.isAppVisible(app.packageName)) { - cancelNotification(originatingUri.toString()); + cancelNotification(downloadUrl); } 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); break; case Installer.ACTION_INSTALL_USER_INTERACTION: PendingIntent installPendingIntent = intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI); - Apk apkUserInteraction = getApkFromActive(originatingUri.toString()); + Apk apkUserInteraction = getApkFromActive(downloadUrl); // show notification if app details is not visible if (AppDetails.isAppVisible(apkUserInteraction.packageName)) { - cancelNotification(originatingUri.toString()); + cancelNotification(downloadUrl); } else { - notifyDownloadComplete(apkUserInteraction, originatingUri.toString(), installPendingIntent); + notifyDownloadComplete(apkUserInteraction, downloadUrl, installPendingIntent); } break; @@ -321,7 +322,7 @@ public class InstallManagerService extends Service { }; localBroadcastManager.registerReceiver(installReceiver, - Installer.getInstallIntentFilter(uri)); + Installer.getInstallIntentFilter(downloadUri)); } private NotificationCompat.Builder createNotificationBuilder(String urlString, Apk apk) { diff --git a/app/src/main/java/org/fdroid/fdroid/installer/Installer.java b/app/src/main/java/org/fdroid/fdroid/installer/Installer.java index b1ed0ff13..9e67d9ef1 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/Installer.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/Installer.java @@ -46,7 +46,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Map; /** - * + * Handles the actual install process. Subclasses implement the details. */ public abstract class Installer { 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"; /** - * Same as http://developer.android.com/reference/android/content/Intent.html#EXTRA_ORIGINATING_URI - * In InstallManagerService often called urlString + * The URI where the APK was originally downloaded from. This is also used + * 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_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"; @@ -91,7 +95,7 @@ public abstract class Installer { 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 { 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. */ - public static boolean verifyApkFile(File apkFile, String hash, String hashType) + static boolean verifyApkFile(File apkFile, String hash, String hashType) throws NoSuchAlgorithmException { if (!apkFile.exists()) { return false; @@ -238,24 +242,23 @@ public abstract class Installer { return hasher.match(hash); } - public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action, + void sendBroadcastInstall(Uri downloadUri, String action, PendingIntent pendingIntent) { - sendBroadcastInstall(uri, originatingUri, action, pendingIntent, null); + sendBroadcastInstall(downloadUri, action, pendingIntent, null); } - public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action) { - sendBroadcastInstall(uri, originatingUri, action, null, null); + void sendBroadcastInstall(Uri downloadUri, String action) { + sendBroadcastInstall(downloadUri, action, null, null); } - public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action, String errorMessage) { - sendBroadcastInstall(uri, originatingUri, action, null, errorMessage); + void sendBroadcastInstall(Uri downloadUri, String action, String 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) { Intent intent = new Intent(action); - intent.setData(uri); - intent.putExtra(Installer.EXTRA_ORIGINATING_URI, originatingUri); + intent.setData(downloadUri); intent.putExtra(Installer.EXTRA_USER_INTERACTION_PI, pendingIntent); if (!TextUtils.isEmpty(errorMessage)) { intent.putExtra(Installer.EXTRA_ERROR_MESSAGE, errorMessage); @@ -263,20 +266,20 @@ public abstract class Installer { 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); } - public void sendBroadcastUninstall(String packageName, String action) { + void sendBroadcastUninstall(String packageName, String action) { sendBroadcastUninstall(packageName, action, null, null); } - public void sendBroadcastUninstall(String packageName, String action, + void sendBroadcastUninstall(String packageName, String action, PendingIntent pendingIntent) { sendBroadcastUninstall(packageName, action, pendingIntent, null); } - public void sendBroadcastUninstall(String packageName, String action, + void sendBroadcastUninstall(String packageName, String action, PendingIntent pendingIntent, String errorMessage) { Uri uri = Uri.fromParts("package", packageName, null); @@ -290,6 +293,10 @@ public abstract class Installer { 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) { IntentFilter intentFilter = new IntentFilter(); 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_USER_INTERACTION); intentFilter.addDataScheme(uri.getScheme()); + intentFilter.addDataAuthority(uri.getHost(), String.valueOf(uri.getPort())); intentFilter.addDataPath(uri.getPath(), PatternMatcher.PATTERN_LITERAL); return intentFilter; } @@ -312,10 +320,20 @@ public abstract class Installer { 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); + /** + * This {@link Installer} instance is capable of "unattended" install and + * uninstall activities, without the system enforcing a user prompt. + */ protected abstract boolean isUnattended(); } diff --git a/app/src/main/java/org/fdroid/fdroid/installer/InstallerService.java b/app/src/main/java/org/fdroid/fdroid/installer/InstallerService.java index 1af566fa3..7e08806c2 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/InstallerService.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/InstallerService.java @@ -33,6 +33,10 @@ import android.net.Uri; * i.e., runs sequentially * - no cancel operation is needed. Cancelling an installation * would be the same as starting uninstall afterwards + *

    + * 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 { @@ -50,9 +54,8 @@ public class InstallerService extends IntentService { if (ACTION_INSTALL.equals(intent.getAction())) { Uri uri = intent.getData(); - Uri originatingUri = intent.getParcelableExtra(Installer.EXTRA_ORIGINATING_URI); - - installer.installPackage(uri, originatingUri, packageName); + Uri downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI); + installer.installPackage(uri, downloadUri, packageName); } else if (ACTION_UNINSTALL.equals(intent.getAction())) { installer.uninstallPackage(packageName); } @@ -61,16 +64,16 @@ public class InstallerService extends IntentService { /** * Install an apk from {@link Uri} * - * @param context this app's {@link Context} - * @param uri {@link Uri} pointing to (downloaded) local apk file - * @param originatingUri {@link Uri} where the apk has been downloaded from - * @param packageName package name of the app that should be installed + * @param context this app's {@link Context} + * @param localApkUri {@link Uri} pointing to (downloaded) local apk file + * @param downloadUri {@link Uri} where the apk has been downloaded from + * @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.setAction(ACTION_INSTALL); - intent.setData(uri); - intent.putExtra(Installer.EXTRA_ORIGINATING_URI, originatingUri); + intent.setData(localApkUri); + intent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri); intent.putExtra(Installer.EXTRA_PACKAGE_NAME, packageName); context.startService(intent); } diff --git a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java index 24a4001ff..66bf38e88 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java @@ -297,15 +297,15 @@ public class PrivilegedInstaller extends Installer { } @Override - protected void installPackage(final Uri uri, final Uri originatingUri, String packageName) { - sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED); + protected void installPackage(final Uri localApkUri, final Uri downloadUri, String packageName) { + sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED); final Uri sanitizedUri; try { - sanitizedUri = Installer.prepareApkFile(context, uri, packageName); + sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName); } catch (Installer.InstallFailedException e) { Log.e(TAG, "prepareApkFile failed", e); - sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED, + sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage()); return; } @@ -318,9 +318,9 @@ public class PrivilegedInstaller extends Installer { @Override public void handleResult(String packageName, int returnCode) throws RemoteException { if (returnCode == INSTALL_SUCCEEDED) { - sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_COMPLETE); + sendBroadcastInstall(downloadUri, ACTION_INSTALL_COMPLETE); } else { - sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED, + sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED, "Error " + returnCode + ": " + INSTALL_RETURN_CODES.get(returnCode)); } @@ -330,7 +330,7 @@ public class PrivilegedInstaller extends Installer { try { boolean hasPermissions = privService.hasPrivilegedPermissions(); if (!hasPermissions) { - sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED, + sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED, context.getString(R.string.system_install_denied_permissions)); return; } @@ -339,7 +339,7 @@ public class PrivilegedInstaller extends Installer { null, callback); } catch (RemoteException e) { Log.e(TAG, "RemoteException", e); - sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED, + sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED, "connecting to privileged service failed"); } } diff --git a/app/src/main/java/org/fdroid/fdroid/privileged/views/UninstallDialogActivity.java b/app/src/main/java/org/fdroid/fdroid/privileged/views/UninstallDialogActivity.java index f0d2bd04c..fa2380719 100644 --- a/app/src/main/java/org/fdroid/fdroid/privileged/views/UninstallDialogActivity.java +++ b/app/src/main/java/org/fdroid/fdroid/privileged/views/UninstallDialogActivity.java @@ -34,6 +34,13 @@ import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.R; 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 { @Override diff --git a/app/src/main/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java b/app/src/main/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java index f6a81b9c8..72a8eca54 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java +++ b/app/src/main/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java @@ -44,14 +44,10 @@ import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.NewRepoConfig; import org.fdroid.fdroid.installer.InstallManagerService; import org.fdroid.fdroid.installer.Installer; -import org.fdroid.fdroid.installer.InstallerService; import org.fdroid.fdroid.localrepo.LocalRepoManager; import org.fdroid.fdroid.localrepo.SwapService; 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.Date; import java.util.HashMap; @@ -773,26 +769,10 @@ public class SwapWorkflowActivity extends AppCompatActivity { public void install(@NonNull final App app) { final Apk apk = ApkProvider.Helper.find(this, app.packageName, app.suggestedVersionCode); - String urlString = 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); - + Uri downloadUri = Uri.parse(apk.getUrl()); localBroadcastManager.registerReceiver(installReceiver, - Installer.getInstallIntentFilter(Uri.fromFile(apkFile))); - InstallerService.install(this, localUri, originatingUri, packageName); + Installer.getInstallIntentFilter(downloadUri)); + InstallManagerService.queue(this, app, apk); } private final BroadcastReceiver installReceiver = new BroadcastReceiver() {