/* * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. * SPDX-License-Identifier: GPL-3.0-only */ package dev.msfjarvis.aps.ui.settings import android.annotation.SuppressLint import android.content.Intent import android.net.Uri import android.os.Build import android.provider.Settings import androidx.annotation.RequiresApi import androidx.appcompat.widget.AppCompatTextView import androidx.fragment.app.FragmentActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import com.github.androidpasswordstore.autofillparser.BrowserAutofillSupportLevel import com.github.androidpasswordstore.autofillparser.getInstalledBrowsersWithAutofillSupportLevel import com.google.android.material.dialog.MaterialAlertDialogBuilder import de.Maxr1998.modernpreferences.PreferenceScreen import de.Maxr1998.modernpreferences.helpers.editText import de.Maxr1998.modernpreferences.helpers.onClick import de.Maxr1998.modernpreferences.helpers.singleChoice import de.Maxr1998.modernpreferences.helpers.switch import de.Maxr1998.modernpreferences.preferences.SwitchPreference import de.Maxr1998.modernpreferences.preferences.choice.SelectionItem import dev.msfjarvis.aps.BuildConfig import dev.msfjarvis.aps.R import dev.msfjarvis.aps.util.autofill.DirectoryStructure import dev.msfjarvis.aps.util.extensions.autofillManager import dev.msfjarvis.aps.util.settings.PreferenceKeys class AutofillSettings(private val activity: FragmentActivity) : SettingsProvider { private val isAutofillServiceEnabled: Boolean get() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false return activity.autofillManager?.hasEnabledAutofillServices() == true } @RequiresApi(Build.VERSION_CODES.O) private fun showAutofillDialog(pref: SwitchPreference) { val observer = LifecycleEventObserver { _, event -> when (event) { Lifecycle.Event.ON_RESUME -> { pref.checked = isAutofillServiceEnabled } else -> {} } } MaterialAlertDialogBuilder(activity).run { setTitle(R.string.pref_autofill_enable_title) @SuppressLint("InflateParams") val layout = activity.layoutInflater.inflate(R.layout.oreo_autofill_instructions, null) val supportedBrowsersTextView = layout.findViewById(R.id.supportedBrowsers) supportedBrowsersTextView.text = getInstalledBrowsersWithAutofillSupportLevel(context).joinToString(separator = "\n") { val appLabel = it.first val supportDescription = when (it.second) { BrowserAutofillSupportLevel.None -> activity.getString(R.string.oreo_autofill_no_support) BrowserAutofillSupportLevel.FlakyFill -> activity.getString(R.string.oreo_autofill_flaky_fill_support) BrowserAutofillSupportLevel.PasswordFill -> activity.getString(R.string.oreo_autofill_password_fill_support) BrowserAutofillSupportLevel.PasswordFillAndSaveIfNoAccessibility -> activity.getString( R.string.oreo_autofill_password_fill_and_conditional_save_support ) BrowserAutofillSupportLevel.GeneralFill -> activity.getString(R.string.oreo_autofill_general_fill_support) BrowserAutofillSupportLevel.GeneralFillAndSave -> activity.getString(R.string.oreo_autofill_general_fill_and_save_support) } "$appLabel: $supportDescription" } setView(layout) setPositiveButton(R.string.dialog_ok) { _, _ -> val intent = Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE).apply { data = Uri.parse("package:${BuildConfig.APPLICATION_ID}") } activity.startActivity(intent) } setNegativeButton(R.string.dialog_cancel, null) setOnDismissListener { pref.checked = isAutofillServiceEnabled } activity.lifecycle.addObserver(observer) show() } } override fun provideSettings(builder: PreferenceScreen.Builder) { builder.apply { switch(PreferenceKeys.AUTOFILL_ENABLE) { titleRes = R.string.pref_autofill_enable_title visible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O defaultValue = isAutofillServiceEnabled onClick { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return@onClick true if (isAutofillServiceEnabled) { activity.autofillManager?.disableAutofillServices() } else { showAutofillDialog(this) } false } } val values = activity.resources.getStringArray(R.array.oreo_autofill_directory_structure_values) val titles = activity.resources.getStringArray(R.array.oreo_autofill_directory_structure_entries) val items = values.zip(titles).map { SelectionItem(it.first, it.second, null) } singleChoice(PreferenceKeys.OREO_AUTOFILL_DIRECTORY_STRUCTURE, items) { initialSelection = DirectoryStructure.DEFAULT.value dependency = PreferenceKeys.AUTOFILL_ENABLE titleRes = R.string.oreo_autofill_preference_directory_structure } editText(PreferenceKeys.OREO_AUTOFILL_DEFAULT_USERNAME) { dependency = PreferenceKeys.AUTOFILL_ENABLE titleRes = R.string.preference_default_username_title summaryProvider = { activity.getString(R.string.preference_default_username_summary) } } editText(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES) { dependency = PreferenceKeys.AUTOFILL_ENABLE titleRes = R.string.preference_custom_public_suffixes_title summaryProvider = { activity.getString(R.string.preference_custom_public_suffixes_summary) } textInputHintRes = R.string.preference_custom_public_suffixes_hint } } } }