From 1c4ac91c6cd8440a1874390d4fd1f32953a2e8e3 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Mon, 10 Aug 2020 18:11:16 +0530 Subject: Prompt user to install OpenKeychain when missing (#1005) * Prompt user to install OpenKeychain when missing Fixes #996 Signed-off-by: Harsh Shandilya * Update changelog Signed-off-by: Harsh Shandilya --- CHANGELOG.md | 1 + .../com/zeapo/pwdstore/crypto/BasePgpActivity.kt | 62 ++++++++++++++++++++-- app/src/main/res/values/strings.xml | 8 +++ 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0b6bebf..128274c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. - Allow creating nested directories directly - I keep saying this but for real: error message for wrong SSH/HTTPS password is properly fixed now +- Fix crash when OpenKeychain is not installed ## [1.10.3] - 2020-07-30 diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt index c7648f55..fd7a8794 100644 --- a/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt @@ -6,10 +6,13 @@ package com.zeapo.pwdstore.crypto import android.app.PendingIntent +import android.content.ActivityNotFoundException import android.content.ClipData import android.content.Intent import android.content.IntentSender import android.content.SharedPreferences +import android.content.pm.PackageManager +import android.net.Uri import android.os.Build import android.os.Bundle import android.text.format.DateUtils @@ -17,10 +20,10 @@ import android.view.WindowManager import androidx.annotation.CallSuper import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity -import androidx.preference.PreferenceManager import com.github.ajalt.timberkt.Timber.tag import com.github.ajalt.timberkt.e import com.github.ajalt.timberkt.i +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.zeapo.pwdstore.ClipboardService import com.zeapo.pwdstore.R @@ -78,6 +81,12 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou private var serviceConnection: OpenPgpServiceConnection? = null var api: OpenPgpApi? = null + /** + * A [OpenPgpServiceConnection.OnBound] instance for the last listener that we wish to bind with + * in case the previous attempt was cancelled due to missing [OPENPGP_PROVIDER] package. + */ + private var previousListener: OpenPgpServiceConnection.OnBound? = null + /** * [onCreate] sets the window up with the right flags to prevent auth leaks through screenshots * or recent apps screen. @@ -98,6 +107,16 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou override fun onDestroy() { super.onDestroy() serviceConnection?.unbindFromService() + previousListener = null + } + + /** + * [onResume] controls the flow for resumption of a PGP operation that was previously interrupted + * by the [OPENPGP_PROVIDER] package being missing. + */ + override fun onResume() { + super.onResume() + previousListener?.let { bindToOpenKeychain(it) } } /** @@ -122,8 +141,45 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou * Method for subclasses to initiate binding with [OpenPgpServiceConnection]. */ fun bindToOpenKeychain(onBoundListener: OpenPgpServiceConnection.OnBound) { - serviceConnection = OpenPgpServiceConnection(this, OPENPGP_PROVIDER, onBoundListener) - serviceConnection?.bindToService() + val installed = try { + packageManager.getPackageInfo(OPENPGP_PROVIDER, 0) + true + } catch (_: PackageManager.NameNotFoundException) { + false + } + if (!installed) { + previousListener = onBoundListener + MaterialAlertDialogBuilder(this) + .setTitle(getString(R.string.openkeychain_not_installed_title)) + .setMessage(getString(R.string.openkeychain_not_installed_message)) + .setPositiveButton(getString(R.string.openkeychain_not_installed_google_play)) { _, _ -> + try { + val intent = Intent(Intent.ACTION_VIEW).apply { + data = Uri.parse(getString(R.string.play_deeplink_template, OPENPGP_PROVIDER)) + setPackage("com.android.vending") + } + startActivity(intent) + } catch (_: ActivityNotFoundException) { + } + } + .setNeutralButton(getString(R.string.openkeychain_not_installed_fdroid)) { _, _ -> + try { + val intent = Intent(Intent.ACTION_VIEW).apply { + data = Uri.parse(getString(R.string.fdroid_deeplink_template, OPENPGP_PROVIDER)) + } + startActivity(intent) + } catch (_: ActivityNotFoundException) { + } + } + .setOnCancelListener { finish() } + .show() + return + } else { + previousListener = null + serviceConnection = OpenPgpServiceConnection(this, OPENPGP_PROVIDER, onBoundListener).also { + it.bindToService() + } + } } /** diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b5f1192d..8303e18d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -375,4 +375,12 @@ Push was rejected by remote, reason: %1$s Remote rejected non-fast-forward push. Check receive.denyNonFastForwards variable in config file of destination repository. Running git operation… + + + OpenKeychain not installed + OpenKeychain is required for Password Store to function, please install it from the stores below + Google Play + https://play.google.com/store/apps/details?id=%1$s + F-Droid + https://f-droid.org/en/packages/%1$s/ -- cgit v1.2.3