mirror of
https://github.com/bitwarden/android.git
synced 2026-06-08 16:17:05 -05:00
Get autofill enabled information more reliably (#867)
This commit is contained in:
committed by
Álison Fernandes
parent
2de2ade7a6
commit
f93db195c0
@@ -12,6 +12,7 @@ import androidx.core.os.LocaleListCompat
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillActivityManager
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillCompletionManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.ui.platform.feature.rootnav.RootNavScreen
|
||||
@@ -29,6 +30,9 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
private val mainViewModel: MainViewModel by viewModels()
|
||||
|
||||
@Inject
|
||||
lateinit var autofillActivityManager: AutofillActivityManager
|
||||
|
||||
@Inject
|
||||
lateinit var autofillCompletionManager: AutofillCompletionManager
|
||||
|
||||
|
||||
@@ -1,25 +1,49 @@
|
||||
package com.x8bit.bitwarden.data.autofill.di
|
||||
|
||||
import com.x8bit.bitwarden.MainActivity
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManagerImpl
|
||||
import android.app.Activity
|
||||
import android.view.autofill.AutofillManager
|
||||
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.platform.manager.AppForegroundManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityRetainedComponent
|
||||
import dagger.hilt.android.scopes.ActivityRetainedScoped
|
||||
import dagger.hilt.android.components.ActivityComponent
|
||||
import dagger.hilt.android.scopes.ActivityScoped
|
||||
|
||||
/**
|
||||
* Provides dependencies in the autofill package that must be scoped to a retained Activity. These
|
||||
* are for dependencies that must operate independently in different application tasks that contain
|
||||
* unique [MainActivity] instances.
|
||||
* Provides dependencies in the autofill package that must be scoped to a single Activity. These
|
||||
* are for dependencies that require a very specific Activity's context to operate.
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(ActivityRetainedComponent::class)
|
||||
@InstallIn(ActivityComponent::class)
|
||||
object ActivityAutofillModule {
|
||||
|
||||
@ActivityRetainedScoped
|
||||
@ActivityScoped
|
||||
@Provides
|
||||
fun provideAutofillSelectionManager(): AutofillSelectionManager =
|
||||
AutofillSelectionManagerImpl()
|
||||
fun provideAutofillActivityManager(
|
||||
@ActivityScopedManager autofillManager: AutofillManager,
|
||||
appForegroundManager: AppForegroundManager,
|
||||
autofillEnabledManager: AutofillEnabledManager,
|
||||
dispatcherManager: DispatcherManager,
|
||||
): AutofillActivityManager =
|
||||
AutofillActivityManagerImpl(
|
||||
autofillManager = autofillManager,
|
||||
appForegroundManager = appForegroundManager,
|
||||
autofillEnabledManager = autofillEnabledManager,
|
||||
dispatcherManager = dispatcherManager,
|
||||
)
|
||||
|
||||
/**
|
||||
* An AutofillManager specific to the given Activity. This wll give more accurate results
|
||||
* compared to the global manager.
|
||||
*/
|
||||
@ActivityScoped
|
||||
@ActivityScopedManager
|
||||
@Provides
|
||||
fun provideActivityScopedAutofillManager(
|
||||
activity: Activity,
|
||||
): AutofillManager = activity.getSystemService(AutofillManager::class.java)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.x8bit.bitwarden.data.autofill.di
|
||||
|
||||
import com.x8bit.bitwarden.MainActivity
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManagerImpl
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityRetainedComponent
|
||||
import dagger.hilt.android.scopes.ActivityRetainedScoped
|
||||
|
||||
/**
|
||||
* Provides dependencies in the autofill package that must be scoped to a retained Activity. These
|
||||
* are for dependencies that must operate independently in different application tasks that contain
|
||||
* unique [MainActivity] instances.
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(ActivityRetainedComponent::class)
|
||||
object ActivityRetainedAutofillModule {
|
||||
|
||||
@ActivityRetainedScoped
|
||||
@Provides
|
||||
fun provideAutofillSelectionManager(): AutofillSelectionManager =
|
||||
AutofillSelectionManagerImpl()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.x8bit.bitwarden.data.autofill.di
|
||||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
/**
|
||||
* Used to denote that the particular manager is scoped to a single Activity instance.
|
||||
*/
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ActivityScopedManager
|
||||
@@ -9,6 +9,8 @@ import com.x8bit.bitwarden.data.autofill.builder.FilledDataBuilder
|
||||
import com.x8bit.bitwarden.data.autofill.builder.FilledDataBuilderImpl
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillCompletionManager
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillCompletionManagerImpl
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillEnabledManager
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillEnabledManagerImpl
|
||||
import com.x8bit.bitwarden.data.autofill.parser.AutofillParser
|
||||
import com.x8bit.bitwarden.data.autofill.parser.AutofillParserImpl
|
||||
import com.x8bit.bitwarden.data.autofill.processor.AutofillProcessor
|
||||
@@ -39,6 +41,11 @@ object AutofillModule {
|
||||
@ApplicationContext context: Context,
|
||||
): AutofillManager = context.getSystemService(AutofillManager::class.java)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun providesAutofillEnabledManager(): AutofillEnabledManager =
|
||||
AutofillEnabledManagerImpl()
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideAutofillCompletionManager(
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.x8bit.bitwarden.data.autofill.manager
|
||||
|
||||
import android.app.Activity
|
||||
|
||||
/**
|
||||
* A helper for dealing with autofill configuration that must be scoped to a specific [Activity].
|
||||
* In particular, this should be injected into an [Activity] to ensure that an
|
||||
* [AutofillEnabledManager] reports correct values.
|
||||
*/
|
||||
interface AutofillActivityManager
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.x8bit.bitwarden.data.autofill.manager
|
||||
|
||||
import android.view.autofill.AutofillManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
/**
|
||||
* Primary implementation of [AutofillActivityManager].
|
||||
*/
|
||||
class AutofillActivityManagerImpl(
|
||||
private val autofillManager: AutofillManager,
|
||||
private val appForegroundManager: AppForegroundManager,
|
||||
private val autofillEnabledManager: AutofillEnabledManager,
|
||||
private val dispatcherManager: DispatcherManager,
|
||||
) : AutofillActivityManager {
|
||||
private val isAutofillEnabledAndSupported: Boolean
|
||||
get() = autofillManager.isEnabled &&
|
||||
autofillManager.hasEnabledAutofillServices() &&
|
||||
autofillManager.isAutofillSupported
|
||||
|
||||
private val unconfinedScope = CoroutineScope(dispatcherManager.unconfined)
|
||||
|
||||
init {
|
||||
appForegroundManager
|
||||
.appForegroundStateFlow
|
||||
.onEach {
|
||||
autofillEnabledManager.isAutofillEnabled = isAutofillEnabledAndSupported
|
||||
}
|
||||
.launchIn(unconfinedScope)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.x8bit.bitwarden.data.autofill.manager
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* A container for values specifying whether or not autofill is enabled. These values should be
|
||||
* filled by an [AutofillActivityManager].
|
||||
*/
|
||||
interface AutofillEnabledManager {
|
||||
/**
|
||||
* Whether or not autofill should be considered enabled.
|
||||
*
|
||||
* Note that changing this does not enable or disable autofill; it is only an indicator that
|
||||
* this has occurred elsewhere.
|
||||
*/
|
||||
var isAutofillEnabled: Boolean
|
||||
|
||||
/**
|
||||
* Emits updates that track [isAutofillEnabled] values.
|
||||
*/
|
||||
val isAutofillEnabledStateFlow: StateFlow<Boolean>
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.x8bit.bitwarden.data.autofill.manager
|
||||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
/**
|
||||
* Primary implementation of [AutofillEnabledManager].
|
||||
*/
|
||||
class AutofillEnabledManagerImpl : AutofillEnabledManager {
|
||||
private val mutableIsAutofillEnabledStateFlow = MutableStateFlow(false)
|
||||
|
||||
override var isAutofillEnabled: Boolean
|
||||
get() = mutableIsAutofillEnabledStateFlow.value
|
||||
set(value) {
|
||||
mutableIsAutofillEnabledStateFlow.value = value
|
||||
}
|
||||
|
||||
override val isAutofillEnabledStateFlow: StateFlow<Boolean>
|
||||
get() = mutableIsAutofillEnabledStateFlow.asStateFlow()
|
||||
}
|
||||
@@ -4,8 +4,8 @@ import android.view.autofill.AutofillManager
|
||||
import com.x8bit.bitwarden.BuildConfig
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserFingerprintResult
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillEnabledManager
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.BiometricsKeyResult
|
||||
@@ -21,13 +21,9 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.Instant
|
||||
@@ -40,7 +36,7 @@ private val DEFAULT_IS_SCREEN_CAPTURE_ALLOWED = BuildConfig.DEBUG
|
||||
@Suppress("TooManyFunctions", "LongParameterList")
|
||||
class SettingsRepositoryImpl(
|
||||
private val autofillManager: AutofillManager,
|
||||
private val appForegroundManager: AppForegroundManager,
|
||||
private val autofillEnabledManager: AutofillEnabledManager,
|
||||
private val authDiskSource: AuthDiskSource,
|
||||
private val settingsDiskSource: SettingsDiskSource,
|
||||
private val vaultSdkSource: VaultSdkSource,
|
||||
@@ -51,13 +47,6 @@ class SettingsRepositoryImpl(
|
||||
|
||||
private val unconfinedScope = CoroutineScope(dispatcherManager.unconfined)
|
||||
|
||||
private val isAutofillEnabledAndSupported: Boolean
|
||||
get() = autofillManager.isEnabled &&
|
||||
autofillManager.hasEnabledAutofillServices() &&
|
||||
autofillManager.isAutofillSupported
|
||||
|
||||
private val mutableIsAutofillEnabledStateFlow = MutableStateFlow(isAutofillEnabledAndSupported)
|
||||
|
||||
override var appLanguage: AppLanguage
|
||||
get() = settingsDiskSource.appLanguage ?: AppLanguage.DEFAULT
|
||||
set(value) {
|
||||
@@ -231,7 +220,7 @@ class SettingsRepositoryImpl(
|
||||
)
|
||||
}
|
||||
override val isAutofillEnabledStateFlow: StateFlow<Boolean> =
|
||||
mutableIsAutofillEnabledStateFlow.asStateFlow()
|
||||
autofillEnabledManager.isAutofillEnabledStateFlow
|
||||
|
||||
override var isScreenCaptureAllowed: Boolean
|
||||
get() = activeUserId?.let {
|
||||
@@ -266,16 +255,12 @@ class SettingsRepositoryImpl(
|
||||
?: DEFAULT_IS_SCREEN_CAPTURE_ALLOWED,
|
||||
)
|
||||
|
||||
init {
|
||||
observeAutofillEnabledChanges()
|
||||
}
|
||||
|
||||
override fun disableAutofill() {
|
||||
autofillManager.disableAutofillServices()
|
||||
|
||||
// Manually indicate that autofill is no longer supported without needing a foreground state
|
||||
// change.
|
||||
mutableIsAutofillEnabledStateFlow.value = false
|
||||
autofillEnabledManager.isAutofillEnabled = false
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
@@ -435,21 +420,6 @@ class SettingsRepositoryImpl(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun observeAutofillEnabledChanges() {
|
||||
mutableIsAutofillEnabledStateFlow
|
||||
// Only observe when subscribed to.
|
||||
.subscriptionCount.map { it > 0 }
|
||||
.filter { hasSubscribers -> hasSubscribers }
|
||||
.flatMapLatest {
|
||||
appForegroundManager.appForegroundStateFlow
|
||||
}
|
||||
.onEach {
|
||||
mutableIsAutofillEnabledStateFlow.value = isAutofillEnabledAndSupported
|
||||
}
|
||||
.launchIn(unconfinedScope)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.platform.repository.di
|
||||
|
||||
import android.view.autofill.AutofillManager
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillEnabledManager
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.EnvironmentDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
|
||||
@@ -42,6 +43,7 @@ object PlatformRepositoryModule {
|
||||
@Singleton
|
||||
fun provideSettingsRepository(
|
||||
autofillManager: AutofillManager,
|
||||
autofillEnabledManager: AutofillEnabledManager,
|
||||
appForegroundManager: AppForegroundManager,
|
||||
authDiskSource: AuthDiskSource,
|
||||
settingsDiskSource: SettingsDiskSource,
|
||||
@@ -51,7 +53,7 @@ object PlatformRepositoryModule {
|
||||
): SettingsRepository =
|
||||
SettingsRepositoryImpl(
|
||||
autofillManager = autofillManager,
|
||||
appForegroundManager = appForegroundManager,
|
||||
autofillEnabledManager = autofillEnabledManager,
|
||||
authDiskSource = authDiskSource,
|
||||
settingsDiskSource = settingsDiskSource,
|
||||
vaultSdkSource = vaultSdkSource,
|
||||
|
||||
Reference in New Issue
Block a user