From 681c557e9ef174543c290aff4346a52326ba3950 Mon Sep 17 00:00:00 2001 From: Fabian Henneke Date: Tue, 14 Jul 2020 11:30:29 +0200 Subject: Revert "Work around Chrome Autofill issue (#921)" (#933) --- CHANGELOG.md | 1 - app/src/main/AndroidManifest.xml | 13 --- .../main/java/com/zeapo/pwdstore/UserPreference.kt | 57 +++---------- .../pwdstore/autofill/oreo/ChromeCompatFix.kt | 94 ---------------------- .../com/zeapo/pwdstore/utils/PreferenceKeys.kt | 1 - app/src/main/res/values-v28/bools.xml | 8 -- app/src/main/res/values/bools.xml | 1 - app/src/main/res/values/strings.xml | 11 --- .../res/xml/oreo_autofill_chrome_compat_fix.xml | 13 --- app/src/main/res/xml/preference.xml | 5 -- 10 files changed, 9 insertions(+), 195 deletions(-) delete mode 100644 app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ChromeCompatFix.kt delete mode 100644 app/src/main/res/values-v28/bools.xml delete mode 100644 app/src/main/res/xml/oreo_autofill_chrome_compat_fix.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 729e66cd..35f99d5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,6 @@ All notable changes to this project will be documented in this file. - Fix authentication failure with usernames that contain the `@` character - Text input boxes were illegible on dark theme - Top-level password names had inconsistent top margin making them look askew -- Autofill can now be made more reliable in Chrome by enabling an accessibility service that works around known Chrome limitations - Password Store no longer ignores the selected OpenKeychain key - Password export now happens in a separate process, preventing possible freezes diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4e6ea102..5fcbe706 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -99,19 +99,6 @@ android:name="android.accessibilityservice" android:resource="@xml/autofill_config" /> - - - - - - - - diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt index 950b6523..f713ad26 100644 --- a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt +++ b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt @@ -41,9 +41,7 @@ import com.github.ajalt.timberkt.w import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.zeapo.pwdstore.autofill.AutofillPreferenceActivity -import com.zeapo.pwdstore.autofill.AutofillService import com.zeapo.pwdstore.autofill.oreo.BrowserAutofillSupportLevel -import com.zeapo.pwdstore.autofill.oreo.ChromeCompatFix import com.zeapo.pwdstore.autofill.oreo.getInstalledBrowsersWithAutofillSupportLevel import com.zeapo.pwdstore.crypto.BasePgpActivity import com.zeapo.pwdstore.crypto.GetKeyIdsActivity @@ -72,7 +70,6 @@ class UserPreference : AppCompatActivity() { class PrefsFragment : PreferenceFragmentCompat() { private var autoFillEnablePreference: SwitchPreferenceCompat? = null - private var oreoAutofillChromeCompatFix: SwitchPreferenceCompat? = null private var clearSavedPassPreference: Preference? = null private lateinit var autofillDependencies: List private lateinit var oreoAutofillDependencies: List @@ -118,7 +115,6 @@ class UserPreference : AppCompatActivity() { // Autofill preferences autoFillEnablePreference = findPreference(PreferenceKeys.AUTOFILL_ENABLE) - oreoAutofillChromeCompatFix = findPreference(PreferenceKeys.OREO_AUTOFILL_CHROME_COMPAT_FIX) val oreoAutofillDirectoryStructurePreference = findPreference(PreferenceKeys.OREO_AUTOFILL_DIRECTORY_STRUCTURE) val oreoAutofillDefaultUsername = findPreference(PreferenceKeys.OREO_AUTOFILL_DEFAULT_USERNAME) val oreoAutofillCustomPublixSuffixes = findPreference(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES) @@ -277,16 +273,6 @@ class UserPreference : AppCompatActivity() { true } - oreoAutofillChromeCompatFix?.onPreferenceClickListener = ClickListener { - if (oreoAutofillChromeCompatFix!!.isChecked) { - startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)) - true - } else { - // Service will disable itself on startup if the preference has the value false. - false - } - } - findPreference(PreferenceKeys.EXPORT_PASSWORDS)?.apply { isVisible = sharedPreferences.getBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) onPreferenceClickListener = Preference.OnPreferenceClickListener { @@ -409,20 +395,16 @@ class UserPreference : AppCompatActivity() { } private fun updateAutofillSettings() { - val isAccessibilityAutofillServiceEnabled = callingActivity.isAccessibilityAutofillServiceEnabled + val isAccessibilityServiceEnabled = callingActivity.isAccessibilityServiceEnabled val isAutofillServiceEnabled = callingActivity.isAutofillServiceEnabled autoFillEnablePreference?.isChecked = - isAccessibilityAutofillServiceEnabled || isAutofillServiceEnabled + isAccessibilityServiceEnabled || isAutofillServiceEnabled autofillDependencies.forEach { - it.isVisible = isAccessibilityAutofillServiceEnabled + it.isVisible = isAccessibilityServiceEnabled } oreoAutofillDependencies.forEach { it.isVisible = isAutofillServiceEnabled } - oreoAutofillChromeCompatFix?.apply { - isChecked = callingActivity.isChromeCompatFixServiceEnabled - isVisible = callingActivity.isChromeCompatFixServiceSupported - } } private fun updateClearSavedPassphrasePrefs() { @@ -443,16 +425,13 @@ class UserPreference : AppCompatActivity() { } private fun onEnableAutofillClick() { - if (callingActivity.isAccessibilityAutofillServiceEnabled) { + if (callingActivity.isAccessibilityServiceEnabled) { startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)) } else if (callingActivity.isAutofillServiceEnabled) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) callingActivity.autofillManager!!.disableAutofillServices() - ChromeCompatFix.setStatusInPreferences(requireContext(), false) - updateAutofillSettings() - } else { + else throw IllegalStateException("isAutofillServiceEnabled == true, but Build.VERSION.SDK_INT < Build.VERSION_CODES.O") - } } else { val enableOreoAutofill = callingActivity.isAutofillServiceSupported MaterialAlertDialogBuilder(callingActivity).run { @@ -744,32 +723,14 @@ class UserPreference : AppCompatActivity() { File("$filesDir/.ssh_key").writeText(lines.joinToString("\n")) } - private val isAccessibilityAutofillServiceEnabled: Boolean + private val isAccessibilityServiceEnabled: Boolean get() { val am = getSystemService() ?: return false val runningServices = am .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC) return runningServices - .mapNotNull { it?.resolveInfo?.serviceInfo } - .any { it.packageName == BuildConfig.APPLICATION_ID && it.name == AutofillService::class.java.name } - } - - private val isChromeCompatFixServiceEnabled: Boolean - get() { - val am = getSystemService() ?: return false - val runningServices = am - .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC) - return runningServices - .mapNotNull { it?.resolveInfo?.serviceInfo } - .any { it.packageName == BuildConfig.APPLICATION_ID && it.name == ChromeCompatFix::class.java.name } - } - - private val isChromeCompatFixServiceSupported: Boolean - get() { - // Autofill compat mode is only available starting with Android Pie and only makes sense - // when used with Autofill enabled. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return false - return isAutofillServiceEnabled + .map { it.id.substringBefore("/") } + .any { it == BuildConfig.APPLICATION_ID } } private val isAutofillServiceSupported: Boolean diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ChromeCompatFix.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ChromeCompatFix.kt deleted file mode 100644 index d1f81c0c..00000000 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ChromeCompatFix.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ -package com.zeapo.pwdstore.autofill.oreo - -import android.accessibilityservice.AccessibilityService -import android.content.Context -import android.content.SharedPreferences -import android.os.Build -import android.os.Handler -import android.os.Looper -import android.view.accessibility.AccessibilityEvent -import androidx.annotation.RequiresApi -import androidx.core.content.edit -import androidx.preference.PreferenceManager -import com.github.ajalt.timberkt.i -import com.github.ajalt.timberkt.v -import com.github.ajalt.timberkt.w -import com.zeapo.pwdstore.utils.PreferenceKeys -import com.zeapo.pwdstore.utils.autofillManager - -@RequiresApi(Build.VERSION_CODES.P) -class ChromeCompatFix : AccessibilityService() { - - companion object { - - fun setStatusInPreferences(context: Context, enabled: Boolean) { - PreferenceManager.getDefaultSharedPreferences(context).edit { - putBoolean(PreferenceKeys.OREO_AUTOFILL_CHROME_COMPAT_FIX, enabled) - } - } - } - - private val isEnabledInPreferences - get() = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(PreferenceKeys.OREO_AUTOFILL_CHROME_COMPAT_FIX, true) - - private val handler = Handler(Looper.getMainLooper()) - private val forceRootNodePopulation = Runnable { - val rootPackageName = rootInActiveWindow?.packageName.toString() - v { "$rootPackageName: forced root node population" } - } - private val disableListener = SharedPreferences.OnSharedPreferenceChangeListener { prefs: SharedPreferences, key: String -> - if (key != PreferenceKeys.OREO_AUTOFILL_CHROME_COMPAT_FIX) - return@OnSharedPreferenceChangeListener - if (!isEnabledInPreferences) { - i { "Disabled in settings, shutting down..." } - disableSelf() - } - } - - override fun onAccessibilityEvent(event: AccessibilityEvent) { - handler.removeCallbacks(forceRootNodePopulation) - when (event.eventType) { - AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, AccessibilityEvent.TYPE_ANNOUNCEMENT -> { - // WINDOW_STATE_CHANGED: Triggered on long press in a text field, replacement for - // the missing Autofill action menu item. - // ANNOUNCEMENT: Triggered when a password field is selected. - // - // These events are triggered only by user actions and thus don't need to be handled - // with debounce. However, they only trigger Autofill popups on the *next* input - // field selected by the user. - forceRootNodePopulation.run() - v { "${event.packageName} (${AccessibilityEvent.eventTypeToString(event.eventType)}): forced root node population" } - } - AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED -> { - // WINDOW_CONTENT_CHANGED: Triggered whenever the page contents change. - // - // This event is triggered many times during page load, which makes a debounce - // necessary to prevent huge performance regressions in Chrome. However, it is the - // only event that reliably runs before the user selects a text field. - handler.postDelayed(forceRootNodePopulation, 300) - v { "${event.packageName} (${AccessibilityEvent.eventTypeToString(event.eventType)}): debounced root node population" } - } - } - } - - override fun onServiceConnected() { - super.onServiceConnected() - // Allow the service to be activated only if the Autofill service is already enabled. - if (autofillManager?.hasEnabledAutofillServices() != true) { - w { "Autofill service not enabled, shutting down..." } - disableSelf() - return - } - // Update preferences if the user manually activated the service. - setStatusInPreferences(this, true) - - PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(disableListener) - } - - override fun onInterrupt() {} -} - diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt b/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt index 3fb05724..3235c7fc 100644 --- a/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt @@ -40,7 +40,6 @@ object PreferenceKeys { const val OPENPGP_KEY_IDS_SET = "openpgp_key_ids_set" const val OPENPGP_KEY_ID_PREF = "openpgp_key_id_pref" const val OPENPGP_PROVIDER_LIST = "openpgp_provider_list" - const val OREO_AUTOFILL_CHROME_COMPAT_FIX = "oreo_autofill_chrome_compat_fix" const val OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES = "oreo_autofill_custom_public_suffixes" const val OREO_AUTOFILL_DEFAULT_USERNAME = "oreo_autofill_default_username" const val OREO_AUTOFILL_DIRECTORY_STRUCTURE = "oreo_autofill_directory_structure" diff --git a/app/src/main/res/values-v28/bools.xml b/app/src/main/res/values-v28/bools.xml deleted file mode 100644 index 3dc8bf79..00000000 --- a/app/src/main/res/values-v28/bools.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - true - diff --git a/app/src/main/res/values/bools.xml b/app/src/main/res/values/bools.xml index b19e7848..475702a1 100644 --- a/app/src/main/res/values/bools.xml +++ b/app/src/main/res/values/bools.xml @@ -7,5 +7,4 @@ true true true - false diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0834b96e..a616896f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -275,16 +275,6 @@ Password Store can offer to fill login forms and even save credentials you enter in apps or on websites. To enable this feature, tap OK to go to Autofill settings. There, select Password Store from the list and confirm the confirmation prompt with OK. Autofill support with installed browsers: - Make Autofill more reliable in Chrome - This accessibility service makes - Autofill work more reliably in Chrome. It can only be activated if you are already using - Password Store as your Autofill service.\n\nThis service is only active while you are - using Chrome. It does not access any data or take any actions on your behalf, but forces - Chrome to properly forward user interactions to the Password Store Autofill - service.\n\nChrome\'s performance should not be noticeably affected. If you are experiencing - any problems with this service, please create an issue at - https://msfjarvis.dev/aps. - Autofills password fields in apps. Only works for Android versions 4.3 and up. Does not rely on the clipboard for Android versions 5.0 and up. @@ -399,7 +389,6 @@ Successfully imported TOTP configuration Failed to import TOTP configuration Improve reliability in Chrome - Requires activating an accessibility service and may affect overall Chrome performance Exporting passwords… File name must not contain \'/\', set directory above Directory diff --git a/app/src/main/res/xml/oreo_autofill_chrome_compat_fix.xml b/app/src/main/res/xml/oreo_autofill_chrome_compat_fix.xml deleted file mode 100644 index 196c93d5..00000000 --- a/app/src/main/res/xml/oreo_autofill_chrome_compat_fix.xml +++ /dev/null @@ -1,13 +0,0 @@ - - diff --git a/app/src/main/res/xml/preference.xml b/app/src/main/res/xml/preference.xml index d4ec4139..0d71d6cc 100644 --- a/app/src/main/res/xml/preference.xml +++ b/app/src/main/res/xml/preference.xml @@ -10,11 +10,6 @@ app:defaultValue="true" app:key="autofill_enable" app:title="@string/pref_autofill_enable_title" /> -