PM-18314 & PM-18450 Check for Chrome browser 3rd party autofill. (#4752)

This commit is contained in:
Dave Severns
2025-02-20 15:59:39 -05:00
committed by GitHub
parent 3fb7904a36
commit b7464b87d9
17 changed files with 427 additions and 3 deletions

View File

@@ -15,7 +15,7 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_USER_DICTIONARY"/>
<!-- Protect access to AuthenticatorBridgeService using this custom permission.
Note that each build type uses a different value for knownCerts.
@@ -320,6 +320,11 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
</intent>
<!-- To Query Chrome Beta: -->
<package android:name="com.chrome.beta" />
<!-- To Query Chrome Stable: -->
<package android:name="com.android.chrome" />
</queries>
</manifest>

View File

@@ -8,6 +8,9 @@ import androidx.lifecycle.lifecycleScope
import com.x8bit.bitwarden.data.autofill.manager.AutofillActivityManager
import com.x8bit.bitwarden.data.autofill.manager.AutofillActivityManagerImpl
import com.x8bit.bitwarden.data.autofill.manager.AutofillEnabledManager
import com.x8bit.bitwarden.data.autofill.manager.chrome.ChromeThirdPartyAutofillEnabledManager
import com.x8bit.bitwarden.data.autofill.manager.chrome.ChromeThirdPartyAutofillManager
import com.x8bit.bitwarden.data.autofill.manager.chrome.ChromeThirdPartyAutofillManagerImpl
import com.x8bit.bitwarden.data.platform.manager.AppStateManager
import dagger.Module
import dagger.Provides
@@ -23,19 +26,32 @@ import dagger.hilt.android.scopes.ActivityScoped
@InstallIn(ActivityComponent::class)
object ActivityAutofillModule {
@ActivityScoped
@ActivityScopedManager
@Provides
fun provideActivityScopedChromeThirdPartyAutofillManager(
activity: Activity,
): ChromeThirdPartyAutofillManager = ChromeThirdPartyAutofillManagerImpl(
context = activity.baseContext,
)
@ActivityScoped
@Provides
fun provideAutofillActivityManager(
@ActivityScopedManager autofillManager: AutofillManager,
@ActivityScopedManager chromeThirdPartyAutofillManager: ChromeThirdPartyAutofillManager,
appStateManager: AppStateManager,
autofillEnabledManager: AutofillEnabledManager,
lifecycleScope: LifecycleCoroutineScope,
chromeThirdPartyAutofillEnabledManager: ChromeThirdPartyAutofillEnabledManager,
): AutofillActivityManager =
AutofillActivityManagerImpl(
autofillManager = autofillManager,
chromeThirdPartyAutofillManager = chromeThirdPartyAutofillManager,
appStateManager = appStateManager,
autofillEnabledManager = autofillEnabledManager,
lifecycleScope = lifecycleScope,
chromeThirdPartyAutofillEnabledManager = chromeThirdPartyAutofillEnabledManager,
)
/**

View File

@@ -15,12 +15,15 @@ import com.x8bit.bitwarden.data.autofill.manager.AutofillEnabledManager
import com.x8bit.bitwarden.data.autofill.manager.AutofillEnabledManagerImpl
import com.x8bit.bitwarden.data.autofill.manager.AutofillTotpManager
import com.x8bit.bitwarden.data.autofill.manager.AutofillTotpManagerImpl
import com.x8bit.bitwarden.data.autofill.manager.chrome.ChromeThirdPartyAutofillEnabledManager
import com.x8bit.bitwarden.data.autofill.manager.chrome.ChromeThirdPartyAutofillEnabledManagerImpl
import com.x8bit.bitwarden.data.autofill.parser.AutofillParser
import com.x8bit.bitwarden.data.autofill.parser.AutofillParserImpl
import com.x8bit.bitwarden.data.autofill.processor.AutofillProcessor
import com.x8bit.bitwarden.data.autofill.processor.AutofillProcessorImpl
import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProvider
import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProviderImpl
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
import com.x8bit.bitwarden.data.platform.manager.ciphermatching.CipherMatchingManager
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
@@ -54,6 +57,15 @@ object AutofillModule {
fun providesAutofillEnabledManager(): AutofillEnabledManager =
AutofillEnabledManagerImpl()
@Singleton
@Provides
fun providesChromeAutofillEnabledManager(
featureFlagManager: FeatureFlagManager,
): ChromeThirdPartyAutofillEnabledManager =
ChromeThirdPartyAutofillEnabledManagerImpl(
featureFlagManager = featureFlagManager,
)
@Singleton
@Provides
fun provideAutofillCompletionManager(

View File

@@ -2,6 +2,9 @@ package com.x8bit.bitwarden.data.autofill.manager
import android.view.autofill.AutofillManager
import androidx.lifecycle.LifecycleCoroutineScope
import com.x8bit.bitwarden.data.autofill.manager.chrome.ChromeThirdPartyAutofillEnabledManager
import com.x8bit.bitwarden.data.autofill.manager.chrome.ChromeThirdPartyAutofillManager
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeThirdPartyAutofillStatus
import com.x8bit.bitwarden.data.platform.manager.AppStateManager
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -11,19 +14,31 @@ import kotlinx.coroutines.flow.onEach
*/
class AutofillActivityManagerImpl(
private val autofillManager: AutofillManager,
private val autofillEnabledManager: AutofillEnabledManager,
private val chromeThirdPartyAutofillManager: ChromeThirdPartyAutofillManager,
autofillEnabledManager: AutofillEnabledManager,
appStateManager: AppStateManager,
lifecycleScope: LifecycleCoroutineScope,
chromeThirdPartyAutofillEnabledManager: ChromeThirdPartyAutofillEnabledManager,
) : AutofillActivityManager {
private val isAutofillEnabledAndSupported: Boolean
get() = autofillManager.isEnabled &&
autofillManager.hasEnabledAutofillServices() &&
autofillManager.isAutofillSupported
private val chromeAutofillStatus: ChromeThirdPartyAutofillStatus
get() = ChromeThirdPartyAutofillStatus(
stableStatusData = chromeThirdPartyAutofillManager.stableChromeAutofillStatus,
betaChannelStatusData = chromeThirdPartyAutofillManager.betaChromeAutofillStatus,
)
init {
appStateManager
.appForegroundStateFlow
.onEach { autofillEnabledManager.isAutofillEnabled = isAutofillEnabledAndSupported }
.onEach {
autofillEnabledManager.isAutofillEnabled = isAutofillEnabledAndSupported
chromeThirdPartyAutofillEnabledManager.chromeThirdPartyAutofillStatus =
chromeAutofillStatus
}
.launchIn(lifecycleScope)
}
}

View File

@@ -0,0 +1,22 @@
package com.x8bit.bitwarden.data.autofill.manager.chrome
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeThirdPartyAutofillStatus
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
/**
* Manager which provides whether specific Chrome versions have third party autofill available and
* enabled.
*/
interface ChromeThirdPartyAutofillEnabledManager {
/**
* Combined status for all concerned Chrome versions.
*/
var chromeThirdPartyAutofillStatus: ChromeThirdPartyAutofillStatus
/**
* An observable [StateFlow] of the combined third party autofill status of all concerned
* chrome versions.
*/
val chromeThirdPartyAutofillStatusFlow: Flow<ChromeThirdPartyAutofillStatus>
}

View File

@@ -0,0 +1,52 @@
package com.x8bit.bitwarden.data.autofill.manager.chrome
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeThirdPartyAutoFillData
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeThirdPartyAutofillStatus
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.update
/**
* Default implementation of [ChromeThirdPartyAutofillEnabledManager].
*/
class ChromeThirdPartyAutofillEnabledManagerImpl(
private val featureFlagManager: FeatureFlagManager,
) : ChromeThirdPartyAutofillEnabledManager {
override var chromeThirdPartyAutofillStatus: ChromeThirdPartyAutofillStatus = DEFAULT_STATUS
set(value) {
field = value
mutableChromeThirdPartyAutofillStatusStateFlow.update {
value
}
}
private val mutableChromeThirdPartyAutofillStatusStateFlow = MutableStateFlow(
chromeThirdPartyAutofillStatus,
)
override val chromeThirdPartyAutofillStatusFlow: Flow<ChromeThirdPartyAutofillStatus>
get() = mutableChromeThirdPartyAutofillStatusStateFlow
.combine(
featureFlagManager.getFeatureFlagFlow(FlagKey.ChromeAutofill),
) { data, enabled ->
if (enabled) {
data
} else {
DEFAULT_STATUS
}
}
}
private val DEFAULT_STATUS = ChromeThirdPartyAutofillStatus(
ChromeThirdPartyAutoFillData(
isAvailable = false,
isThirdPartyEnabled = false,
),
ChromeThirdPartyAutoFillData(
isAvailable = false,
isThirdPartyEnabled = false,
),
)

View File

@@ -0,0 +1,20 @@
package com.x8bit.bitwarden.data.autofill.manager.chrome
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeThirdPartyAutoFillData
/**
* Manager class used to determine if a device has installed versions of Chrome (either the
* stable release or beta channel) which support and require opt in to third party autofill.
*/
interface ChromeThirdPartyAutofillManager {
/**
* The data representing the status of the stable chrome version
*/
val stableChromeAutofillStatus: ChromeThirdPartyAutoFillData
/**
* The data representing the status of the beta chrome version
*/
val betaChromeAutofillStatus: ChromeThirdPartyAutoFillData
}

View File

@@ -0,0 +1,62 @@
package com.x8bit.bitwarden.data.autofill.manager.chrome
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeReleaseChannel
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeThirdPartyAutoFillData
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
private const val CONTENT_PROVIDER_NAME = ".AutofillThirdPartyModeContentProvider"
private const val THIRD_PARTY_MODE_COLUMN = "autofill_third_party_state"
private const val THIRD_PARTY_MODE_ACTIONS_URI_PATH = "autofill_third_party_mode"
/**
* Default implementation of the [ChromeThirdPartyAutofillManager] which uses a
* [ContentResolver] to determine if the installed Chrome packages support and enable
* third party autofill services.
*
* Based off of [this blog post](https://android-developers.googleblog.com/2025/02/chrome-3p-autofill-services-update.html)
*/
@OmitFromCoverage
class ChromeThirdPartyAutofillManagerImpl(
private val context: Context,
) : ChromeThirdPartyAutofillManager {
override val stableChromeAutofillStatus: ChromeThirdPartyAutoFillData
get() = getThirdPartyAutoFillStatusForChannel(ChromeReleaseChannel.STABLE)
override val betaChromeAutofillStatus: ChromeThirdPartyAutoFillData
get() = getThirdPartyAutoFillStatusForChannel(ChromeReleaseChannel.BETA)
private fun getThirdPartyAutoFillStatusForChannel(
releaseChannel: ChromeReleaseChannel,
): ChromeThirdPartyAutoFillData {
val uri = Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(releaseChannel.packageName + CONTENT_PROVIDER_NAME)
.path(THIRD_PARTY_MODE_ACTIONS_URI_PATH)
.build()
val cursor = context
.contentResolver
.query(
/* uri = */ uri,
/* projection = */ arrayOf(THIRD_PARTY_MODE_COLUMN),
/* selection = */ null,
/* selectionArgs = */ null,
/* sortOrder = */ null,
)
var thirdPartyEnabled = false
val isThirdPartyAvailable = cursor
?.let {
it.moveToFirst()
val columnIndex = it.getColumnIndex(THIRD_PARTY_MODE_COLUMN)
thirdPartyEnabled = it.getInt(columnIndex) != 0
it.close()
true
}
?: false
return ChromeThirdPartyAutoFillData(
isAvailable = isThirdPartyAvailable,
isThirdPartyEnabled = thirdPartyEnabled,
)
}
}

View File

@@ -0,0 +1,14 @@
package com.x8bit.bitwarden.data.autofill.model.chrome
private const val BETA_CHANNEL_PACKAGE = "com.chrome.beta"
private const val CHROME_CHANNEL_PACKAGE = "com.android.chrome"
/**
* Enumerated values of each version of Chrome supported for third party autofill checks.
*
* @property packageName the package name of the release channel for the Chrome version.
*/
enum class ChromeReleaseChannel(val packageName: String) {
STABLE(CHROME_CHANNEL_PACKAGE),
BETA(BETA_CHANNEL_PACKAGE),
}

View File

@@ -0,0 +1,17 @@
package com.x8bit.bitwarden.data.autofill.model.chrome
/**
* Relevant data relating to the third party autofill status of a version of the Chrome browser app.
*/
data class ChromeThirdPartyAutoFillData(
val isAvailable: Boolean,
val isThirdPartyEnabled: Boolean,
)
/**
* The overall status for all relevant release channels of Chrome.
*/
data class ChromeThirdPartyAutofillStatus(
val stableStatusData: ChromeThirdPartyAutoFillData,
val betaChannelStatusData: ChromeThirdPartyAutoFillData,
)

View File

@@ -44,6 +44,7 @@ sealed class FlagKey<out T : Any> {
SingleTapPasskeyAuthentication,
AnonAddySelfHostAlias,
SimpleLoginSelfHostAlias,
ChromeAutofill,
)
}
}
@@ -222,6 +223,16 @@ sealed class FlagKey<out T : Any> {
override val isRemotelyConfigured: Boolean = true
}
/**
* Data object holding the feature flag key to enable the checking for Chrome's third party
* autofill.
*/
data object ChromeAutofill : FlagKey<Boolean>() {
override val keyName: String = "enable-pm-chrome-autofill"
override val defaultValue: Boolean = false
override val isRemotelyConfigured: Boolean = true
}
//region Dummy keys for testing
/**
* Data object holding the key for a [Boolean] flag to be used in tests.

View File

@@ -43,6 +43,7 @@ fun <T : Any> FlagKey<T>.ListItemContent(
FlagKey.SingleTapPasskeyAuthentication,
FlagKey.AnonAddySelfHostAlias,
FlagKey.SimpleLoginSelfHostAlias,
FlagKey.ChromeAutofill,
-> BooleanFlagItem(
label = flagKey.getDisplayLabel(),
key = flagKey as FlagKey<Boolean>,
@@ -101,4 +102,5 @@ private fun <T : Any> FlagKey<T>.getDisplayLabel(): String = when (this) {
stringResource(R.string.single_tap_passkey_authentication)
FlagKey.AnonAddySelfHostAlias -> stringResource(R.string.anon_addy_self_hosted_aliases)
FlagKey.SimpleLoginSelfHostAlias -> stringResource(R.string.simple_login_self_hosted_aliases)
FlagKey.ChromeAutofill -> stringResource(R.string.enable_chrome_autofill)
}

View File

@@ -28,5 +28,6 @@
<string name="reset_coach_mark_tour_status">Reset all coach mark tours</string>
<string name="anon_addy_self_hosted_aliases">AnonAddy self-hosted aliases</string>
<string name="simple_login_self_hosted_aliases">SimpleLogin self-hosted aliases</string>
<string name="enable_chrome_autofill">Enable chrome autofill</string>
<!-- /Debug Menu -->
</resources>

View File

@@ -3,8 +3,15 @@ package com.x8bit.bitwarden.data.autofill.manager
import android.view.autofill.AutofillManager
import androidx.lifecycle.LifecycleCoroutineScope
import app.cash.turbine.test
import com.x8bit.bitwarden.data.autofill.manager.chrome.ChromeThirdPartyAutofillEnabledManager
import com.x8bit.bitwarden.data.autofill.manager.chrome.ChromeThirdPartyAutofillEnabledManagerImpl
import com.x8bit.bitwarden.data.autofill.manager.chrome.ChromeThirdPartyAutofillManager
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeThirdPartyAutoFillData
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeThirdPartyAutofillStatus
import com.x8bit.bitwarden.data.platform.manager.AppStateManager
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.model.AppForegroundState
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
@@ -13,6 +20,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
@@ -34,6 +42,16 @@ class AutofillActivityManagerTest {
private val lifecycleScope = mockk<LifecycleCoroutineScope> {
every { coroutineContext } returns UnconfinedTestDispatcher()
}
private val chromeThirdPartyAutofillManager = mockk<ChromeThirdPartyAutofillManager> {
every { stableChromeAutofillStatus } returns DEFAULT_CHROME_AUTOFILL_DATA
every { betaChromeAutofillStatus } returns DEFAULT_CHROME_AUTOFILL_DATA
}
private val featureFlagManager = mockk<FeatureFlagManager> {
every { getFeatureFlagFlow(FlagKey.ChromeAutofill) } returns MutableStateFlow(true)
}
private val chromeThirdPartyAutofillEnabledManager: ChromeThirdPartyAutofillEnabledManager =
ChromeThirdPartyAutofillEnabledManagerImpl(featureFlagManager = featureFlagManager)
// We will construct an instance here just to hook the various dependencies together internally
@Suppress("unused")
@@ -42,6 +60,8 @@ class AutofillActivityManagerTest {
appStateManager = appStateManager,
autofillEnabledManager = autofillEnabledManager,
lifecycleScope = lifecycleScope,
chromeThirdPartyAutofillManager = chromeThirdPartyAutofillManager,
chromeThirdPartyAutofillEnabledManager = chromeThirdPartyAutofillEnabledManager,
)
private var isAutofillEnabledAndSupported = false
@@ -70,4 +90,37 @@ class AutofillActivityManagerTest {
assertFalse(awaitItem())
}
}
@Suppress("MaxLineLength")
@Test
fun `changes in app foreground status should update the ChromeThirdPartyAutofillEnabledManager as necessary`() =
runTest {
val updatedBetaState =
DEFAULT_CHROME_AUTOFILL_DATA.copy(isAvailable = true)
chromeThirdPartyAutofillEnabledManager.chromeThirdPartyAutofillStatusFlow.test {
assertEquals(
DEFAULT_EXPECTED_AUTOFILL_STATUS,
awaitItem(),
)
every { chromeThirdPartyAutofillManager.betaChromeAutofillStatus } returns
updatedBetaState
mutableAppForegroundStateFlow.value = AppForegroundState.FOREGROUNDED
assertEquals(
DEFAULT_EXPECTED_AUTOFILL_STATUS.copy(
betaChannelStatusData = updatedBetaState,
),
awaitItem(),
)
}
}
}
private val DEFAULT_CHROME_AUTOFILL_DATA = ChromeThirdPartyAutoFillData(
isAvailable = false,
isThirdPartyEnabled = false,
)
private val DEFAULT_EXPECTED_AUTOFILL_STATUS = ChromeThirdPartyAutofillStatus(
stableStatusData = DEFAULT_CHROME_AUTOFILL_DATA,
betaChannelStatusData = DEFAULT_CHROME_AUTOFILL_DATA,
)

View File

@@ -0,0 +1,114 @@
package com.x8bit.bitwarden.data.autofill.manager.chrome
import app.cash.turbine.test
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeThirdPartyAutoFillData
import com.x8bit.bitwarden.data.autofill.model.chrome.ChromeThirdPartyAutofillStatus
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class ChromeThirdPartyAutofillEnabledManagerTest {
private val mutableChromeAutofillFeatureFlow = MutableStateFlow(true)
private val featureFlagManager = mockk<FeatureFlagManager> {
every {
getFeatureFlagFlow(FlagKey.ChromeAutofill)
} returns mutableChromeAutofillFeatureFlow
}
private val chromeThirdPartyAutofillEnabledManager =
ChromeThirdPartyAutofillEnabledManagerImpl(featureFlagManager = featureFlagManager)
@Suppress("MaxLineLength")
@Test
fun `chromeThirdPartyAutofillStatusStateFlow should emit whenever isAutofillEnabled is set to a unique value`() =
runTest {
chromeThirdPartyAutofillEnabledManager.chromeThirdPartyAutofillStatusFlow.test {
assertEquals(
DEFAULT_EXPECTED_AUTOFILL_STATUS,
awaitItem(),
)
val firstExpectedStatusChange = DEFAULT_EXPECTED_AUTOFILL_STATUS.copy(
stableStatusData = DEFAULT_CHROME_AUTOFILL_DATA.copy(isAvailable = true),
)
chromeThirdPartyAutofillEnabledManager.chromeThirdPartyAutofillStatus =
firstExpectedStatusChange
assertEquals(
firstExpectedStatusChange,
awaitItem(),
)
chromeThirdPartyAutofillEnabledManager.chromeThirdPartyAutofillStatus =
firstExpectedStatusChange.copy()
expectNoEvents()
val secondExpectedStatusChange = firstExpectedStatusChange
.copy(
betaChannelStatusData = DEFAULT_CHROME_AUTOFILL_DATA.copy(
isThirdPartyEnabled = true,
),
)
chromeThirdPartyAutofillEnabledManager.chromeThirdPartyAutofillStatus =
secondExpectedStatusChange
assertEquals(
secondExpectedStatusChange,
awaitItem(),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `chromeThirdPartyAutofillStatusStateFlow should not emit whenever isAutofillEnabled is set to a unique value if the feature is off`() =
runTest {
mutableChromeAutofillFeatureFlow.update { false }
chromeThirdPartyAutofillEnabledManager.chromeThirdPartyAutofillStatusFlow.test {
assertEquals(
DEFAULT_EXPECTED_AUTOFILL_STATUS,
awaitItem(),
)
val firstExpectedStatusChange = DEFAULT_EXPECTED_AUTOFILL_STATUS.copy(
stableStatusData = DEFAULT_CHROME_AUTOFILL_DATA.copy(isAvailable = true),
)
chromeThirdPartyAutofillEnabledManager.chromeThirdPartyAutofillStatus =
firstExpectedStatusChange
assertEquals(
DEFAULT_EXPECTED_AUTOFILL_STATUS,
awaitItem(),
)
chromeThirdPartyAutofillEnabledManager.chromeThirdPartyAutofillStatus =
firstExpectedStatusChange.copy()
expectNoEvents()
val secondExpectedStatusChange = firstExpectedStatusChange
.copy(
betaChannelStatusData = DEFAULT_CHROME_AUTOFILL_DATA.copy(
isThirdPartyEnabled = true,
),
)
chromeThirdPartyAutofillEnabledManager.chromeThirdPartyAutofillStatus =
secondExpectedStatusChange
assertEquals(
DEFAULT_EXPECTED_AUTOFILL_STATUS,
awaitItem(),
)
}
}
}
private val DEFAULT_CHROME_AUTOFILL_DATA = ChromeThirdPartyAutoFillData(
isAvailable = false,
isThirdPartyEnabled = false,
)
private val DEFAULT_EXPECTED_AUTOFILL_STATUS = ChromeThirdPartyAutofillStatus(
stableStatusData = DEFAULT_CHROME_AUTOFILL_DATA,
betaChannelStatusData = DEFAULT_CHROME_AUTOFILL_DATA,
)

View File

@@ -81,6 +81,10 @@ class FlagKeyTest {
FlagKey.AnonAddySelfHostAlias.keyName,
"anon-addy-self-host-alias",
)
assertEquals(
FlagKey.ChromeAutofill.keyName,
"enable-pm-chrome-autofill",
)
}
@Test
@@ -104,6 +108,7 @@ class FlagKeyTest {
FlagKey.AnonAddySelfHostAlias,
FlagKey.SimpleLoginSelfHostAlias,
FlagKey.CipherKeyEncryption,
FlagKey.ChromeAutofill,
).all {
!it.defaultValue
},
@@ -132,6 +137,7 @@ class FlagKeyTest {
FlagKey.MutualTls,
FlagKey.AnonAddySelfHostAlias,
FlagKey.SimpleLoginSelfHostAlias,
FlagKey.ChromeAutofill,
).all {
it.isRemotelyConfigured
},

View File

@@ -136,6 +136,7 @@ private val DEFAULT_MAP_VALUE: Map<FlagKey<Any>, Any> = mapOf(
FlagKey.SingleTapPasskeyAuthentication to true,
FlagKey.AnonAddySelfHostAlias to true,
FlagKey.SimpleLoginSelfHostAlias to true,
FlagKey.ChromeAutofill to true,
)
private val UPDATED_MAP_VALUE: Map<FlagKey<Any>, Any> = mapOf(
@@ -157,6 +158,7 @@ private val UPDATED_MAP_VALUE: Map<FlagKey<Any>, Any> = mapOf(
FlagKey.SingleTapPasskeyAuthentication to false,
FlagKey.AnonAddySelfHostAlias to false,
FlagKey.SimpleLoginSelfHostAlias to false,
FlagKey.ChromeAutofill to false,
)
private val DEFAULT_STATE = DebugMenuState(