From ef717437a9e2abf1e4abb7eb72941e69530a837a Mon Sep 17 00:00:00 2001
From: Peter Serwylo <peter@serwylo.com>
Date: Tue, 8 Aug 2017 10:01:43 +1000
Subject: [PATCH] Explain multi-sig problems to user in app details.

---
 .../views/AppDetailsRecyclerViewAdapter.java  | 76 ++++++++++++++++++-
 app/src/main/res/values/strings.xml           |  7 ++
 2 files changed, 79 insertions(+), 4 deletions(-)

diff --git a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java
index 4af3004d4..61ab2c8d6 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java
@@ -12,6 +12,7 @@ import android.support.annotation.LayoutRes;
 import android.support.annotation.NonNull;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.TextViewCompat;
+import android.support.v7.app.AlertDialog;
 import android.support.v7.widget.GridLayout;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -96,6 +97,7 @@ public class AppDetailsRecyclerViewAdapter
     private RecyclerView recyclerView;
     private List<Object> items;
     private List<Apk> versions;
+    private List<Apk> compatibleVersionsDifferentSig;
     private boolean showVersions;
 
     private HeaderViewHolder headerView;
@@ -112,12 +114,16 @@ public class AppDetailsRecyclerViewAdapter
 
         // Get versions
         versions = new ArrayList<>();
+        compatibleVersionsDifferentSig = new ArrayList<>();
         final List<Apk> apks = ApkProvider.Helper.findByPackageName(context, this.app.packageName);
         for (final Apk apk : apks) {
             boolean allowByCompatability = apk.compatible || Preferences.get().showIncompatibleVersions();
             boolean allowBySig = this.app.installedSig == null || TextUtils.equals(this.app.installedSig, apk.sig);
-            if (allowByCompatability && allowBySig) {
-                versions.add(apk);
+            if (allowByCompatability) {
+                compatibleVersionsDifferentSig.add(apk);
+                if (allowBySig) {
+                    versions.add(apk);
+                }
             }
         }
 
@@ -226,8 +232,12 @@ public class AppDetailsRecyclerViewAdapter
                 View permissions = inflater.inflate(R.layout.app_details2_links, parent, false);
                 return new PermissionsViewHolder(permissions);
             case VIEWTYPE_VERSIONS:
-                View versions = inflater.inflate(R.layout.app_details2_links, parent, false);
-                return new VersionsViewHolder(versions);
+                View versionsView = inflater.inflate(R.layout.app_details2_links, parent, false);
+                if (versions.size() == 0) {
+                    return new NoVersionsViewHolder(versionsView);
+                } else {
+                    return new VersionsViewHolder(versionsView);
+                }
             case VIEWTYPE_VERSION:
                 View version = inflater.inflate(R.layout.apklistitem, parent, false);
                 return new VersionViewHolder(version);
@@ -690,6 +700,64 @@ public class AppDetailsRecyclerViewAdapter
         }
     }
 
+    private class NoVersionsViewHolder extends AppDetailsViewHolder {
+        final TextView headerView;
+
+        NoVersionsViewHolder(View view) {
+            super(view);
+            headerView = (TextView) view.findViewById(R.id.information);
+            TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(headerView, R.drawable.ic_access_time_24dp_grey600, 0, 0, 0);
+
+            itemView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    explainIncompatibleVersions();
+                }
+            });
+        }
+
+        @Override
+        public void bindModel() {
+            if (hasCompatibleApksDifferentSigs()) {
+                headerView.setText("No versions with compatible signature");
+            } else {
+                headerView.setText("No versions compatible with device");
+            }
+        }
+
+        /**
+         * Show a dialog to the user explaining the reaons there are no compatible versions.
+         * This will either be due to device features (e.g. NFC, API levels, etc) or being signed
+         * by a different certificate (as is often the case with apps from Google Play signed by
+         * upstream).
+         */
+        private void explainIncompatibleVersions() {
+            String preferenceName = context.getString(R.string.show_incompat_versions);
+            String showIncompatible = context.getString(
+                    R.string.app_details__no_versions__show_incompat_versions, preferenceName);
+
+            String message;
+            String title;
+            if (hasCompatibleApksDifferentSigs()) {
+                title = context.getString(R.string.app_details__no_versions__no_compatible_signatures);
+                message = context.getString(R.string.app_details__no_versions__explain_incompatible_signatures) +
+                        "\n\n" + showIncompatible;
+            } else {
+                title = context.getString(R.string.app_details__no_versions__none_compatible_with_device);
+                message = showIncompatible;
+            }
+
+            new AlertDialog.Builder(context)
+                    .setTitle(title)
+                    .setMessage(message)
+                    .show();
+        }
+
+        private boolean hasCompatibleApksDifferentSigs() {
+            return compatibleVersionsDifferentSig != null && compatibleVersionsDifferentSig.size() > 0;
+        }
+    }
+
     private class PermissionsViewHolder extends ExpandableLinearLayoutViewHolder {
 
         PermissionsViewHolder(View view) {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c3e01cc93..6136cb79d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -54,6 +54,13 @@
     <string name="app_details_donate_prompt_unknown_author">Buy the developers of %1$s a coffee!</string>
     <string name="app_details_donate_prompt">%1$s is created by %2$s. Buy them a coffee!</string>
 
+    <string name="app_details__no_versions__show_incompat_versions">To show incompatible versions here anyway, enable the \"%1$s\" setting.</string>
+    <string name="app_details__no_versions__no_compatible_signatures">No versions with compatible signature</string>
+    <string name="app_details__no_versions__none_compatible_with_device">No versions compatible with device</string>
+    <string name="app_details__no_versions__explain_incompatible_signatures">The installed version is not compatible with any available versions. Uninstalling the app will enable you to view and install compatible versions.
+
+This often occurs with apps installed via Google Play or other sources, if they are signed by a different certificate.</string>
+
     <string name="about_title">About F-Droid</string>
     <string name="about_version">Version</string>
     <string name="about_site">Website</string>