diff --git a/app/src/main/java/org/fdroid/fdroid/AppDetails.java b/app/src/main/java/org/fdroid/fdroid/AppDetails.java
index d3a16343f..79efbc780 100644
--- a/app/src/main/java/org/fdroid/fdroid/AppDetails.java
+++ b/app/src/main/java/org/fdroid/fdroid/AppDetails.java
@@ -562,55 +562,28 @@ public class AppDetails extends AppCompatActivity {
}
case Installer.ACTION_INSTALL_COMPLETE: {
headerFragment.removeProgress();
+
localBroadcastManager.unregisterReceiver(this);
-
- PackageManagerCompat.setInstaller(packageManager, app.packageName);
-
- onAppChanged();
break;
}
case Installer.ACTION_INSTALL_INTERRUPTED: {
headerFragment.removeProgress();
+ onAppChanged();
+
+ String errorMessage =
+ intent.getStringExtra(Installer.EXTRA_ERROR_MESSAGE);
+
+ if (!TextUtils.isEmpty(errorMessage)) {
+ Log.e(TAG, "Installer aborted with errorMessage: " + errorMessage);
+
+ AlertDialog.Builder alertBuilder = new AlertDialog.Builder(AppDetails.this);
+ alertBuilder.setTitle(R.string.install_error_notify_title);
+ alertBuilder.setMessage(errorMessage);
+ alertBuilder.setNeutralButton(android.R.string.ok, null);
+ alertBuilder.create().show();
+ }
+
localBroadcastManager.unregisterReceiver(this);
-
-
- // TODO: old error handling code:
-// if (errorCode == InstallerCallback.ERROR_CODE_CANCELED) {
-// return;
-// }
-// final int title, body;
-// if (operation == InstallerCallback.OPERATION_INSTALL) {
-// title = R.string.install_error_title;
-// switch (errorCode) {
-// case ERROR_CODE_CANNOT_PARSE:
-// body = R.string.install_error_cannot_parse;
-// break;
-// default: // ERROR_CODE_OTHER
-// body = R.string.install_error_unknown;
-// break;
-// }
-// } else { // InstallerCallback.OPERATION_DELETE
-// title = R.string.uninstall_error_title;
-// switch (errorCode) {
-// default: // ERROR_CODE_OTHER
-// body = R.string.uninstall_error_unknown;
-// break;
-// }
-// }
-// runOnUiThread(new Runnable() {
-// @Override
-// public void run() {
-// onAppChanged();
-//
-// Log.e(TAG, "Installer aborted with errorCode: " + errorCode);
-//
-// AlertDialog.Builder alertBuilder = new AlertDialog.Builder(AppDetails.this);
-// alertBuilder.setTitle(title);
-// alertBuilder.setMessage(body);
-// alertBuilder.setNeutralButton(android.R.string.ok, null);
-// alertBuilder.create().show();
-// }
-// });
break;
}
case Installer.ACTION_INSTALL_USER_INTERACTION: {
@@ -643,52 +616,28 @@ public class AppDetails extends AppCompatActivity {
}
case Installer.ACTION_UNINSTALL_COMPLETE: {
headerFragment.removeProgress();
- localBroadcastManager.unregisterReceiver(this);
-
onAppChanged();
+
+ localBroadcastManager.unregisterReceiver(this);
break;
}
case Installer.ACTION_UNINSTALL_INTERRUPTED: {
headerFragment.removeProgress();
- localBroadcastManager.unregisterReceiver(this);
- // TODO: old error handling code:
-// if (errorCode == InstallerCallback.ERROR_CODE_CANCELED) {
-// return;
-// }
-// final int title, body;
-// if (operation == InstallerCallback.OPERATION_INSTALL) {
-// title = R.string.install_error_title;
-// switch (errorCode) {
-// case ERROR_CODE_CANNOT_PARSE:
-// body = R.string.install_error_cannot_parse;
-// break;
-// default: // ERROR_CODE_OTHER
-// body = R.string.install_error_unknown;
-// break;
-// }
-// } else { // InstallerCallback.OPERATION_DELETE
-// title = R.string.uninstall_error_title;
-// switch (errorCode) {
-// default: // ERROR_CODE_OTHER
-// body = R.string.uninstall_error_unknown;
-// break;
-// }
-// }
-// runOnUiThread(new Runnable() {
-// @Override
-// public void run() {
-// onAppChanged();
-//
-// Log.e(TAG, "Installer aborted with errorCode: " + errorCode);
-//
-// AlertDialog.Builder alertBuilder = new AlertDialog.Builder(AppDetails.this);
-// alertBuilder.setTitle(title);
-// alertBuilder.setMessage(body);
-// alertBuilder.setNeutralButton(android.R.string.ok, null);
-// alertBuilder.create().show();
-// }
-// });
+ String errorMessage =
+ intent.getStringExtra(Installer.EXTRA_ERROR_MESSAGE);
+
+ if (!TextUtils.isEmpty(errorMessage)) {
+ Log.e(TAG, "Installer aborted with errorMessage: " + errorMessage);
+
+ AlertDialog.Builder alertBuilder = new AlertDialog.Builder(AppDetails.this);
+ alertBuilder.setTitle(R.string.uninstall_error_notify_title);
+ alertBuilder.setMessage(errorMessage);
+ alertBuilder.setNeutralButton(android.R.string.ok, null);
+ alertBuilder.create().show();
+ }
+
+ localBroadcastManager.unregisterReceiver(this);
break;
}
case Installer.ACTION_UNINSTALL_USER_INTERACTION: {
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 d31d2641b..d43f6d040 100644
--- a/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java
+++ b/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstaller.java
@@ -25,9 +25,7 @@ import android.content.Intent;
import android.net.Uri;
import android.util.Log;
-import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.Utils;
-import org.fdroid.fdroid.privileged.install.InstallExtensionDialogActivity;
import java.io.File;
@@ -43,36 +41,22 @@ public class DefaultInstaller extends Installer {
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
- Utils.debugLog(TAG, "ACTION_INSTALL uri: " + uri + " file: " + new File(uri.getPath()));
+ Utils.debugLog(TAG, "DefaultInstaller uri: " + uri + " file: " + new File(uri.getPath()));
Uri sanitizedUri;
try {
sanitizedUri = Installer.prepareApkFile(mContext, uri, packageName);
} catch (Installer.InstallFailedException e) {
Log.e(TAG, "prepareApkFile failed", e);
+ sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
+ e.getMessage());
return;
}
- Intent installIntent;
- // special case: F-Droid Privileged Extension
- if (packageName != null && packageName.equals(PrivilegedInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME)) {
-
- // extension must be signed with the same public key as main F-Droid
- // NOTE: Disabled for debug builds to be able to use official extension from repo
- ApkSignatureVerifier signatureVerifier = new ApkSignatureVerifier(mContext);
- if (!BuildConfig.DEBUG && !signatureVerifier.hasFDroidSignature(new File(sanitizedUri.getPath()))) {
- throw new RuntimeException("APK signature of extension not correct!");
- }
-
- installIntent = new Intent(mContext, InstallExtensionDialogActivity.class);
- installIntent.setAction(InstallExtensionDialogActivity.ACTION_INSTALL);
- installIntent.setData(sanitizedUri);
- } else {
- installIntent = new Intent(mContext, DefaultInstallerActivity.class);
- installIntent.setAction(DefaultInstallerActivity.ACTION_INSTALL_PACKAGE);
- installIntent.putExtra(DefaultInstallerActivity.EXTRA_ORIGINATING_URI, originatingUri);
- installIntent.setData(sanitizedUri);
- }
+ Intent installIntent = new Intent(mContext, DefaultInstallerActivity.class);
+ installIntent.setAction(DefaultInstallerActivity.ACTION_INSTALL_PACKAGE);
+ installIntent.putExtra(DefaultInstallerActivity.EXTRA_ORIGINATING_URI, originatingUri);
+ installIntent.setData(sanitizedUri);
PendingIntent installPendingIntent = PendingIntent.getActivity(
mContext.getApplicationContext(),
@@ -88,17 +72,10 @@ public class DefaultInstaller extends Installer {
protected void uninstallPackage(String packageName) {
sendBroadcastUninstall(packageName, Installer.ACTION_UNINSTALL_STARTED);
- Intent uninstallIntent;
- // special case: F-Droid Privileged Extension
- if (packageName != null && packageName.equals(PrivilegedInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME)) {
- uninstallIntent = new Intent(mContext, InstallExtensionDialogActivity.class);
- uninstallIntent.setAction(InstallExtensionDialogActivity.ACTION_UNINSTALL);
- } else {
- uninstallIntent = new Intent(mContext, DefaultInstallerActivity.class);
- uninstallIntent.setAction(DefaultInstallerActivity.ACTION_UNINSTALL_PACKAGE);
- uninstallIntent.putExtra(
- DefaultInstallerActivity.EXTRA_UNINSTALL_PACKAGE_NAME, packageName);
- }
+ Intent uninstallIntent = new Intent(mContext, DefaultInstallerActivity.class);
+ uninstallIntent.setAction(DefaultInstallerActivity.ACTION_UNINSTALL_PACKAGE);
+ uninstallIntent.putExtra(
+ DefaultInstallerActivity.EXTRA_UNINSTALL_PACKAGE_NAME, packageName);
PendingIntent uninstallPendingIntent = PendingIntent.getActivity(
mContext.getApplicationContext(),
packageName.hashCode(),
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 aada32327..eb5e1ccb5 100644
--- a/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstallerActivity.java
+++ b/app/src/main/java/org/fdroid/fdroid/installer/DefaultInstallerActivity.java
@@ -30,6 +30,7 @@ import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
+import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
/**
@@ -207,9 +208,10 @@ public class DefaultInstallerActivity extends FragmentActivity {
}
default:
case Activity.RESULT_FIRST_USER: {
- // AOSP actually returns Activity.RESULT_FIRST_USER if something breaks
+ // AOSP returns Activity.RESULT_FIRST_USER on error
installer.sendBroadcastInstall(mInstallUri, mInstallOriginatingUri,
- Installer.ACTION_INSTALL_INTERRUPTED, "error");
+ Installer.ACTION_INSTALL_INTERRUPTED,
+ getString(R.string.install_error_unknown));
break;
}
}
@@ -237,11 +239,10 @@ public class DefaultInstallerActivity extends FragmentActivity {
}
default:
case Activity.RESULT_FIRST_USER: {
- // AOSP UninstallAppProgress actually returns
- // Activity.RESULT_FIRST_USER if something breaks
+ // AOSP UninstallAppProgress returns RESULT_FIRST_USER on error
installer.sendBroadcastUninstall(mUninstallPackageName,
Installer.ACTION_UNINSTALL_INTERRUPTED,
- "error");
+ getString(R.string.uninstall_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 887d18290..c778a6897 100644
--- a/app/src/main/java/org/fdroid/fdroid/installer/ExtensionInstaller.java
+++ b/app/src/main/java/org/fdroid/fdroid/installer/ExtensionInstaller.java
@@ -43,13 +43,13 @@ public class ExtensionInstaller extends Installer {
@Override
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
- sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
-
Uri sanitizedUri;
try {
sanitizedUri = Installer.prepareApkFile(mContext, uri, packageName);
} catch (InstallFailedException e) {
Log.e(TAG, "prepareApkFile failed", e);
+ sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
+ e.getMessage());
return;
}
@@ -57,10 +57,10 @@ public class ExtensionInstaller extends Installer {
// NOTE: Disabled for debug builds to be able to use official extension from repo
ApkSignatureVerifier signatureVerifier = new ApkSignatureVerifier(mContext);
if (!BuildConfig.DEBUG && !signatureVerifier.hasFDroidSignature(new File(sanitizedUri.getPath()))) {
- throw new RuntimeException("APK signature of extension not correct!");
+ sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
+ "APK signature of extension not correct!");
}
- Intent installIntent;
- installIntent = new Intent(mContext, InstallExtensionDialogActivity.class);
+ Intent installIntent = new Intent(mContext, InstallExtensionDialogActivity.class);
installIntent.setAction(InstallExtensionDialogActivity.ACTION_INSTALL);
installIntent.setData(sanitizedUri);
@@ -72,14 +72,16 @@ public class ExtensionInstaller extends Installer {
sendBroadcastInstall(uri, originatingUri,
Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent);
+
+ // don't use broadcasts for the rest of this special installer
+ sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_COMPLETE);
}
@Override
protected void uninstallPackage(String packageName) {
sendBroadcastUninstall(packageName, Installer.ACTION_UNINSTALL_STARTED);
- Intent uninstallIntent;
- uninstallIntent = new Intent(mContext, InstallExtensionDialogActivity.class);
+ Intent uninstallIntent = new Intent(mContext, InstallExtensionDialogActivity.class);
uninstallIntent.setAction(InstallExtensionDialogActivity.ACTION_UNINSTALL);
PendingIntent uninstallPendingIntent = PendingIntent.getActivity(
@@ -90,5 +92,8 @@ public class ExtensionInstaller extends Installer {
sendBroadcastUninstall(packageName,
Installer.ACTION_UNINSTALL_USER_INTERACTION, uninstallPendingIntent);
+
+ // don't use broadcasts for the rest of this special installer
+ sendBroadcastUninstall(packageName, Installer.ACTION_UNINSTALL_COMPLETE);
}
}
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 2630c6081..8dcaa8001 100644
--- a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java
+++ b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java
@@ -19,6 +19,7 @@ import android.text.TextUtils;
import org.fdroid.fdroid.AppDetails;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
+import org.fdroid.fdroid.compat.PackageManagerCompat;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.net.Downloader;
@@ -274,15 +275,26 @@ public class InstallManagerService extends Service {
Uri originatingUri =
intent.getParcelableExtra(Installer.EXTRA_ORIGINATING_URI);
String urlString = originatingUri.toString();
- removeFromActive(urlString);
+ Apk apk = removeFromActive(urlString);
+
+ PackageManagerCompat.setInstaller(getPackageManager(), apk.packageName);
localBroadcastManager.unregisterReceiver(this);
-
break;
}
case Installer.ACTION_INSTALL_INTERRUPTED: {
- localBroadcastManager.unregisterReceiver(this);
+ Uri originatingUri =
+ intent.getParcelableExtra(Installer.EXTRA_ORIGINATING_URI);
+ String urlString = originatingUri.toString();
+ String errorMessage =
+ intent.getStringExtra(Installer.EXTRA_ERROR_MESSAGE);
+ if (!TextUtils.isEmpty(errorMessage)) {
+ App app = getAppFromActive(urlString);
+ notifyError(app, urlString, errorMessage, false);
+ }
+
+ localBroadcastManager.unregisterReceiver(this);
break;
}
case Installer.ACTION_INSTALL_USER_INTERACTION: {
@@ -292,7 +304,7 @@ public class InstallManagerService extends Service {
intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI);
Utils.debugLog(TAG, "originatingUri: " + originatingUri);
- Apk apk = getFromActive(originatingUri.toString());
+ Apk apk = getApkFromActive(originatingUri.toString());
// show notification if app details is not visible
if (AppDetails.isAppVisible(apk.packageName)) {
cancelNotification(originatingUri.toString());
@@ -379,6 +391,25 @@ public class InstallManagerService extends Service {
notificationManager.notify(downloadUrlId, notification);
}
+ private void notifyError(App app, String urlString, String text, boolean uninstall) {
+ String title;
+ if (uninstall) {
+ title = String.format(getString(R.string.uninstall_error_notify_title), app.name);
+ } else {
+ title = String.format(getString(R.string.install_error_notify_title), app.name);
+ }
+
+ int downloadUrlId = urlString.hashCode();
+ NotificationCompat.Builder builder =
+ new NotificationCompat.Builder(this)
+ .setAutoCancel(true)
+ .setContentTitle(title)
+ .setSmallIcon(R.drawable.ic_issues)
+ .setContentText(text);
+ NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ nm.notify(downloadUrlId, builder.build());
+ }
+
/**
* Cancel the {@link Notification} tied to {@code urlString}, which is the
* unique ID used to represent a given APK file. {@link String#hashCode()}
@@ -393,7 +424,7 @@ public class InstallManagerService extends Service {
ACTIVE_APPS.put(app.packageName, app);
}
- private static Apk getFromActive(String urlString) {
+ private static Apk getApkFromActive(String urlString) {
return ACTIVE_APKS.get(urlString);
}
@@ -404,6 +435,10 @@ public class InstallManagerService extends Service {
* {@link BroadcastReceiver}s, in which case {@code urlString} would not
* find anything in the active maps.
*/
+ private static App getAppFromActive(String urlString) {
+ return ACTIVE_APPS.get(getApkFromActive(urlString).packageName);
+ }
+
private static Apk removeFromActive(String urlString) {
Apk apk = ACTIVE_APKS.remove(urlString);
if (apk != null) {
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 b53d5e06e..3663ecd5c 100644
--- a/app/src/main/java/org/fdroid/fdroid/installer/Installer.java
+++ b/app/src/main/java/org/fdroid/fdroid/installer/Installer.java
@@ -160,6 +160,9 @@ public abstract class Installer {
// if (count < 0) {
// mCallback.onError(InstallerCallback.OPERATION_INSTALL,
// InstallerCallback.ERROR_CODE_CANNOT_PARSE);
+
+// install_error_cannot_parse
+
// return;
// }
// if (count > 0) {
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 e1158aa67..4307b98a4 100644
--- a/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java
+++ b/app/src/main/java/org/fdroid/fdroid/installer/PrivilegedInstaller.java
@@ -151,6 +151,8 @@ public class PrivilegedInstaller extends Installer {
sanitizedUri = Installer.prepareApkFile(mContext, uri, packageName);
} catch (Installer.InstallFailedException e) {
Log.e(TAG, "prepareApkFile failed", e);
+ sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
+ e.getMessage());
return;
}
@@ -299,6 +301,9 @@ public class PrivilegedInstaller extends Installer {
// } else if (resultCode == InstallConfirmActivity.RESULT_CANNOT_PARSE) {
// mCallback.onError(InstallerCallback.OPERATION_INSTALL,
// InstallerCallback.ERROR_CODE_CANNOT_PARSE);
+
+// install_error_cannot_parse
+
// } else { // Activity.RESULT_CANCELED
// mCallback.onError(InstallerCallback.OPERATION_INSTALL,
// InstallerCallback.ERROR_CODE_CANCELED);
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d07727e72..a9b4acd8e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -267,10 +267,8 @@
Requesting root access…
Root access denied
Either your Android device is not rooted or you have denied root access for F-Droid.
- Install error
Failed to install due to an unknown error
An error occurred while parsing the package
- Uninstall error
Failed to uninstall due to an unknown error
F-Droid Privileged Extension is not available
This option is only available when F-Droid Privileged Extension is installed.
@@ -365,6 +363,9 @@
Download completed, tap to install
Download unsuccessful
Waiting to start download…
+ Error installing %s
+ Error uninstalling %s
+
New:
Provided by %1$s.