improvement: Add a note for Chrome users to enable native autofill #680
This commit is contained in:
parent
2c4456d5cf
commit
fdee7778ad
|
@ -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,
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue