diff options
| author | Fabian Henneke <FabianHenneke@users.noreply.github.com> | 2020-03-24 14:03:40 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-24 14:03:40 +0100 |
| commit | bebe43468330f182ea35e01ace555ce8d0512aeb (patch) | |
| tree | 85899eccd985b302183ee1551054ef54bdb0ada5 /app/src/main/java/com/zeapo/pwdstore/UserPreference.kt | |
| parent | 98e9f6734a00cfb1d8164227b2de07d2aea150d2 (diff) | |
| download | HardenedPass-bebe43468330f182ea35e01ace555ce8d0512aeb.tar.gz HardenedPass-bebe43468330f182ea35e01ace555ce8d0512aeb.zip | |
Add support for Oreo Autofill (#653)
Adds support for the Autofill feature first available in Android Oreo.
In compatible apps and browsers, login forms are automatically detected and
the user is presented with options to fill or generate credentials. In most apps
and certain browsers, the service will also offer to create new Password Store
entries from credentials entered into login forms.
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/UserPreference.kt')
| -rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/UserPreference.kt | 126 |
1 files changed, 94 insertions, 32 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt index 8667110a..895338e9 100644 --- a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt +++ b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt @@ -6,7 +6,6 @@ package com.zeapo.pwdstore import android.accessibilityservice.AccessibilityServiceInfo import android.app.Activity -import android.content.Context import android.content.Intent import android.content.pm.ShortcutManager import android.net.Uri @@ -20,6 +19,7 @@ import android.view.MenuItem import android.view.accessibility.AccessibilityManager import android.widget.Toast import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.AppCompatTextView import androidx.biometric.BiometricManager import androidx.core.content.getSystemService import androidx.documentfile.provider.DocumentFile @@ -32,6 +32,8 @@ import androidx.preference.SwitchPreferenceCompat 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.oreo.BrowserAutofillSupportLevel +import com.zeapo.pwdstore.autofill.oreo.getInstalledBrowsersWithAutofillSupportLevel import com.zeapo.pwdstore.crypto.PgpActivity import com.zeapo.pwdstore.git.GitActivity import com.zeapo.pwdstore.pwgenxkpwd.XkpwdDictionary @@ -40,6 +42,7 @@ import com.zeapo.pwdstore.sshkeygen.SshKeyGenActivity import com.zeapo.pwdstore.utils.PasswordRepository import com.zeapo.pwdstore.utils.auth.AuthenticationResult import com.zeapo.pwdstore.utils.auth.Authenticator +import com.zeapo.pwdstore.utils.autofillManager import java.io.File import java.io.IOException import java.time.LocalDateTime @@ -127,9 +130,7 @@ class UserPreference : AppCompatActivity() { openkeystoreIdPreference?.isVisible = sharedPreferences.getString("ssh_openkeystore_keyid", null)?.isNotEmpty() ?: false - // see if the autofill service is enabled and check the preference accordingly - autoFillEnablePreference?.isChecked = callingActivity.isServiceEnabled - autofillDependencies.forEach { it?.isVisible = callingActivity.isServiceEnabled } + updateAutofillSettings() appVersionPreference?.summary = "Version: ${BuildConfig.VERSION_NAME}" @@ -242,24 +243,7 @@ class UserPreference : AppCompatActivity() { } autoFillEnablePreference?.onPreferenceClickListener = ClickListener { - var isEnabled = callingActivity.isServiceEnabled - if (isEnabled) { - startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)) - } else { - MaterialAlertDialogBuilder(callingActivity) - .setTitle(R.string.pref_autofill_enable_title) - .setView(R.layout.autofill_instructions) - .setPositiveButton(R.string.dialog_ok) { _, _ -> - startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)) - } - .setNegativeButton(R.string.dialog_cancel, null) - .setOnDismissListener { - isEnabled = callingActivity.isServiceEnabled - autoFillEnablePreference?.isChecked = isEnabled - autofillDependencies.forEach { it?.isVisible = isEnabled } - } - .show() - } + onEnableAutofillClick() true } @@ -370,11 +354,79 @@ class UserPreference : AppCompatActivity() { } } + private fun updateAutofillSettings() { + val isAccessibilityServiceEnabled = callingActivity.isAccessibilityServiceEnabled + autoFillEnablePreference?.isChecked = + isAccessibilityServiceEnabled || callingActivity.isAutofillServiceEnabled + autofillDependencies.forEach { + it?.isVisible = isAccessibilityServiceEnabled + } + } + + private fun onEnableAutofillClick() { + if (callingActivity.isAccessibilityServiceEnabled) { + startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)) + } else if (callingActivity.isAutofillServiceEnabled) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + callingActivity.autofillManager!!.disableAutofillServices() + else + throw IllegalStateException("isAutofillServiceEnabled == true, but Build.VERSION.SDK_INT < Build.VERSION_CODES.O") + } else { + val enableOreoAutofill = callingActivity.isAutofillServiceSupported + MaterialAlertDialogBuilder(callingActivity).run { + setTitle(R.string.pref_autofill_enable_title) + if (enableOreoAutofill && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val layout = + layoutInflater.inflate(R.layout.oreo_autofill_instructions, null) + val supportedBrowsersTextView = + layout.findViewById<AppCompatTextView>(R.id.supportedBrowsers) + supportedBrowsersTextView.text = + getInstalledBrowsersWithAutofillSupportLevel(context).joinToString( + separator = "\n" + ) { + val appLabel = it.first + val supportDescription = when (it.second) { + BrowserAutofillSupportLevel.None -> getString(R.string.oreo_autofill_no_support) + BrowserAutofillSupportLevel.FlakyFill -> getString(R.string.oreo_autofill_flaky_fill_support) + BrowserAutofillSupportLevel.Fill -> getString(R.string.oreo_autofill_fill_support) + BrowserAutofillSupportLevel.FillAndSave -> getString(R.string.oreo_autofill_fill_and_save_support) + } + "$appLabel: $supportDescription" + } + setView(layout) + } else { + setView(R.layout.autofill_instructions) + } + setPositiveButton(R.string.dialog_ok) { _, _ -> + val intent = + if (enableOreoAutofill && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE).apply { + data = Uri.parse("package:${BuildConfig.APPLICATION_ID}") + } + } else { + Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) + } + startActivity(intent) + } + setNegativeButton(R.string.dialog_cancel, null) + setOnDismissListener { + val isEnabled = + if (enableOreoAutofill && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + callingActivity.isAutofillServiceEnabled + } else { + callingActivity.isAccessibilityServiceEnabled + } + autoFillEnablePreference?.isChecked = isEnabled + autofillDependencies.forEach { it?.isVisible = isEnabled } + } + show() + } + } + } + override fun onResume() { super.onResume() - val isEnabled = callingActivity.isServiceEnabled - autoFillEnablePreference?.isChecked = isEnabled - autofillDependencies.forEach { it?.isVisible = isEnabled } + updateAutofillSettings() } } @@ -487,16 +539,26 @@ class UserPreference : AppCompatActivity() { } } - // Returns whether the autofill service is enabled - private val isServiceEnabled: Boolean + private val isAccessibilityServiceEnabled: Boolean get() { - val am = this - .getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager + val am = getSystemService(AccessibilityManager::class.java) val runningServices = am - .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC) + .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC) return runningServices - .map { it.id.substringBefore("/") } - .any { it == BuildConfig.APPLICATION_ID } + .map { it.id.substringBefore("/") } + .any { it == BuildConfig.APPLICATION_ID } + } + + private val isAutofillServiceSupported: Boolean + get() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false + return autofillManager?.isAutofillSupported != null + } + + private val isAutofillServiceEnabled: Boolean + get() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false + return autofillManager?.hasEnabledAutofillServices() == true } override fun onActivityResult( |
