diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/SwapAppsView.java b/app/src/full/java/org/fdroid/fdroid/views/swap/SwapAppsView.java index 7ad2f38eb..076d4ec45 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/SwapAppsView.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/SwapAppsView.java @@ -314,10 +314,8 @@ public class SwapAppsView extends ListView implements } if (apk != null) { - String urlString = apk.getCanonicalUrl(); - // TODO unregister receivers? or will they just die with this instance - IntentFilter downloadFilter = DownloaderService.getIntentFilter(urlString); + IntentFilter downloadFilter = DownloaderService.getIntentFilter(apk.getCanonicalUrl()); localBroadcastManager.registerReceiver(downloadReceiver, downloadFilter); } diff --git a/app/src/full/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java b/app/src/full/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java index a8a426db9..c55d773b6 100644 --- a/app/src/full/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java +++ b/app/src/full/java/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java @@ -836,9 +836,8 @@ public class SwapWorkflowActivity extends AppCompatActivity { } public void install(@NonNull final App app, @NonNull final Apk apk) { - Uri downloadUri = Uri.parse(apk.getCanonicalUrl()); localBroadcastManager.registerReceiver(installReceiver, - Installer.getInstallIntentFilter(downloadUri)); + Installer.getInstallIntentFilter(apk.getCanonicalUrl())); InstallManagerService.queue(this, app, apk); } diff --git a/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java b/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java index a1372c619..6db802467 100644 --- a/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java +++ b/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java @@ -129,7 +129,7 @@ public final class AppUpdateStatusManager { /** * @return the unique ID used to represent this specific package's install process - * also known as {@code urlString}. + * also known as {@code canonicalUrl}. * @see org.fdroid.fdroid.installer.InstallManagerService */ public String getCanonicalUrl() { @@ -225,9 +225,9 @@ public final class AppUpdateStatusManager { } @Nullable - public AppUpdateStatus get(String key) { + public AppUpdateStatus get(String canonicalUrl) { synchronized (appMapping) { - return appMapping.get(key); + return appMapping.get(canonicalUrl); } } @@ -420,16 +420,15 @@ public final class AppUpdateStatusManager { /** * @param errorText If null, then it is likely because the user cancelled the download. */ - // TODO should url actually be canonicalUrl? - public void setDownloadError(String url, @Nullable String errorText) { + public void setDownloadError(String canonicalUrl, @Nullable String errorText) { synchronized (appMapping) { - AppUpdateStatus entry = appMapping.get(url); + AppUpdateStatus entry = appMapping.get(canonicalUrl); if (entry != null) { entry.status = Status.DownloadInterrupted; entry.errorText = errorText; entry.intent = null; notifyChange(entry, true); - removeApk(url); + removeApk(canonicalUrl); } } } diff --git a/app/src/main/java/org/fdroid/fdroid/NotificationBroadcastReceiver.java b/app/src/main/java/org/fdroid/fdroid/NotificationBroadcastReceiver.java index d562a0484..a93982cf5 100644 --- a/app/src/main/java/org/fdroid/fdroid/NotificationBroadcastReceiver.java +++ b/app/src/main/java/org/fdroid/fdroid/NotificationBroadcastReceiver.java @@ -14,7 +14,7 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { AppUpdateStatusManager manager = AppUpdateStatusManager.getInstance(context); - String notificationKey = intent.getStringExtra(NotificationHelper.EXTRA_NOTIFICATION_KEY); + String canonicalUrl = intent.getStringExtra(NotificationHelper.EXTRA_NOTIFICATION_KEY); switch (intent.getAction()) { case NotificationHelper.BROADCAST_NOTIFICATIONS_ALL_UPDATES_CLEARED: manager.clearAllUpdates(); @@ -25,13 +25,13 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver { case NotificationHelper.BROADCAST_NOTIFICATIONS_UPDATE_CLEARED: // If clearing apps in state "InstallError" (like when auto-cancelling) we // remove them from the status manager entirely. - AppUpdateStatusManager.AppUpdateStatus appUpdateStatus = manager.get(notificationKey); + AppUpdateStatusManager.AppUpdateStatus appUpdateStatus = manager.get(canonicalUrl); if (appUpdateStatus != null && appUpdateStatus.status == AppUpdateStatusManager.Status.InstallError) { - manager.removeApk(notificationKey); + manager.removeApk(canonicalUrl); } break; case NotificationHelper.BROADCAST_NOTIFICATIONS_INSTALLED_CLEARED: - manager.removeApk(notificationKey); + manager.removeApk(canonicalUrl); break; } } 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 70c23e054..af3535ba5 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java @@ -43,11 +43,11 @@ public class DefaultInstaller extends Installer { } @Override - protected void installPackageInternal(Uri localApkUri, Uri downloadUri) { + protected void installPackageInternal(Uri localApkUri, Uri canonicalUri) { Intent installIntent = new Intent(context, DefaultInstallerActivity.class); installIntent.setAction(DefaultInstallerActivity.ACTION_INSTALL_PACKAGE); - installIntent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri); + installIntent.putExtra(Installer.EXTRA_DOWNLOAD_URI, canonicalUri); installIntent.putExtra(Installer.EXTRA_APK, apk); installIntent.setData(localApkUri); @@ -57,7 +57,7 @@ public class DefaultInstaller extends Installer { installIntent, PendingIntent.FLAG_UPDATE_CURRENT); - sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_USER_INTERACTION, + sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent); } 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 322350c29..a0e32e6c9 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstallerActivity.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstallerActivity.java @@ -48,7 +48,10 @@ public class DefaultInstallerActivity extends FragmentActivity { private static final int REQUEST_CODE_INSTALL = 0; private static final int REQUEST_CODE_UNINSTALL = 1; - private Uri downloadUri; + /** + * @see InstallManagerService + */ + private Uri canonicalUri; // for the broadcasts private DefaultInstaller installer; @@ -63,7 +66,7 @@ public class DefaultInstallerActivity extends FragmentActivity { installer = new DefaultInstaller(this, apk); if (ACTION_INSTALL_PACKAGE.equals(action)) { Uri localApkUri = intent.getData(); - downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI); + canonicalUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI); installPackage(localApkUri); } else if (ACTION_UNINSTALL_PACKAGE.equals(action)) { uninstallPackage(apk.packageName); @@ -120,7 +123,7 @@ public class DefaultInstallerActivity extends FragmentActivity { startActivityForResult(intent, REQUEST_CODE_INSTALL); } catch (ActivityNotFoundException e) { Log.e(TAG, "ActivityNotFoundException", e); - installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, + installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_INTERRUPTED, "This Android rom does not support ACTION_INSTALL_PACKAGE!"); finish(); } @@ -169,23 +172,23 @@ public class DefaultInstallerActivity extends FragmentActivity { * never executed on Androids < 4.0 */ if (Build.VERSION.SDK_INT < 14) { - installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE); + installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_COMPLETE); break; } switch (resultCode) { case Activity.RESULT_OK: - installer.sendBroadcastInstall(downloadUri, + installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_COMPLETE); break; case Activity.RESULT_CANCELED: - installer.sendBroadcastInstall(downloadUri, + installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_INTERRUPTED); break; case Activity.RESULT_FIRST_USER: default: // AOSP returns Activity.RESULT_FIRST_USER on error - installer.sendBroadcastInstall(downloadUri, + installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_INTERRUPTED, getString(R.string.install_error_unknown)); break; diff --git a/app/src/main/java/org/fdroid/fdroid/installer/FileInstaller.java b/app/src/main/java/org/fdroid/fdroid/installer/FileInstaller.java index 01bf38d3d..63975208a 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/FileInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/FileInstaller.java @@ -44,15 +44,15 @@ public class FileInstaller extends Installer { } @Override - public void installPackage(Uri localApkUri, Uri downloadUri) { - installPackageInternal(localApkUri, downloadUri); + public void installPackage(Uri localApkUri, Uri canonicalUri) { + installPackageInternal(localApkUri, canonicalUri); } @Override - protected void installPackageInternal(Uri localApkUri, Uri downloadUri) { + protected void installPackageInternal(Uri localApkUri, Uri canonicalUri) { Intent installIntent = new Intent(context, FileInstallerActivity.class); installIntent.setAction(FileInstallerActivity.ACTION_INSTALL_FILE); - installIntent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri); + installIntent.putExtra(Installer.EXTRA_DOWNLOAD_URI, canonicalUri); installIntent.putExtra(Installer.EXTRA_APK, apk); installIntent.setData(localApkUri); @@ -62,7 +62,7 @@ public class FileInstaller extends Installer { installIntent, PendingIntent.FLAG_UPDATE_CURRENT); - sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_USER_INTERACTION, + sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent); } diff --git a/app/src/main/java/org/fdroid/fdroid/installer/FileInstallerActivity.java b/app/src/main/java/org/fdroid/fdroid/installer/FileInstallerActivity.java index 9bc3db7b8..5d7d1ddb3 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/FileInstallerActivity.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/FileInstallerActivity.java @@ -13,7 +13,6 @@ import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.view.ContextThemeWrapper; import android.widget.Toast; - import org.apache.commons.io.FileUtils; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.R; @@ -40,7 +39,10 @@ public class FileInstallerActivity extends FragmentActivity { private Apk apk; private Uri localApkUri; - private Uri downloadUri; + /** + * @see InstallManagerService + */ + private Uri canonicalUri; private int act = 0; @@ -51,12 +53,12 @@ public class FileInstallerActivity extends FragmentActivity { Intent intent = getIntent(); String action = intent.getAction(); localApkUri = intent.getData(); - downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI); + canonicalUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI); apk = intent.getParcelableExtra(Installer.EXTRA_APK); installer = new FileInstaller(this, apk); if (ACTION_INSTALL_FILE.equals(action)) { if (hasStoragePermission()) { - installPackage(localApkUri, downloadUri, apk); + installPackage(localApkUri, canonicalUri, apk); } else { requestPermission(); act = 1; @@ -110,7 +112,7 @@ public class FileInstallerActivity extends FragmentActivity { .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (act == 1) { - installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED); + installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_INTERRUPTED); } else if (act == 2) { installer.sendBroadcastUninstall(Installer.ACTION_UNINSTALL_INTERRUPTED); } @@ -129,13 +131,13 @@ public class FileInstallerActivity extends FragmentActivity { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (act == 1) { - installPackage(localApkUri, downloadUri, apk); + installPackage(localApkUri, canonicalUri, apk); } else if (act == 2) { uninstallPackage(apk); } } else { if (act == 1) { - installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED); + installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_INTERRUPTED); } else if (act == 2) { installer.sendBroadcastUninstall(Installer.ACTION_UNINSTALL_INTERRUPTED); } @@ -144,7 +146,7 @@ public class FileInstallerActivity extends FragmentActivity { } } - private void installPackage(Uri localApkUri, Uri downloadUri, Apk apk) { + private void installPackage(Uri localApkUri, Uri canonicalUri, Apk apk) { Utils.debugLog(TAG, "Installing: " + localApkUri.getPath()); File path = apk.getMediaInstallPath(activity.getApplicationContext()); path.mkdirs(); @@ -152,15 +154,15 @@ public class FileInstallerActivity extends FragmentActivity { FileUtils.copyFileToDirectory(new File(localApkUri.getPath()), path); } catch (IOException e) { Utils.debugLog(TAG, "Failed to copy: " + e.getMessage()); - installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED); + installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_INTERRUPTED); } if (apk.isMediaInstalled(activity.getApplicationContext())) { // Copying worked Utils.debugLog(TAG, "Copying worked: " + localApkUri.getPath()); Toast.makeText(this, String.format(this.getString(R.string.app_installed_media), path.toString()), Toast.LENGTH_LONG).show(); - installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE); + installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_COMPLETE); } else { - installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED); + installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_INTERRUPTED); } finish(); } 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 184c30bff..78fae9b1c 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java @@ -65,7 +65,7 @@ import java.io.IOException; * APK on different servers, signed by different keys, or even different builds. *

@@ -146,24 +146,24 @@ public class InstallManagerService extends Service { public int onStartCommand(Intent intent, int flags, int startId) { Utils.debugLog(TAG, "onStartCommand " + intent); - String urlString = intent.getDataString(); - if (TextUtils.isEmpty(urlString)) { - Utils.debugLog(TAG, "empty urlString, nothing to do"); + String canonicalUrl = intent.getDataString(); + if (TextUtils.isEmpty(canonicalUrl)) { + Utils.debugLog(TAG, "empty canonicalUrl, nothing to do"); return START_NOT_STICKY; } String action = intent.getAction(); if (ACTION_CANCEL.equals(action)) { - DownloaderService.cancel(this, urlString); - Apk apk = appUpdateStatusManager.getApk(urlString); + DownloaderService.cancel(this, canonicalUrl); + Apk apk = appUpdateStatusManager.getApk(canonicalUrl); if (apk != null) { DownloaderService.cancel(this, apk.getPatchObbUrl()); DownloaderService.cancel(this, apk.getMainObbUrl()); } return START_NOT_STICKY; } else if (ACTION_INSTALL.equals(action)) { - if (!isPendingInstall(urlString)) { + if (!isPendingInstall(canonicalUrl)) { Log.i(TAG, "Ignoring INSTALL that is not Pending Install: " + intent); return START_NOT_STICKY; } @@ -173,14 +173,14 @@ public class InstallManagerService extends Service { } if (!intent.hasExtra(EXTRA_APP) || !intent.hasExtra(EXTRA_APK)) { - Utils.debugLog(TAG, urlString + " did not include both an App and Apk instance, ignoring"); + Utils.debugLog(TAG, canonicalUrl + " did not include both an App and Apk instance, ignoring"); return START_NOT_STICKY; } if ((flags & START_FLAG_REDELIVERY) == START_FLAG_REDELIVERY - && !DownloaderService.isQueuedOrActive(urlString)) { - Utils.debugLog(TAG, urlString + " finished downloading while InstallManagerService was killed."); - appUpdateStatusManager.removeApk(urlString); + && !DownloaderService.isQueuedOrActive(canonicalUrl)) { + Utils.debugLog(TAG, canonicalUrl + " finished downloading while InstallManagerService was killed."); + appUpdateStatusManager.removeApk(canonicalUrl); return START_NOT_STICKY; } @@ -204,23 +204,23 @@ public class InstallManagerService extends Service { appUpdateStatusManager.addApk(apk, AppUpdateStatusManager.Status.Downloading, null); - registerPackageDownloaderReceivers(urlString); - getObb(urlString, apk.getMainObbUrl(), apk.getMainObbFile(), apk.obbMainFileSha256); - getObb(urlString, apk.getPatchObbUrl(), apk.getPatchObbFile(), apk.obbPatchFileSha256); + registerPackageDownloaderReceivers(canonicalUrl); + getObb(canonicalUrl, apk.getMainObbUrl(), apk.getMainObbFile(), apk.obbMainFileSha256); + getObb(canonicalUrl, apk.getPatchObbUrl(), apk.getPatchObbFile(), apk.obbPatchFileSha256); File apkFilePath = ApkCache.getApkDownloadPath(this, apk.getCanonicalUrl()); long apkFileSize = apkFilePath.length(); if (!apkFilePath.exists() || apkFileSize < apk.size) { - Utils.debugLog(TAG, "download " + urlString + " " + apkFilePath); - DownloaderService.queueUsingRandomMirror(this, apk.repoId, urlString); + Utils.debugLog(TAG, "download " + canonicalUrl + " " + apkFilePath); + DownloaderService.queueUsingRandomMirror(this, apk.repoId, canonicalUrl); } else if (ApkCache.apkIsCached(apkFilePath, apk)) { - Utils.debugLog(TAG, "skip download, we have it, straight to install " + urlString + " " + apkFilePath); + Utils.debugLog(TAG, "skip download, we have it, straight to install " + canonicalUrl + " " + apkFilePath); sendBroadcast(intent.getData(), Downloader.ACTION_STARTED, apkFilePath); sendBroadcast(intent.getData(), Downloader.ACTION_COMPLETE, apkFilePath); } else { - Utils.debugLog(TAG, "delete and download again " + urlString + " " + apkFilePath); + Utils.debugLog(TAG, "delete and download again " + canonicalUrl + " " + apkFilePath); apkFilePath.delete(); - DownloaderService.queueUsingRandomMirror(this, apk.repoId, urlString); + DownloaderService.queueUsingRandomMirror(this, apk.repoId, canonicalUrl); } return START_REDELIVER_INTENT; // if killed before completion, retry Intent @@ -240,7 +240,7 @@ public class InstallManagerService extends Service { * * @see APK Expansion Files */ - private void getObb(final String urlString, String obbUrlString, + private void getObb(final String canonicalUrl, String obbUrlString, final File obbDestFile, final String hash) { if (obbDestFile == null || obbDestFile.exists() || TextUtils.isEmpty(obbUrlString)) { return; @@ -259,7 +259,7 @@ public class InstallManagerService extends Service { long bytesRead = intent.getLongExtra(Downloader.EXTRA_BYTES_READ, 0); long totalBytes = intent.getLongExtra(Downloader.EXTRA_TOTAL_BYTES, 0); - appUpdateStatusManager.updateApkProgress(urlString, totalBytes, bytesRead); + appUpdateStatusManager.updateApkProgress(canonicalUrl, totalBytes, bytesRead); } else if (Downloader.ACTION_COMPLETE.equals(action)) { localBroadcastManager.unregisterReceiver(this); File localFile = new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH)); @@ -291,7 +291,7 @@ public class InstallManagerService extends Service { } else if (Downloader.ACTION_INTERRUPTED.equals(action)) { localBroadcastManager.unregisterReceiver(this); } else if (Downloader.ACTION_CONNECTION_FAILED.equals(action)) { - DownloaderService.queueUsingDifferentMirror(context, 0, urlString); + DownloaderService.queueUsingDifferentMirror(context, 0, canonicalUrl); } else { throw new RuntimeException("intent action not handled!"); } @@ -304,9 +304,9 @@ public class InstallManagerService extends Service { /** * Register a {@link BroadcastReceiver} for tracking download progress for a - * give {@code urlString}. There can be multiple of these registered at a time. + * give {@code canonicalUrl}. There can be multiple of these registered at a time. */ - private void registerPackageDownloaderReceivers(String urlString) { + private void registerPackageDownloaderReceivers(String canonicalUrl) { BroadcastReceiver downloadReceiver = new BroadcastReceiver() { @Override @@ -315,8 +315,8 @@ public class InstallManagerService extends Service { localBroadcastManager.unregisterReceiver(this); return; } - Uri downloadUri = intent.getData(); - String urlString = downloadUri.toString(); + Uri canonicalUri = intent.getData(); + String canonicalUrl = intent.getDataString(); long repoId = intent.getLongExtra(Downloader.EXTRA_REPO_ID, 0); switch (intent.getAction()) { @@ -324,14 +324,15 @@ public class InstallManagerService extends Service { // App should currently be in the "PendingDownload" state, so this changes it to "Downloading". Intent intentObject = new Intent(context, InstallManagerService.class); intentObject.setAction(ACTION_CANCEL); - intentObject.setData(downloadUri); + intentObject.setData(canonicalUri); PendingIntent action = PendingIntent.getService(context, 0, intentObject, 0); - appUpdateStatusManager.updateApk(urlString, AppUpdateStatusManager.Status.Downloading, action); + appUpdateStatusManager.updateApk(canonicalUrl, + AppUpdateStatusManager.Status.Downloading, action); break; case Downloader.ACTION_PROGRESS: long bytesRead = intent.getLongExtra(Downloader.EXTRA_BYTES_READ, 0); long totalBytes = intent.getLongExtra(Downloader.EXTRA_TOTAL_BYTES, 0); - appUpdateStatusManager.updateApkProgress(urlString, totalBytes, bytesRead); + appUpdateStatusManager.updateApkProgress(canonicalUrl, totalBytes, bytesRead); break; case Downloader.ACTION_COMPLETE: File localFile = new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH)); @@ -339,29 +340,33 @@ public class InstallManagerService extends Service { Utils.debugLog(TAG, "download completed of " + intent.getStringExtra(Downloader.EXTRA_MIRROR_URL) + " to " + localApkUri); - appUpdateStatusManager.updateApk(urlString, AppUpdateStatusManager.Status.ReadyToInstall, null); + appUpdateStatusManager.updateApk(canonicalUrl, + AppUpdateStatusManager.Status.ReadyToInstall, null); localBroadcastManager.unregisterReceiver(this); - registerInstallReceiver(downloadUri); + registerInstallReceiver(canonicalUrl); - Apk apk = appUpdateStatusManager.getApk(urlString); + Apk apk = appUpdateStatusManager.getApk(canonicalUrl); if (apk != null) { - InstallerService.install(context, localApkUri, downloadUri, apk); + InstallerService.install(context, localApkUri, canonicalUri, apk); } break; case Downloader.ACTION_INTERRUPTED: - appUpdateStatusManager.setDownloadError(urlString, intent.getStringExtra(Downloader.EXTRA_ERROR_MESSAGE)); + appUpdateStatusManager.setDownloadError(canonicalUrl, + intent.getStringExtra(Downloader.EXTRA_ERROR_MESSAGE)); localBroadcastManager.unregisterReceiver(this); break; case Downloader.ACTION_CONNECTION_FAILED: + // TODO move this logic into DownloaderService to hide the mirror URL stuff from this class try { String currentUrlString = FDroidApp.getNewMirrorOnError( intent.getStringExtra(Downloader.EXTRA_MIRROR_URL), RepoProvider.Helper.findById(InstallManagerService.this, repoId)); - DownloaderService.queue(context, currentUrlString, repoId, urlString); + DownloaderService.queue(context, currentUrlString, repoId, canonicalUrl); DownloaderService.setTimeout(FDroidApp.getTimeout()); } catch (IOException e) { - appUpdateStatusManager.setDownloadError(urlString, intent.getStringExtra(Downloader.EXTRA_ERROR_MESSAGE)); + appUpdateStatusManager.setDownloadError(canonicalUrl, + intent.getStringExtra(Downloader.EXTRA_ERROR_MESSAGE)); localBroadcastManager.unregisterReceiver(this); } break; @@ -372,14 +377,14 @@ public class InstallManagerService extends Service { }; localBroadcastManager.registerReceiver(downloadReceiver, - DownloaderService.getIntentFilter(urlString)); + DownloaderService.getIntentFilter(canonicalUrl)); } /** * Register a {@link BroadcastReceiver} for tracking install progress for a * give {@link Uri}. There can be multiple of these registered at a time. */ - private void registerInstallReceiver(Uri downloadUri) { + private void registerInstallReceiver(String canonicalUrl) { BroadcastReceiver installReceiver = new BroadcastReceiver() { @Override @@ -388,15 +393,17 @@ public class InstallManagerService extends Service { localBroadcastManager.unregisterReceiver(this); return; } - String downloadUrl = intent.getDataString(); + String canonicalUrl = intent.getDataString(); Apk apk; switch (intent.getAction()) { case Installer.ACTION_INSTALL_STARTED: - appUpdateStatusManager.updateApk(downloadUrl, AppUpdateStatusManager.Status.Installing, null); + appUpdateStatusManager.updateApk(canonicalUrl, + AppUpdateStatusManager.Status.Installing, null); break; case Installer.ACTION_INSTALL_COMPLETE: - appUpdateStatusManager.updateApk(downloadUrl, AppUpdateStatusManager.Status.Installed, null); - Apk apkComplete = appUpdateStatusManager.getApk(downloadUrl); + appUpdateStatusManager.updateApk(canonicalUrl, + AppUpdateStatusManager.Status.Installed, null); + Apk apkComplete = appUpdateStatusManager.getApk(canonicalUrl); if (apkComplete != null && apkComplete.isApk()) { try { @@ -414,7 +421,7 @@ public class InstallManagerService extends Service { if (!TextUtils.isEmpty(errorMessage)) { appUpdateStatusManager.setApkError(apk, errorMessage); } else { - appUpdateStatusManager.removeApk(downloadUrl); + appUpdateStatusManager.removeApk(canonicalUrl); } localBroadcastManager.unregisterReceiver(this); break; @@ -430,7 +437,7 @@ public class InstallManagerService extends Service { }; localBroadcastManager.registerReceiver(installReceiver, - Installer.getInstallIntentFilter(downloadUri)); + Installer.getInstallIntentFilter(canonicalUrl)); } /** 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 40b2e1775..9b646a988 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/Installer.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/Installer.java @@ -165,23 +165,23 @@ public abstract class Installer { return intent; } - void sendBroadcastInstall(Uri downloadUri, String action, PendingIntent pendingIntent) { - sendBroadcastInstall(context, downloadUri, action, apk, pendingIntent, null); + void sendBroadcastInstall(Uri canonicalUri, String action, PendingIntent pendingIntent) { + sendBroadcastInstall(context, canonicalUri, action, apk, pendingIntent, null); } - void sendBroadcastInstall(Uri downloadUri, String action) { - sendBroadcastInstall(context, downloadUri, action, apk, null, null); + void sendBroadcastInstall(Uri canonicalUri, String action) { + sendBroadcastInstall(context, canonicalUri, action, apk, null, null); } - void sendBroadcastInstall(Uri downloadUri, String action, String errorMessage) { - sendBroadcastInstall(context, downloadUri, action, apk, null, errorMessage); + void sendBroadcastInstall(Uri canonicalUri, String action, String errorMessage) { + sendBroadcastInstall(context, canonicalUri, action, apk, null, errorMessage); } static void sendBroadcastInstall(Context context, - Uri downloadUri, String action, Apk apk, + Uri canonicalUri, String action, Apk apk, PendingIntent pendingIntent, String errorMessage) { Intent intent = new Intent(action); - intent.setData(downloadUri); + intent.setData(canonicalUri); intent.putExtra(Installer.EXTRA_USER_INTERACTION_PI, pendingIntent); intent.putExtra(Installer.EXTRA_APK, apk); if (!TextUtils.isEmpty(errorMessage)) { @@ -226,20 +226,34 @@ public abstract class Installer { /** * Gets an {@link IntentFilter} for matching events from the install - * process based on the original download URL as a {@link Uri}. + * process based on {@code canonicalUri}, which is the global unique + * ID for a package going through the install process. + * + * @see InstallManagerService for more about {@code canonicalUri} */ - public static IntentFilter getInstallIntentFilter(Uri uri) { + public static IntentFilter getInstallIntentFilter(Uri canonicalUri) { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Installer.ACTION_INSTALL_STARTED); intentFilter.addAction(Installer.ACTION_INSTALL_COMPLETE); 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); + intentFilter.addDataScheme(canonicalUri.getScheme()); + intentFilter.addDataAuthority(canonicalUri.getHost(), String.valueOf(canonicalUri.getPort())); + intentFilter.addDataPath(canonicalUri.getPath(), PatternMatcher.PATTERN_LITERAL); return intentFilter; } + /** + * Gets an {@link IntentFilter} for matching events from the install + * process based on {@code canonicalUrl}, which is the global unique + * ID for a package going through the install process. + * + * @see InstallManagerService for more about {@code canonicalUrl} + */ + public static IntentFilter getInstallIntentFilter(String canonicalUrl) { + return getInstallIntentFilter(Uri.parse(canonicalUrl)); + } + public static IntentFilter getUninstallIntentFilter(String packageName) { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Installer.ACTION_UNINSTALL_STARTED); @@ -262,20 +276,20 @@ public abstract class Installer { * is prompted with the system installer dialog, which shows all the * permissions that the APK is requesting. * - * @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 localApkUri points to the local copy of the APK to be installed + * @param canonicalUri serves as the unique ID for all actions related to the + * installation of that specific APK * @see InstallManagerService * @see ACTION_INSTALL_PACKAGE Fails For Any Possible Uri */ - public void installPackage(Uri localApkUri, Uri downloadUri) { + public void installPackage(Uri localApkUri, Uri canonicalUri) { Uri sanitizedUri; try { sanitizedUri = ApkFileProvider.getSafeUri(context, localApkUri, apk); } catch (IOException e) { Utils.debugLog(TAG, e.getMessage(), e); - sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage()); + sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage()); return; } @@ -285,7 +299,7 @@ public abstract class Installer { apkVerifier.verifyApk(); } catch (ApkVerifier.ApkVerificationException e) { Utils.debugLog(TAG, e.getMessage(), e); - sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage()); + sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage()); return; } catch (ApkVerifier.ApkPermissionUnequalException e) { // if permissions of apk are not the ones listed in the repo @@ -295,15 +309,15 @@ public abstract class Installer { Utils.debugLog(TAG, e.getMessage(), e); Utils.debugLog(TAG, "Falling back to AOSP DefaultInstaller!"); DefaultInstaller defaultInstaller = new DefaultInstaller(context, apk); - defaultInstaller.installPackageInternal(sanitizedUri, downloadUri); + defaultInstaller.installPackageInternal(sanitizedUri, canonicalUri); return; } } - installPackageInternal(sanitizedUri, downloadUri); + installPackageInternal(sanitizedUri, canonicalUri); } - protected abstract void installPackageInternal(Uri localApkUri, Uri downloadUri); + protected abstract void installPackageInternal(Uri localApkUri, Uri canonicalUri); /** * Uninstall app as defined by {@link Installer#apk} in 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 496d46d5d..75f8f8a96 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/InstallerService.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/InstallerService.java @@ -28,10 +28,10 @@ import android.support.annotation.NonNull; import android.support.v4.app.JobIntentService; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.WildcardFileFilter; -import org.fdroid.fdroid.views.AppDetailsActivity; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.App; +import org.fdroid.fdroid.views.AppDetailsActivity; import java.io.File; import java.io.FileFilter; @@ -74,8 +74,8 @@ public class InstallerService extends JobIntentService { if (ACTION_INSTALL.equals(intent.getAction())) { Uri uri = intent.getData(); - Uri downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI); - installer.installPackage(uri, downloadUri); + Uri canonicalUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI); + installer.installPackage(uri, canonicalUri); } else if (ACTION_UNINSTALL.equals(intent.getAction())) { installer.uninstallPackage(); new Thread() { @@ -111,19 +111,20 @@ public class InstallerService extends JobIntentService { * {@link #uninstall(Context, Apk)} since this is called in one place where * the input has already been validated. * - * @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 apk apk object of app that should be installed + * @param context this app's {@link Context} + * @param localApkUri {@link Uri} pointing to (downloaded) local apk file + * @param canonicalUri {@link Uri} used as the global unique ID for the package + * @param apk apk object of app that should be installed * @see #uninstall(Context, Apk) + * @see InstallManagerService */ - public static void install(Context context, Uri localApkUri, Uri downloadUri, Apk apk) { - Installer.sendBroadcastInstall(context, downloadUri, Installer.ACTION_INSTALL_STARTED, apk, + public static void install(Context context, Uri localApkUri, Uri canonicalUri, Apk apk) { + Installer.sendBroadcastInstall(context, canonicalUri, Installer.ACTION_INSTALL_STARTED, apk, null, null); Intent intent = new Intent(context, InstallerService.class); intent.setAction(ACTION_INSTALL); intent.setData(localApkUri); - intent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri); + intent.putExtra(Installer.EXTRA_DOWNLOAD_URI, canonicalUri); intent.putExtra(Installer.EXTRA_APK, apk); enqueueWork(context, 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 a4908e156..51e5ee8f4 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java @@ -308,7 +308,7 @@ public class PrivilegedInstaller extends Installer { } @Override - protected void installPackageInternal(final Uri localApkUri, final Uri downloadUri) { + protected void installPackageInternal(final Uri localApkUri, final Uri canonicalUri) { ServiceConnection mServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { IPrivilegedService privService = IPrivilegedService.Stub.asInterface(service); @@ -317,9 +317,9 @@ public class PrivilegedInstaller extends Installer { @Override public void handleResult(String packageName, int returnCode) throws RemoteException { if (returnCode == INSTALL_SUCCEEDED) { - sendBroadcastInstall(downloadUri, ACTION_INSTALL_COMPLETE); + sendBroadcastInstall(canonicalUri, ACTION_INSTALL_COMPLETE); } else { - sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED, + sendBroadcastInstall(canonicalUri, ACTION_INSTALL_INTERRUPTED, "Error " + returnCode + ": " + INSTALL_RETURN_CODES.get(returnCode)); } @@ -329,7 +329,7 @@ public class PrivilegedInstaller extends Installer { try { boolean hasPermissions = privService.hasPrivilegedPermissions(); if (!hasPermissions) { - sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED, + sendBroadcastInstall(canonicalUri, ACTION_INSTALL_INTERRUPTED, context.getString(R.string.system_install_denied_permissions)); return; } @@ -338,7 +338,7 @@ public class PrivilegedInstaller extends Installer { null, callback); } catch (RemoteException e) { Log.e(TAG, "RemoteException", e); - sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED, + sendBroadcastInstall(canonicalUri, ACTION_INSTALL_INTERRUPTED, "connecting to privileged service failed"); } } diff --git a/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java b/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java index b4201e486..96724a76f 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java +++ b/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java @@ -75,17 +75,18 @@ import java.net.UnknownHostException; * long as necessary (and will not block the application's main loop), but * only one request will be processed at a time. *

- * The full URL for the file to download is also used as the unique ID to + * The Canonical URL for the file to download is also used as the unique ID to * represent the download itself throughout F-Droid. This follows the model * of {@link Intent#setData(Uri)}, where the core data of an {@code Intent} is * a {@code Uri}. For places that need an {@code int} ID, * {@link String#hashCode()} should be used to get a reproducible, unique {@code int} - * from any {@code urlString}. The full URL is guaranteed to be unique since + * from any {@code canonicalUrl}. That full URL is guaranteed to be unique since * it points to a file on a filesystem. This is more important with media files * than with APKs since there is not reliable standard for a unique ID for * media files, unlike APKs with {@code packageName} and {@code versionCode}. * * @see android.app.IntentService + * @see org.fdroid.fdroid.installer.InstallManagerService */ public class DownloaderService extends Service { private static final String TAG = "DownloaderService"; @@ -332,18 +333,18 @@ public class DownloaderService extends Service { *

* All notifications are sent as an {@link Intent} via local broadcasts to be received by * - * @param context this app's {@link Context} - * @param urlString The URL to remove from the download queue + * @param context this app's {@link Context} + * @param canonicalUrl The URL to remove from the download queue * @see #queue(Context, String, long, String) */ - public static void cancel(Context context, String urlString) { - if (TextUtils.isEmpty(urlString)) { + public static void cancel(Context context, String canonicalUrl) { + if (TextUtils.isEmpty(canonicalUrl)) { return; } - Utils.debugLog(TAG, "Preparing cancellation of " + urlString + " download"); + Utils.debugLog(TAG, "Preparing cancellation of " + canonicalUrl + " download"); Intent intent = new Intent(context, DownloaderService.class); intent.setAction(ACTION_CANCEL); - intent.setData(Uri.parse(urlString)); + intent.setData(Uri.parse(canonicalUrl)); context.startService(intent); } @@ -352,21 +353,21 @@ public class DownloaderService extends Service { * This is useful for checking whether to re-register {@link android.content.BroadcastReceiver}s * in {@link android.app.Activity#onResume()}. */ - public static boolean isQueuedOrActive(String urlString) { - if (TextUtils.isEmpty(urlString)) { //NOPMD - suggests unreadable format + public static boolean isQueuedOrActive(String canonicalUrl) { + if (TextUtils.isEmpty(canonicalUrl)) { //NOPMD - suggests unreadable format return false; } if (serviceHandler == null) { return false; // this service is not even running } - return serviceHandler.hasMessages(urlString.hashCode()) || isActive(urlString); + return serviceHandler.hasMessages(canonicalUrl.hashCode()) || isActive(canonicalUrl); } /** * Check if a URL is actively being downloaded. */ - private static boolean isActive(String urlString) { - return downloader != null && TextUtils.equals(urlString, downloader.urlString); + private static boolean isActive(String downloadUrl) { + return downloader != null && TextUtils.equals(downloadUrl, downloader.urlString); } public static void setTimeout(int ms) { diff --git a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsActivity.java b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsActivity.java index ec554956a..77160ceb8 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsActivity.java +++ b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsActivity.java @@ -449,7 +449,7 @@ public class AppDetailsActivity extends AppCompatActivity if (justReceived) { adapter.setIndeterminateProgress(R.string.installing); localBroadcastManager.registerReceiver(installReceiver, - Installer.getInstallIntentFilter(Uri.parse(newStatus.getCanonicalUrl()))); + Installer.getInstallIntentFilter(newStatus.getCanonicalUrl())); } break; diff --git a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java index fde7af64e..7801ff82e 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java +++ b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java @@ -483,8 +483,8 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { } if (currentStatus != null && currentStatus.status == AppUpdateStatusManager.Status.ReadyToInstall) { - String urlString = currentStatus.apk.getCanonicalUrl(); - File apkFilePath = ApkCache.getApkDownloadPath(activity, urlString); + String canonicalUrl = currentStatus.apk.getCanonicalUrl(); + File apkFilePath = ApkCache.getApkDownloadPath(activity, canonicalUrl); Utils.debugLog(TAG, "skip download, we have already downloaded " + currentStatus.apk.getCanonicalUrl() + " to " + apkFilePath); @@ -505,10 +505,10 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { } }; - Uri apkDownloadUri = Uri.parse(urlString); - broadcastManager.registerReceiver(receiver, Installer.getInstallIntentFilter(apkDownloadUri)); + Uri canonicalUri = Uri.parse(canonicalUrl); + broadcastManager.registerReceiver(receiver, Installer.getInstallIntentFilter(canonicalUri)); Installer installer = InstallerFactory.create(activity, currentStatus.apk); - installer.installPackage(Uri.parse(apkFilePath.toURI().toString()), apkDownloadUri); + installer.installPackage(Uri.parse(apkFilePath.toURI().toString()), canonicalUri); } else { final Apk suggestedApk = ApkProvider.Helper.findSuggestedApk(activity, app); InstallManagerService.queue(activity, app, suggestedApk); diff --git a/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java b/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java index a4d89fa7f..0d1ac37dd 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java +++ b/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java @@ -5,12 +5,10 @@ import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.LocalBroadcastManager; import android.view.View; - import org.fdroid.fdroid.AppUpdateStatusManager; import org.fdroid.fdroid.R; import org.fdroid.fdroid.data.Apk; @@ -73,8 +71,8 @@ public class KnownVulnAppListItemController extends AppListItemController { Apk suggestedApk = ApkProvider.Helper.findSuggestedApk(activity, app); if (shouldUpgradeInsteadOfUninstall(app, suggestedApk)) { LocalBroadcastManager manager = LocalBroadcastManager.getInstance(activity); - Uri uri = Uri.parse(suggestedApk.getCanonicalUrl()); - manager.registerReceiver(installReceiver, Installer.getInstallIntentFilter(uri)); + manager.registerReceiver(installReceiver, + Installer.getInstallIntentFilter(suggestedApk.getCanonicalUrl())); InstallManagerService.queue(activity, app, suggestedApk); } else { LocalBroadcastManager manager = LocalBroadcastManager.getInstance(activity); @@ -141,7 +139,8 @@ public class KnownVulnAppListItemController extends AppListItemController { try { uninstallPendingIntent.send(); - } catch (PendingIntent.CanceledException ignored) { } + } catch (PendingIntent.CanceledException ignored) { + } break; } }