improvement: Add a note for Chrome users to enable native autofill #680

This commit is contained in:
Artem Chepurnoy 2024-10-28 15:03:02 +02:00
parent 2c4456d5cf
commit fdee7778ad
No known key found for this signature in database
GPG Key ID: FAC37D0CF674043E
4 changed files with 92 additions and 6 deletions

View File

@ -35,6 +35,7 @@ import com.artemchep.keyguard.res.*
import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart
@ -316,7 +317,7 @@ fun produceAppPickerState(
} }
} }
val itemsFlow = getAppsFlow(context.context) val itemsFlow = flowOfInstalledApps(context.context)
.combine(sortSink) { items, sort -> .combine(sortSink) { items, sort ->
val comparator = Comparator<AppInfo> { a, b -> val comparator = Comparator<AppInfo> { a, b ->
val result = sort.comparator.compare(a, b) val result = sort.comparator.compare(a, b)
@ -370,7 +371,17 @@ fun produceAppPickerState(
} }
} }
private fun getAppsFlow( fun flowOfInstalledAppsAnyOf(
context: Context,
packageNames: Iterable<String>,
) = flowOfInstalledApps(context)
.map { installedApps ->
installedApps
.any { app -> app.packageName in packageNames }
}
.distinctUntilChanged()
fun flowOfInstalledApps(
context: Context, context: Context,
) = broadcastFlow( ) = broadcastFlow(
context = context, context = context,

View File

@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AutoAwesome import androidx.compose.material.icons.outlined.AutoAwesome
import androidx.compose.material.icons.outlined.OpenInBrowser
import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
@ -23,6 +24,10 @@ import arrow.core.partially1
import com.artemchep.keyguard.android.closestActivityOrNull import com.artemchep.keyguard.android.closestActivityOrNull
import com.artemchep.keyguard.common.service.autofill.AutofillService import com.artemchep.keyguard.common.service.autofill.AutofillService
import com.artemchep.keyguard.common.service.autofill.AutofillServiceStatus import com.artemchep.keyguard.common.service.autofill.AutofillServiceStatus
import com.artemchep.keyguard.feature.apppicker.flowOfInstalledAppsAnyOf
import com.artemchep.keyguard.feature.navigation.LocalNavigationController
import com.artemchep.keyguard.feature.navigation.NavigationIntent
import com.artemchep.keyguard.platform.LeContext
import com.artemchep.keyguard.res.Res import com.artemchep.keyguard.res.Res
import com.artemchep.keyguard.res.* import com.artemchep.keyguard.res.*
import com.artemchep.keyguard.ui.ExpandedIfNotEmpty import com.artemchep.keyguard.ui.ExpandedIfNotEmpty
@ -31,8 +36,9 @@ import com.artemchep.keyguard.ui.FlatSimpleNote
import com.artemchep.keyguard.ui.SimpleNote import com.artemchep.keyguard.ui.SimpleNote
import com.artemchep.keyguard.ui.icons.icon import com.artemchep.keyguard.ui.icons.icon
import com.artemchep.keyguard.ui.theme.Dimens import com.artemchep.keyguard.ui.theme.Dimens
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import kotlinx.coroutines.flow.map
import org.kodein.di.DirectDI import org.kodein.di.DirectDI
import org.kodein.di.instance import org.kodein.di.instance
import java.io.BufferedReader import java.io.BufferedReader
@ -43,13 +49,18 @@ actual fun settingAutofillProvider(
directDI: DirectDI, directDI: DirectDI,
): SettingComponent = settingAutofillProvider( ): SettingComponent = settingAutofillProvider(
autofillService = directDI.instance(), autofillService = directDI.instance(),
appContext = directDI.instance(),
) )
fun settingAutofillProvider( fun settingAutofillProvider(
autofillService: AutofillService, autofillService: AutofillService,
): SettingComponent = autofillService appContext: LeContext,
.status() ): SettingComponent =
.map { status -> combine(
autofillService
.status(),
flowOfIsChromiumInstalled(context = appContext.context),
) { status, isChromeInstalled ->
val platformWarning = when { val platformWarning = when {
isMiui() -> AutofillPlatformWarning.Miui isMiui() -> AutofillPlatformWarning.Miui
else -> null else -> null
@ -88,6 +99,12 @@ fun settingAutofillProvider(
}, },
platformWarning = platformWarning, platformWarning = platformWarning,
) )
ExpandedIfNotEmpty(
valueOrNull = isChromeInstalled.takeIf { it },
) {
SettingAutofillChromeNativeAutofillWarning()
}
} }
} }
@ -168,6 +185,37 @@ private fun SettingAutofillPlatformWarningMiui(
) )
} }
@Composable
private fun SettingAutofillChromeNativeAutofillWarning(
) {
FlatSimpleNote(
modifier = Modifier
.padding(
top = 8.dp,
bottom = 8.dp,
start = Dimens.horizontalPadding * 1 + 24.dp,
),
type = SimpleNote.Type.INFO,
title = stringResource(Res.string.pref_item_autofill_service_chrome_native_autofill_title),
text = stringResource(Res.string.pref_item_autofill_service_chrome_native_autofill_text),
trailing = {
val navController by rememberUpdatedState(LocalNavigationController.current)
IconButton(
onClick = {
val url = "https://android-developers.googleblog.com/2024/10/chrome-3p-autofill-services.html"
val intent = NavigationIntent.NavigateToBrowser(url)
navController.queue(intent)
},
) {
Icon(
imageVector = Icons.Outlined.OpenInBrowser,
contentDescription = null,
)
}
},
)
}
private sealed interface AutofillPlatformWarning { private sealed interface AutofillPlatformWarning {
data object Miui : AutofillPlatformWarning { data object Miui : AutofillPlatformWarning {
fun launchPermissionSettings( fun launchPermissionSettings(
@ -196,6 +244,24 @@ private sealed interface AutofillPlatformWarning {
} }
} }
private fun flowOfIsChromiumInstalled(
context: Context,
): Flow<Boolean> {
val chromiumPackageNames = setOf(
"com.android.chrome",
"com.chrome.beta",
"com.chrome.canary",
"com.chrome.dev",
"com.google.android.apps.chrome",
"com.google.android.apps.chrome_dev",
"org.chromium.chrome",
)
return flowOfInstalledAppsAnyOf(
context,
packageNames = chromiumPackageNames,
)
}
private fun isMiui(): Boolean { private fun isMiui(): Boolean {
return !getSystemProperty("ro.miui.ui.version.name").isNullOrBlank() return !getSystemProperty("ro.miui.ui.version.name").isNullOrBlank()
} }

View File

@ -1075,6 +1075,10 @@
<string name="pref_item_autofill_service_title">Autofill service</string> <string name="pref_item_autofill_service_title">Autofill service</string>
<string name="pref_item_autofill_service_text">Use the Android Autofill Framework to assist in filling login information into other apps on the device</string> <string name="pref_item_autofill_service_text">Use the Android Autofill Framework to assist in filling login information into other apps on the device</string>
<string name="pref_item_autofill_service_xiaomi_permission_note">Some Xiaomi devices require you to manually allow the "Display pop-up windows while running in the background" permission. Please open the settings and verify that it is granted.</string> <string name="pref_item_autofill_service_xiaomi_permission_note">Some Xiaomi devices require you to manually allow the "Display pop-up windows while running in the background" permission. Please open the settings and verify that it is granted.</string>
<string name="pref_item_autofill_service_chrome_native_autofill_title">Chrome to support third-party autofill services natively</string>
<string name="pref_item_autofill_service_chrome_native_autofill_text">1. Open Chrome's Settings and tap Autofill Services
2. Choose Autofill using another service
3. Confirm and restart Chrome</string>
<string name="pref_item_autofill_auto_copy_otp_title">Auto-copy one-time passwords</string> <string name="pref_item_autofill_auto_copy_otp_title">Auto-copy one-time passwords</string>
<string name="pref_item_autofill_auto_copy_otp_text">When filling a login information, automatically copy one-time passwords</string> <string name="pref_item_autofill_auto_copy_otp_text">When filling a login information, automatically copy one-time passwords</string>
<string name="pref_item_autofill_inline_suggestions_title">Inline suggestions</string> <string name="pref_item_autofill_inline_suggestions_title">Inline suggestions</string>

View File

@ -1,5 +1,6 @@
package com.artemchep.keyguard.ui package com.artemchep.keyguard.ui
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Check import androidx.compose.material.icons.outlined.Check
@ -58,6 +59,7 @@ fun FlatSimpleNote(
text: String? = null, text: String? = null,
leading: (@Composable RowScope.() -> Unit)? = null, leading: (@Composable RowScope.() -> Unit)? = null,
trailing: (@Composable RowScope.() -> Unit)? = null, trailing: (@Composable RowScope.() -> Unit)? = null,
content: (@Composable ColumnScope.() -> Unit)? = null,
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
enabled: Boolean = true, enabled: Boolean = true,
) { ) {
@ -123,6 +125,9 @@ fun FlatSimpleNote(
color = textColor, color = textColor,
) )
} }
if (content != null) {
content()
}
}, },
trailing = trailing, trailing = trailing,
onClick = onClick, onClick = onClick,