mirror of
https://github.com/bitwarden/android.git
synced 2024-11-21 17:05:44 +03:00
BITAU-182 BITAU-107 Don't show authetnicator sync toggle below API 31 (#4156)
This commit is contained in:
parent
0960f61c37
commit
164cc09f19
5 changed files with 63 additions and 9 deletions
|
@ -1,5 +1,6 @@
|
||||||
package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity
|
package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
@ -19,6 +20,7 @@ import com.x8bit.bitwarden.data.platform.repository.model.BiometricsKeyResult
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
|
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||||
import com.x8bit.bitwarden.data.platform.repository.util.baseWebVaultUrlOrDefault
|
import com.x8bit.bitwarden.data.platform.repository.util.baseWebVaultUrlOrDefault
|
||||||
|
import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||||
|
@ -71,9 +73,9 @@ class AccountSecurityViewModel @Inject constructor(
|
||||||
?.activeAccount
|
?.activeAccount
|
||||||
?.hasMasterPassword != false,
|
?.hasMasterPassword != false,
|
||||||
isUnlockWithPinEnabled = settingsRepository.isUnlockWithPinEnabled,
|
isUnlockWithPinEnabled = settingsRepository.isUnlockWithPinEnabled,
|
||||||
shouldShowEnableAuthenticatorSync = featureFlagManager.getFeatureFlag(
|
shouldShowEnableAuthenticatorSync =
|
||||||
key = FlagKey.AuthenticatorSync,
|
featureFlagManager.getFeatureFlag(FlagKey.AuthenticatorSync) &&
|
||||||
),
|
!isBuildVersionBelow(Build.VERSION_CODES.S),
|
||||||
userId = userId,
|
userId = userId,
|
||||||
vaultTimeout = settingsRepository.vaultTimeout,
|
vaultTimeout = settingsRepository.vaultTimeout,
|
||||||
vaultTimeoutAction = settingsRepository.vaultTimeoutAction,
|
vaultTimeoutAction = settingsRepository.vaultTimeoutAction,
|
||||||
|
@ -372,9 +374,11 @@ class AccountSecurityViewModel @Inject constructor(
|
||||||
private fun handleAuthenticatorSyncFeatureFlagUpdate(
|
private fun handleAuthenticatorSyncFeatureFlagUpdate(
|
||||||
action: AccountSecurityAction.Internal.AuthenticatorSyncFeatureFlagUpdate,
|
action: AccountSecurityAction.Internal.AuthenticatorSyncFeatureFlagUpdate,
|
||||||
) {
|
) {
|
||||||
|
val shouldShowAuthenticatorSync =
|
||||||
|
action.isEnabled && !isBuildVersionBelow(Build.VERSION_CODES.S)
|
||||||
mutableStateFlow.update {
|
mutableStateFlow.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
shouldShowEnableAuthenticatorSync = action.isEnabled,
|
shouldShowEnableAuthenticatorSync = shouldShowAuthenticatorSync,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1001,7 +1001,7 @@ Do you want to switch to this account?</string>
|
||||||
<string name="please_restart_registration_or_try_logging_in">Please restart registration or try logging in. You may already have an account.</string>
|
<string name="please_restart_registration_or_try_logging_in">Please restart registration or try logging in. You may already have an account.</string>
|
||||||
<string name="restart_registration">Restart registration</string>
|
<string name="restart_registration">Restart registration</string>
|
||||||
<string name="authenticator_sync">Authenticator Sync</string>
|
<string name="authenticator_sync">Authenticator Sync</string>
|
||||||
<string name="allow_bitwarden_authenticator_syncing">Allow Bitwarden Authenticator Syncing</string>
|
<string name="allow_bitwarden_authenticator_syncing">Allow authenticator syncing</string>
|
||||||
<string name="there_was_an_issue_validating_the_registration_token">There was an issue validating the registration token.</string>
|
<string name="there_was_an_issue_validating_the_registration_token">There was an issue validating the registration token.</string>
|
||||||
<string name="turn_on_autofill">Turn on autofill</string>
|
<string name="turn_on_autofill">Turn on autofill</string>
|
||||||
<string name="use_autofill_to_log_into_your_accounts">Use autofill to log into your accounts with a single tap.</string>
|
<string name="use_autofill_to_log_into_your_accounts">Use autofill to log into your accounts with a single tap.</string>
|
||||||
|
|
|
@ -1465,7 +1465,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `sync with Bitwarden authenticator UI should be displayed according to state`() {
|
fun `sync with Bitwarden authenticator UI should be displayed according to state`() {
|
||||||
val toggleText = "Allow Bitwarden Authenticator Syncing"
|
val toggleText = "Allow authenticator syncing"
|
||||||
composeTestRule.onNodeWithText(toggleText).assertDoesNotExist()
|
composeTestRule.onNodeWithText(toggleText).assertDoesNotExist()
|
||||||
|
|
||||||
mutableStateFlow.update { DEFAULT_STATE.copy(shouldShowEnableAuthenticatorSync = true) }
|
mutableStateFlow.update { DEFAULT_STATE.copy(shouldShowEnableAuthenticatorSync = true) }
|
||||||
|
@ -1486,7 +1486,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||||
fun `sync with Bitwarden authenticator click should send AuthenticatorSyncToggle action`() {
|
fun `sync with Bitwarden authenticator click should send AuthenticatorSyncToggle action`() {
|
||||||
mutableStateFlow.update { DEFAULT_STATE.copy(shouldShowEnableAuthenticatorSync = true) }
|
mutableStateFlow.update { DEFAULT_STATE.copy(shouldShowEnableAuthenticatorSync = true) }
|
||||||
composeTestRule
|
composeTestRule
|
||||||
.onNodeWithText("Allow Bitwarden Authenticator Syncing")
|
.onNodeWithText("Allow authenticator syncing")
|
||||||
.performScrollTo()
|
.performScrollTo()
|
||||||
.performClick()
|
.performClick()
|
||||||
verify { viewModel.trySendAction(AccountSecurityAction.AuthenticatorSyncToggle(true)) }
|
verify { viewModel.trySendAction(AccountSecurityAction.AuthenticatorSyncToggle(true)) }
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity
|
package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.x8bit.bitwarden.R
|
import com.x8bit.bitwarden.R
|
||||||
|
@ -22,6 +23,7 @@ import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||||
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
||||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||||
|
import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockPolicy
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockPolicy
|
||||||
|
@ -35,7 +37,9 @@ import io.mockk.coVerify
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
import io.mockk.mockkStatic
|
||||||
import io.mockk.runs
|
import io.mockk.runs
|
||||||
|
import io.mockk.unmockkStatic
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.emptyFlow
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
|
@ -44,7 +48,9 @@ import kotlinx.coroutines.test.runTest
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.encodeToJsonElement
|
import kotlinx.serialization.json.encodeToJsonElement
|
||||||
import kotlinx.serialization.json.jsonObject
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import org.junit.jupiter.api.AfterEach
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
|
|
||||||
|
@ -91,6 +97,16 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||||
every { getFeatureFlag(FlagKey.AuthenticatorSync) } returns false
|
every { getFeatureFlag(FlagKey.AuthenticatorSync) } returns false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun setup() {
|
||||||
|
mockkStatic(::isBuildVersionBelow)
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
fun teardown() {
|
||||||
|
unmockkStatic(::isBuildVersionBelow)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `initial state should be correct when saved state is set`() {
|
fun `initial state should be correct when saved state is set`() {
|
||||||
val viewModel = createViewModel(initialState = DEFAULT_STATE)
|
val viewModel = createViewModel(initialState = DEFAULT_STATE)
|
||||||
|
@ -679,7 +695,8 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `when featureFlagManger returns true for AuthenticatorSync, should show authenticator sync UI`() {
|
fun `when featureFlagManger returns true for AuthenticatorSync, and version is at least 31 should show authenticator sync UI`() {
|
||||||
|
every { isBuildVersionBelow(Build.VERSION_CODES.S) } returns false
|
||||||
val vm = createViewModel(
|
val vm = createViewModel(
|
||||||
initialState = null,
|
initialState = null,
|
||||||
featureFlagManager = mockk {
|
featureFlagManager = mockk {
|
||||||
|
@ -693,8 +710,22 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `when featureFlagManger returns true for AuthenticatorSync, and version is under 31 should not show authenticator sync UI`() {
|
||||||
|
every { isBuildVersionBelow(Build.VERSION_CODES.S) } returns true
|
||||||
|
every { featureFlagManager.getFeatureFlag(FlagKey.AuthenticatorSync) } returns true
|
||||||
|
every { featureFlagManager.getFeatureFlagFlow(FlagKey.AuthenticatorSync) } returns emptyFlow()
|
||||||
|
val vm = createViewModel(initialState = null)
|
||||||
|
assertEquals(
|
||||||
|
DEFAULT_STATE,
|
||||||
|
vm.stateFlow.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when featureFlagManger updates value AuthenticatorSync, should update UI`() = runTest {
|
fun `when featureFlagManger updates value AuthenticatorSync, should update UI`() = runTest {
|
||||||
|
every { isBuildVersionBelow(Build.VERSION_CODES.S) } returns false
|
||||||
val featureFlagFlow = MutableStateFlow(false)
|
val featureFlagFlow = MutableStateFlow(false)
|
||||||
val vm = createViewModel(
|
val vm = createViewModel(
|
||||||
initialState = null,
|
initialState = null,
|
||||||
|
@ -712,6 +743,25 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
fun `when featureFlagManger updates value AuthenticatorSync, authenticator sync row should never show if below API 31`() =
|
||||||
|
runTest {
|
||||||
|
every { isBuildVersionBelow(Build.VERSION_CODES.S) } returns true
|
||||||
|
val featureFlagFlow = MutableStateFlow(false)
|
||||||
|
every { featureFlagManager.getFeatureFlag(FlagKey.AuthenticatorSync) } returns false
|
||||||
|
every {
|
||||||
|
featureFlagManager.getFeatureFlagFlow(FlagKey.AuthenticatorSync)
|
||||||
|
} returns featureFlagFlow
|
||||||
|
val vm = createViewModel(initialState = null)
|
||||||
|
vm.stateFlow.test {
|
||||||
|
assertEquals(DEFAULT_STATE, awaitItem())
|
||||||
|
featureFlagFlow.value = true
|
||||||
|
featureFlagFlow.value = false
|
||||||
|
expectNoEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when showUnlockBadgeFlow updates value, should update state`() = runTest {
|
fun `when showUnlockBadgeFlow updates value, should update state`() = runTest {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
|
|
|
@ -7,4 +7,4 @@ import android.os.Build
|
||||||
*
|
*
|
||||||
* @see Build.VERSION_CODES
|
* @see Build.VERSION_CODES
|
||||||
*/
|
*/
|
||||||
fun isBuildVersionBelow(version: Int): Boolean = version > Build.VERSION.SDK_INT
|
internal fun isBuildVersionBelow(version: Int): Boolean = version > Build.VERSION.SDK_INT
|
||||||
|
|
Loading…
Reference in a new issue