From 1a81e2ddd680b645d4e22aa8879c37caeb771c45 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 9 Oct 2020 11:44:10 -0300 Subject: [PATCH] If possible, open the app store an app was originally installed with When an app fails to install during restore, we offer the option to manually install it. If this doesn't happen with the same app store, it is likely that the installed app will have a different signature (e.g. Aurora vs. F-Droid). If the signature doesn't match, the data restore will fail. Therefore, we attempt to let the user only use the same store for re-install. There's a known issue that F-Droid doesn't report the proper package name: https://gitlab.com/fdroid/fdroidclient/-/issues/2085 --- .../seedvault/restore/RestoreViewModel.kt | 2 + .../restore/install/InstallIntentCreator.kt | 52 +++++++++++++++++++ .../install/InstallProgressFragment.kt | 18 +------ 3 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallIntentCreator.kt diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreViewModel.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreViewModel.kt index 8a80aad2..b089ec10 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreViewModel.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreViewModel.kt @@ -29,6 +29,7 @@ import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_APPS import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_BACKUP import com.stevesoltys.seedvault.restore.install.ApkRestore +import com.stevesoltys.seedvault.restore.install.InstallIntentCreator import com.stevesoltys.seedvault.restore.install.InstallResult import com.stevesoltys.seedvault.settings.SettingsManager import com.stevesoltys.seedvault.transport.TRANSPORT_ID @@ -88,6 +89,7 @@ internal class RestoreViewModel( switchMap(mChosenRestorableBackup) { backup -> getInstallResult(backup) } + internal val installIntentCreator by lazy { InstallIntentCreator(app.packageManager) } private val mNextButtonEnabled = MutableLiveData().apply { value = false } internal val nextButtonEnabled: LiveData = mNextButtonEnabled diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallIntentCreator.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallIntentCreator.kt new file mode 100644 index 00000000..3bf3fcb2 --- /dev/null +++ b/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallIntentCreator.kt @@ -0,0 +1,52 @@ +package com.stevesoltys.seedvault.restore.install + +import android.content.Intent +import android.content.Intent.ACTION_VIEW +import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK +import android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED +import android.content.pm.PackageManager +import android.net.Uri + +internal class InstallIntentCreator( + private val packageManager: PackageManager +) { + + private val installerToPackage = mapOf( + "org.fdroid.fdroid" to "org.fdroid.fdroid", + "org.fdroid.fdroid.privileged" to "org.fdroid.fdroid", + "com.aurora.store" to "com.aurora.store", + "com.aurora.services" to "com.aurora.store", + "com.android.vending" to "com.android.vending" + ) + private val isPackageInstalled = HashMap() + + fun getIntent(packageName: CharSequence, installerPackageName: CharSequence?): Intent { + val i = Intent(ACTION_VIEW, Uri.parse("market://details?id=$packageName")).apply { + addFlags(FLAG_ACTIVITY_NEW_TASK) + addFlags(FLAG_ACTIVITY_CLEAR_TOP) + addFlags(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) + } + getIntentPackage(installerPackageName)?.let { i.setPackage(it) } + return i + } + + /** + * Returns a package name to restrict the intent to + * or null if we can't restrict the intent. + */ + private fun getIntentPackage(installerPackageName: CharSequence?): String? { + if (installerPackageName == null) return null + val packageName = installerToPackage[installerPackageName] ?: return null + val isInstalled = isPackageInstalled.getOrPut(packageName) { + try { + packageManager.getPackageInfo(packageName, 0) + true + } catch (e: PackageManager.NameNotFoundException) { + false + } + } + return if (isInstalled) packageName else null + } + +} diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt index 2a96d476..4c8023c3 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt @@ -1,11 +1,5 @@ package com.stevesoltys.seedvault.restore.install -import android.content.Intent -import android.content.Intent.ACTION_VIEW -import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP -import android.content.Intent.FLAG_ACTIVITY_NEW_TASK -import android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED -import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -121,16 +115,8 @@ class InstallProgressFragment : Fragment(), InstallItemListener { } override fun onFailedItemClicked(item: ApkInstallResult) { - // TODO restrict intent to installer package names to one of: - // * "org.fdroid.fdroid" "org.fdroid.fdroid.privileged" - // * "com.aurora.store" - // * "com.android.vending" - val i = Intent(ACTION_VIEW, Uri.parse("market://details?id=${item.packageName}")).apply { - addFlags(FLAG_ACTIVITY_NEW_TASK) - addFlags(FLAG_ACTIVITY_CLEAR_TOP) - addFlags(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) - // setPackage("com.aurora.store") - } + val i = + viewModel.installIntentCreator.getIntent(item.packageName, item.installerPackageName) startActivity(i) }