From 80ed1e71800d2772ce317e94419ee0434c87e613 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 11 May 2016 21:11:14 +0200 Subject: [PATCH 1/3] prevent crash when starting swap in Android 6.0+ This just stops the crash for now, it does not yet request the permission. That'll be part of the big UX overhaul. #656 https://gitlab.com/fdroid/fdroidclient/issues/656 --- app/src/main/AndroidManifest.xml | 1 + .../main/java/org/fdroid/fdroid/views/swap/StartSwapView.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7b4b8cdd5..599b4f9b5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -47,6 +47,7 @@ + diff --git a/app/src/main/java/org/fdroid/fdroid/views/swap/StartSwapView.java b/app/src/main/java/org/fdroid/fdroid/views/swap/StartSwapView.java index 507e03fc7..3b15c261f 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/swap/StartSwapView.java +++ b/app/src/main/java/org/fdroid/fdroid/views/swap/StartSwapView.java @@ -436,7 +436,7 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In viewWifiId.setVisibility(TextUtils.isEmpty(FDroidApp.ipAddressString) ? View.GONE : View.VISIBLE); WifiApControl wifiAp = WifiApControl.getInstance(getActivity()); - if (wifiAp.isWifiApEnabled()) { + if (wifiAp != null && wifiAp.isWifiApEnabled()) { WifiConfiguration config = wifiAp.getConfiguration(); viewWifiNetwork.setText(getContext().getString(R.string.swap_active_hotspot, config.SSID)); } else if (TextUtils.isEmpty(FDroidApp.ssid)) { From cad7a9687d6d5c21b039c11ca5575b5562c43ce3 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 12 May 2016 11:25:43 +0200 Subject: [PATCH 2/3] manage InstallManagerService queue with methods This should hopefully make it a bit clearer how the list of active APKs is managed. --- .../installer/InstallManagerService.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) 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 c6a5e2272..6aa83b599 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java @@ -209,8 +209,7 @@ public class InstallManagerService extends Service { public void onReceive(Context context, Intent intent) { String urlString = intent.getDataString(); // TODO these need to be removed based on whether they are fed to InstallerService or not - Apk apk = ACTIVE_APKS.remove(urlString); - ACTIVE_APPS.remove(apk.packageName); + Apk apk = removeFromActive(urlString); if (AppDetails.isAppVisible(apk.packageName)) { cancelNotification(urlString); } else { @@ -223,8 +222,7 @@ public class InstallManagerService extends Service { @Override public void onReceive(Context context, Intent intent) { String urlString = intent.getDataString(); - Apk apk = ACTIVE_APKS.remove(urlString); - ACTIVE_APPS.remove(apk.packageName); + Apk apk = removeFromActive(urlString); unregisterDownloaderReceivers(urlString); cancelNotification(urlString); } @@ -319,6 +317,18 @@ public class InstallManagerService extends Service { notificationManager.cancel(urlString.hashCode()); } + private static void addToActive(String urlString, App app, Apk apk) { + ACTIVE_APKS.put(urlString, apk); + ACTIVE_APPS.put(app.packageName, app); + TEMP_HACK_APP_NAMES.put(urlString, app.name); // TODO delete me once InstallerService exists + } + + private static Apk removeFromActive(String urlString) { + Apk apk = ACTIVE_APKS.remove(urlString); + ACTIVE_APPS.remove(apk.packageName); + return apk; + } + /** * Install an APK, checking the cache and downloading if necessary before starting the process. * All notifications are sent as an {@link Intent} via local broadcasts to be received by @@ -328,9 +338,7 @@ public class InstallManagerService extends Service { public static void queue(Context context, App app, Apk apk) { String urlString = apk.getUrl(); Utils.debugLog(TAG, "queue " + app.packageName + " " + apk.versionCode + " from " + urlString); - ACTIVE_APKS.put(urlString, apk); - ACTIVE_APPS.put(app.packageName, app); - TEMP_HACK_APP_NAMES.put(urlString, app.name); // TODO delete me once InstallerService exists + addToActive(urlString, app, apk); Intent intent = new Intent(context, InstallManagerService.class); intent.setAction(ACTION_INSTALL); intent.setData(Uri.parse(urlString)); From 768b3d768859026b6dc2a63b14879fd61772ea40 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 12 May 2016 16:29:18 +0200 Subject: [PATCH 3/3] register event receivers for SwapAppsView when Apk is available This was crashing when coming to SwapAppsView because some of the flow changed related to the new DownloaderService and InstallManagerService. Also, this lazy loading is a tiny optimization that we cannot afford right now, there are far too many lifecycle bugs with swap. --- .../fdroid/views/swap/SwapAppsView.java | 45 +++++++------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java b/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java index dd360fcb7..bdb34a58a 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java +++ b/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java @@ -234,9 +234,6 @@ public class SwapAppsView extends ListView implements private final LocalBroadcastManager localBroadcastManager; private App app; - @Nullable - private Apk apkToInstall; - ProgressBar progressView; TextView nameView; ImageView iconView; @@ -289,33 +286,32 @@ public class SwapAppsView extends ListView implements Activity activity = getActivity(); if (activity != null) { app = AppProvider.Helper.findByPackageName(getActivity().getContentResolver(), app.packageName); - apkToInstall = null; // Force lazy loading to fetch correct apk next time. resetView(); } } }; ViewHolder() { - // TODO: Unregister receivers correctly... - - Apk apk = getApkToInstall(); - String url = apk.getUrl(); - - localBroadcastManager = LocalBroadcastManager.getInstance(getActivity()); - localBroadcastManager.registerReceiver(appListViewResetReceiver, - DownloaderService.getIntentFilter(url, Downloader.ACTION_STARTED)); - localBroadcastManager.registerReceiver(downloadProgressReceiver, - DownloaderService.getIntentFilter(url, Downloader.ACTION_PROGRESS)); - localBroadcastManager.registerReceiver(appListViewResetReceiver, - DownloaderService.getIntentFilter(url, Downloader.ACTION_COMPLETE)); - localBroadcastManager.registerReceiver(interruptedReceiver, - DownloaderService.getIntentFilter(url, Downloader.ACTION_INTERRUPTED)); + localBroadcastManager = LocalBroadcastManager.getInstance(getContext()); } public void setApp(@NonNull App app) { if (this.app == null || !this.app.packageName.equals(app.packageName)) { this.app = app; - apkToInstall = null; // Force lazy loading to fetch the correct apk next time. + + Context context = getContext(); + Apk apk = ApkProvider.Helper.find(context, app.packageName, app.suggestedVersionCode); + String urlString = apk.getUrl(); + + // TODO unregister receivers? or will they just die with this instance + localBroadcastManager.registerReceiver(appListViewResetReceiver, + DownloaderService.getIntentFilter(urlString, Downloader.ACTION_STARTED)); + localBroadcastManager.registerReceiver(downloadProgressReceiver, + DownloaderService.getIntentFilter(urlString, Downloader.ACTION_PROGRESS)); + localBroadcastManager.registerReceiver(appListViewResetReceiver, + DownloaderService.getIntentFilter(urlString, Downloader.ACTION_COMPLETE)); + localBroadcastManager.registerReceiver(interruptedReceiver, + DownloaderService.getIntentFilter(urlString, Downloader.ACTION_INTERRUPTED)); // NOTE: Instead of continually unregistering and re-registering the observer // (with a different URI), this could equally be done by only having one @@ -329,17 +325,6 @@ public class SwapAppsView extends ListView implements resetView(); } - /** - * Lazily load the apk from the database the first time it is requested. Means it wont - * be loaded unless we receive a download event from the {@link ApkDownloader}. - */ - private Apk getApkToInstall() { - if (apkToInstall == null) { - apkToInstall = ApkProvider.Helper.find(getActivity(), app.packageName, app.suggestedVersionCode); - } - return apkToInstall; - } - private void resetView() { if (app == null) {