mirror of
https://github.com/bitwarden/android.git
synced 2025-03-16 03:08:50 +03:00
Add AppForegroundManager (#599)
This commit is contained in:
parent
70308c84be
commit
3d75867a15
8 changed files with 168 additions and 0 deletions
|
@ -77,6 +77,11 @@ The following is a list of all third-party dependencies included as part of the
|
|||
- Purpose: Display and capture images for barcode scanning.
|
||||
- License: Apache 2.0
|
||||
|
||||
- **AndroidX Lifecycle**
|
||||
- https://developer.android.com/jetpack/androidx/releases/lifecycle
|
||||
- Purpose: Lifecycle aware components and tooling.
|
||||
- License: Apache 2.0
|
||||
|
||||
- **AndroidX Security**
|
||||
- https://developer.android.com/jetpack/androidx/releases/security
|
||||
- Purpose: Safely manage keys and encrypt files and sharedpreferences.
|
||||
|
|
|
@ -162,6 +162,7 @@ dependencies {
|
|||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.hilt.navigation.compose)
|
||||
implementation(libs.androidx.lifecycle.process)
|
||||
implementation(libs.androidx.lifecycle.runtime.compose)
|
||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.AppForegroundState
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* A manager for tracking app foreground state changes.
|
||||
*/
|
||||
interface AppForegroundManager {
|
||||
|
||||
/**
|
||||
* Emits whenever there are changes to the app foreground state.
|
||||
*/
|
||||
val appForegroundStateFlow: StateFlow<AppForegroundState>
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.AppForegroundState
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
/**
|
||||
* Primary implementation of [AppForegroundManager].
|
||||
*/
|
||||
class AppForegroundManagerImpl(
|
||||
processLifecycleOwner: LifecycleOwner = ProcessLifecycleOwner.get(),
|
||||
) : AppForegroundManager {
|
||||
private val mutableAppForegroundStateFlow =
|
||||
MutableStateFlow(AppForegroundState.BACKGROUNDED)
|
||||
|
||||
override val appForegroundStateFlow: StateFlow<AppForegroundState>
|
||||
get() = mutableAppForegroundStateFlow.asStateFlow()
|
||||
|
||||
init {
|
||||
processLifecycleOwner.lifecycle.addObserver(
|
||||
object : DefaultLifecycleObserver {
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
mutableAppForegroundStateFlow.value = AppForegroundState.FOREGROUNDED
|
||||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
mutableAppForegroundStateFlow.value = AppForegroundState.BACKGROUNDED
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
|||
import com.x8bit.bitwarden.data.platform.datasource.network.authenticator.RefreshAuthenticator
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.interceptor.AuthTokenInterceptor
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.interceptor.BaseUrlInterceptors
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.NetworkConfigManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.NetworkConfigManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.SdkClientManager
|
||||
|
@ -29,6 +31,11 @@ import javax.inject.Singleton
|
|||
@InstallIn(SingletonComponent::class)
|
||||
object PlatformManagerModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAppForegroundManager(): AppForegroundManager =
|
||||
AppForegroundManagerImpl()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideClock(): Clock = Clock.systemDefaultZone()
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager.model
|
||||
|
||||
/**
|
||||
* Represents the foreground state of the app.
|
||||
*/
|
||||
enum class AppForegroundState {
|
||||
/**
|
||||
* Denotes that the app is backgrounded.
|
||||
*/
|
||||
BACKGROUNDED,
|
||||
|
||||
/**
|
||||
* Denotes that the app is foregrounded.
|
||||
*/
|
||||
FOREGROUNDED,
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.AppForegroundState
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class AppForegroundManagerTest {
|
||||
|
||||
private val fakeLifecycleOwner = FakeLifecycleOwner()
|
||||
|
||||
private val appForegroundManager = AppForegroundManagerImpl(
|
||||
processLifecycleOwner = fakeLifecycleOwner,
|
||||
)
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `appForegroundStateFlow should emit whenever the underlying ProcessLifecycleOwner receives start and stop events`() =
|
||||
runTest {
|
||||
appForegroundManager.appForegroundStateFlow.test {
|
||||
// Initial state is BACKGROUNDED
|
||||
assertEquals(
|
||||
AppForegroundState.BACKGROUNDED,
|
||||
awaitItem(),
|
||||
)
|
||||
|
||||
fakeLifecycleOwner.lifecycle.dispatchOnStart()
|
||||
|
||||
assertEquals(
|
||||
AppForegroundState.FOREGROUNDED,
|
||||
awaitItem(),
|
||||
)
|
||||
|
||||
fakeLifecycleOwner.lifecycle.dispatchOnStop()
|
||||
|
||||
assertEquals(
|
||||
AppForegroundState.BACKGROUNDED,
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FakeLifecycle(
|
||||
private val lifecycleOwner: LifecycleOwner,
|
||||
) : Lifecycle() {
|
||||
private val observers = mutableSetOf<DefaultLifecycleObserver>()
|
||||
|
||||
override var currentState: State = State.INITIALIZED
|
||||
|
||||
override fun addObserver(observer: LifecycleObserver) {
|
||||
observers += (observer as DefaultLifecycleObserver)
|
||||
}
|
||||
|
||||
override fun removeObserver(observer: LifecycleObserver) {
|
||||
observers -= (observer as DefaultLifecycleObserver)
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers [DefaultLifecycleObserver.onStart] calls for each registered observer.
|
||||
*/
|
||||
fun dispatchOnStart() {
|
||||
currentState = State.STARTED
|
||||
observers.forEach { observer ->
|
||||
observer.onStart(lifecycleOwner)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers [DefaultLifecycleObserver.onStop] calls for each registered observer.
|
||||
*/
|
||||
fun dispatchOnStop() {
|
||||
currentState = State.CREATED
|
||||
observers.forEach { observer ->
|
||||
observer.onStop(lifecycleOwner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FakeLifecycleOwner : LifecycleOwner {
|
||||
override val lifecycle: FakeLifecycle = FakeLifecycle(this)
|
||||
}
|
|
@ -71,6 +71,7 @@ androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
|
|||
androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
|
||||
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" }
|
||||
androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "androidxHiltNavigationCompose" }
|
||||
androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "androidxLifecycle" }
|
||||
androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidxLifecycle" }
|
||||
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidxLifecycle" }
|
||||
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidxNavigation" }
|
||||
|
|
Loading…
Add table
Reference in a new issue