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() {