From 6c127077206bb11bad02148fe9054ff7f43ef2ab Mon Sep 17 00:00:00 2001
From: Peter Serwylo <peter@serwylo.com>
Date: Wed, 12 Apr 2017 14:36:03 +1000
Subject: [PATCH] Update AppDetails buttons after upgrading app to latest
 version.

Prior to this, it would only update the "Uninstall"/"Run"/"Upgrade"
buttons after a fresh install, or an uninstall.

This change is a bit more liberal in how often we try to update the
view, due to a race condition with PackageManager and AppDetails2.
AppDetails2 listens for InstalledAppProviderService in onResume, but
sometimes that is too late (the notification has already fired).
---
 .../main/java/org/fdroid/fdroid/AppDetails2.java    | 13 ++++++++++++-
 .../fdroid/data/InstalledAppProviderService.java    |  3 +++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/app/src/main/java/org/fdroid/fdroid/AppDetails2.java b/app/src/main/java/org/fdroid/fdroid/AppDetails2.java
index 7bd70df9a..067631236 100644
--- a/app/src/main/java/org/fdroid/fdroid/AppDetails2.java
+++ b/app/src/main/java/org/fdroid/fdroid/AppDetails2.java
@@ -469,9 +469,20 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
                 case Installer.ACTION_INSTALL_COMPLETE:
                     adapter.clearProgress();
                     unregisterInstallReceiver();
-                    // Don't try and update the view here, because the InstalledAppProviderService
+                    // Ideally, we wouldn't try to update the view here, because the InstalledAppProviderService
                     // hasn't had time to do its thing and mark the app as installed. Instead, we
                     // wait for that service to notify us, and then we will respond in appObserver.
+
+                    // Having said that, there are some cases where the PackageManager doesn't
+                    // return control back to us until after it has already braodcast to the
+                    // InstalledAppProviderService. This means that we are not listening for any
+                    // feedback from InstalledAppProviderService (we intentionally stop listening in
+                    // onPause). Empirically, this happens when upgrading an app rather than a clean
+                    // install. However given the nature of this race condition, it may be different
+                    // on different operating systems. As such, we'll just update our view now. It may
+                    // happen again in our appObserver, but that will only cause a little more load
+                    // on the system, it shouldn't cause a different UX.
+                    onAppChanged();
                     break;
                 case Installer.ACTION_INSTALL_INTERRUPTED:
                     adapter.clearProgress();
diff --git a/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java b/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java
index 67c92743b..adf78e0f4 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java
@@ -10,6 +10,7 @@ import android.content.pm.Signature;
 import android.net.Uri;
 import android.os.Process;
 import android.support.annotation.Nullable;
+import android.util.Log;
 
 import org.acra.ACRA;
 import org.fdroid.fdroid.Hasher;
@@ -173,6 +174,7 @@ public class InstalledAppProviderService extends IntentService {
         if (ACTION_INSERT.equals(action)) {
             PackageInfo packageInfo = getPackageInfo(intent, packageName);
             if (packageInfo != null) {
+                Log.i(TAG, "Marking " + packageName + " as installed");
                 File apk = new File(packageInfo.applicationInfo.publicSourceDir);
                 if (apk.isDirectory()) {
                     FilenameFilter filter = new FilenameFilter() {
@@ -204,6 +206,7 @@ public class InstalledAppProviderService extends IntentService {
                 }
             }
         } else if (ACTION_DELETE.equals(action)) {
+            Log.i(TAG, "Marking " + packageName + " as no longer installed");
             deleteAppFromDb(this, packageName);
         }
         notifyEvents.onNext(null);