Merge branch 'fix-ish-698' into 'master'

handle install broadcasts after InstallManagerService was killed

If InstallManagerService was killed, it'll forget all of its state.  If it is killed while an install process is running, and that install fails,
InstallManagerService will receive a broadcast about the error but then it can't find anything about the app in question besides its download URL.
That is enough to control the notification, but not enough to get the name of the app in question.  This is a workaround by showing the APK filename when the app name cannot be found. Ideally, the packageName would somehow magically be delivered to InstallManagerService in this case, but the
Installer stuff doesn't always have it to send.

With android-23, there is getActiveNotifications(), which we might be able to use to stash the packageName and fetch it as needed.

See merge request !387
This commit is contained in:
Hans-Christoph Steiner 2016-09-07 12:16:56 +00:00
commit 3657cf3256
6 changed files with 53 additions and 34 deletions

View File

@ -45,7 +45,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
public static final String PREF_UPD_INTERVAL = "updateInterval";
public static final String PREF_UPD_WIFI_ONLY = "updateOnWifiOnly";
public static final String PREF_UPD_AUTO_DOWNLOAD = "updateAutoDownload";
public static final String PREF_AUTO_DOWNLOAD_INSTALL_UPDATES = "updateAutoDownload";
public static final String PREF_UPD_NOTIFY = "updateNotify";
public static final String PREF_UPD_HISTORY = "updateHistoryDays";
public static final String PREF_ROOTED = "rooted";
@ -222,7 +222,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
}
public boolean isAutoDownloadEnabled() {
return preferences.getBoolean(PREF_UPD_AUTO_DOWNLOAD, false);
return preferences.getBoolean(PREF_AUTO_DOWNLOAD_INSTALL_UPDATES, false);
}
public boolean isUpdateOnlyOnWifi() {

View File

@ -16,7 +16,6 @@ import android.support.v4.app.TaskStackBuilder;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import org.acra.ACRA;
import org.fdroid.fdroid.AppDetails;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
@ -249,22 +248,12 @@ public class InstallManagerService extends Service {
// show notification if app details is not visible
if (!TextUtils.isEmpty(errorMessage)) {
try {
// temp setup to debug https://gitlab.com/fdroid/fdroidclient/issues/698
App app = getAppFromActive(downloadUrl);
// show notification if app details is not visible
if (AppDetails.isAppVisible(app.packageName)) {
cancelNotification(downloadUrl);
} else {
String title = String.format(
getString(R.string.install_error_notify_title),
app.name);
notifyError(downloadUrl, title, errorMessage);
}
} catch (NullPointerException e) { //NOPMD
ACRA.getErrorReporter().handleException(
new IllegalStateException(errorMessage, e));
App app = getAppFromActive(downloadUrl);
// show notification if app details is not visible
if (app != null && AppDetails.isAppVisible(app.packageName)) {
cancelNotification(downloadUrl);
} else {
notifyError(downloadUrl, app, errorMessage);
}
}
removeFromActive(downloadUrl);
@ -342,7 +331,12 @@ public class InstallManagerService extends Service {
title = String.format(getString(R.string.tap_to_update_format),
pm.getApplicationLabel(pm.getApplicationInfo(apk.packageName, 0)));
} catch (PackageManager.NameNotFoundException e) {
title = String.format(getString(R.string.tap_to_install_format), getAppName(apk));
// TODO use packageName to fetch App instance from database if not cached
String name = getAppName(apk);
if (TextUtils.isEmpty(name) || name.equals(new App().name)) {
return; // do not have a name to display, so leave notification as is
}
title = String.format(getString(R.string.tap_to_install_format), name);
}
int downloadUrlId = urlString.hashCode();
@ -358,9 +352,19 @@ public class InstallManagerService extends Service {
notificationManager.notify(downloadUrlId, notification);
}
private void notifyError(String urlString, String title, String text) {
private void notifyError(String urlString, App app, String text) {
int downloadUrlId = urlString.hashCode();
String name;
if (app == null) {
// if we have nothing else, show the APK filename
String path = Uri.parse(urlString).getPath();
name = path.substring(path.lastIndexOf('/'), path.length());
} else {
name = app.name;
}
String title = String.format(getString(R.string.install_error_notify_title), name);
Intent errorDialogIntent = new Intent(this, ErrorDialogActivity.class);
errorDialogIntent.putExtra(
ErrorDialogActivity.EXTRA_TITLE, title);
@ -397,8 +401,16 @@ public class InstallManagerService extends Service {
ACTIVE_APPS.put(app.packageName, app);
}
/**
* Always returns an {@link Apk} instance to avoid annoying null guards.
*/
private static Apk getApkFromActive(String urlString) {
return ACTIVE_APKS.get(urlString);
Apk apk = ACTIVE_APKS.get(urlString);
if (apk == null) {
return new Apk();
} else {
return apk;
}
}
/**

View File

@ -21,7 +21,6 @@ package org.fdroid.fdroid.installer;
import android.content.Context;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.Apk;
@ -46,9 +45,7 @@ public class InstallerFactory {
&& apk.packageName.equals(PrivilegedInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME)) {
// special case for "F-Droid Privileged Extension"
installer = new ExtensionInstaller(context);
} else if (isPrivilegedInstallerEnabled()
&& PrivilegedInstaller.isExtensionInstalledCorrectly(context)
== PrivilegedInstaller.IS_EXTENSION_INSTALLED_YES) {
} else if (PrivilegedInstaller.isDefault(context)) {
Utils.debugLog(TAG, "privileged extension correctly installed -> PrivilegedInstaller");
installer = new PrivilegedInstaller(context);
} else {
@ -57,12 +54,4 @@ public class InstallerFactory {
return installer;
}
/**
* Extension has privileged permissions and preference is enabled?
*/
private static boolean isPrivilegedInstallerEnabled() {
return Preferences.get().isPrivilegedInstallerEnabled();
}
}

View File

@ -30,6 +30,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.privileged.IPrivilegedCallback;
@ -296,6 +297,14 @@ public class PrivilegedInstaller extends Installer {
return IS_EXTENSION_INSTALLED_YES;
}
/**
* Extension has privileged permissions and preference is enabled?
*/
public static boolean isDefault(Context context) {
return Preferences.get().isPrivilegedInstallerEnabled()
&& isExtensionInstalledCorrectly(context) == IS_EXTENSION_INSTALLED_YES;
}
@Override
protected void installPackageInternal(final Uri localApkUri, final Uri downloadUri, Apk apk) {
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED);

View File

@ -50,6 +50,7 @@ public class PreferencesFragment extends PreferenceFragment
private static final int REQUEST_INSTALL_ORBOT = 0x1234;
private CheckBoxPreference enableProxyCheckPref;
private CheckBoxPreference useTorCheckPref;
private Preference updateAutoDownloadPref;
private Preference updatePrivilegedExtensionPref;
private long currentKeepCacheTime;
@ -59,6 +60,7 @@ public class PreferencesFragment extends PreferenceFragment
addPreferencesFromResource(R.xml.preferences);
useTorCheckPref = (CheckBoxPreference) findPreference(Preferences.PREF_USE_TOR);
enableProxyCheckPref = (CheckBoxPreference) findPreference(Preferences.PREF_ENABLE_PROXY);
updateAutoDownloadPref = findPreference(Preferences.PREF_AUTO_DOWNLOAD_INSTALL_UPDATES);
updatePrivilegedExtensionPref = findPreference(Preferences.PREF_UNINSTALL_PRIVILEGED_APP);
}
@ -282,6 +284,11 @@ public class PreferencesFragment extends PreferenceFragment
return true;
}
});
if (PrivilegedInstaller.isDefault(getContext())) {
updateAutoDownloadPref.setTitle(R.string.update_auto_install);
updateAutoDownloadPref.setSummary(R.string.update_auto_install_summary);
}
}
@Override

View File

@ -22,6 +22,8 @@
<string name="automatic_scan_wifi_on">Update app lists automatically only on Wi-Fi</string>
<string name="update_auto_download">Automatically download updates</string>
<string name="update_auto_download_summary">Download the update files in the background</string>
<string name="update_auto_install">Automatically install updates</string>
<string name="update_auto_install_summary">Download and install update apps in the background</string>
<string name="notify">Update notifications</string>
<string name="notify_on">Show a notification when updates are available</string>
<string name="update_history">Update history</string>