Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
</activity-alias>

<activity
android:name=".ui.permissioncheck.PermissionCheckActivity"
android:name=".ui.onboarding.OnboardingActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:theme="@style/Theme.Compose" />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.android.common.test.helpers

import com.android.messaging.BuildConfig
import com.android.messaging.util.BuglePrefs
import com.android.messaging.util.BuglePrefsKeys

object SmsWarningHelper {

fun acknowledgeSmsWarning(): Int {
val previousAcknowledgedVersion = BuglePrefs.getApplicationPrefs().getInt(
BuglePrefsKeys.SMS_WARNING_ACKNOWLEDGED_VERSION,
BuglePrefsKeys.SMS_WARNING_ACKNOWLEDGED_VERSION_DEFAULT,
)
BuglePrefs.getApplicationPrefs().putInt(
BuglePrefsKeys.SMS_WARNING_ACKNOWLEDGED_VERSION,
BuildConfig.VERSION_CODE,
)

return previousAcknowledgedVersion
}

fun restoreSmsWarning(previousAcknowledgedVersion: Int) {
BuglePrefs.getApplicationPrefs().putInt(
BuglePrefsKeys.SMS_WARNING_ACKNOWLEDGED_VERSION,
previousAcknowledgedVersion,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.android.common.test.rules

import com.android.common.test.helpers.ShellCommandHelper
import com.android.common.test.helpers.SmsWarningHelper
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
Expand All @@ -14,13 +15,17 @@ class AppTestRule : TestRule {
return object : Statement() {
override fun evaluate() {
val previousSmsRoleHolders = ShellCommandHelper.setupSmsDefaultRole()
val previousAcknowledgedVersion = SmsWarningHelper.acknowledgeSmsWarning()
var baseFailure: Throwable? = null
try {
base.evaluate()
} catch (throwable: Throwable) {
baseFailure = throwable
} finally {
try {
SmsWarningHelper.restoreSmsWarning(
previousAcknowledgedVersion = previousAcknowledgedVersion,
)
ShellCommandHelper.restoreSmsDefaultRole(
previousRoleHolders = previousSmsRoleHolders,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package com.android.messaging.ui.permissioncheck.screen
package com.android.messaging.ui.onboarding.screen

import app.cash.turbine.test
import com.android.messaging.data.permissioncheck.GetMissingPermissionLabels
import com.android.messaging.data.permissioncheck.RequiredPermissionsChecker
import com.android.messaging.domain.permissioncheck.model.PermissionRequest
import com.android.messaging.domain.permissioncheck.usecase.DeterminePermissionRequest
import com.android.messaging.data.onboarding.GetMissingPermissionLabels
import com.android.messaging.data.onboarding.RequiredPermissionsChecker
import com.android.messaging.data.onboarding.store.SmsWarningStore
import com.android.messaging.domain.onboarding.model.PermissionRequest
import com.android.messaging.domain.onboarding.usecase.DeterminePermissionRequest
import com.android.messaging.testutil.MainDispatcherRule
import com.android.messaging.ui.permissioncheck.screen.model.PermissionCheckAction as Action
import com.android.messaging.ui.permissioncheck.screen.model.PermissionCheckScreenEffect as Effect
import com.android.messaging.ui.permissioncheck.screen.model.SettingsGuidance
import com.android.messaging.ui.onboarding.screen.model.OnboardingAction as Action
import com.android.messaging.ui.onboarding.screen.model.OnboardingScreenEffect as Effect
import com.android.messaging.ui.onboarding.screen.model.OnboardingUiState as State
import com.android.messaging.ui.onboarding.screen.model.SettingsGuidance
import com.android.messaging.util.core.ElapsedRealtimeProvider
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
Expand All @@ -21,11 +24,93 @@ import org.junit.Rule
import org.junit.Test

@OptIn(ExperimentalCoroutinesApi::class)
class PermissionCheckViewModelTest {
class OnboardingViewModelTest {

@get:Rule
val mainDispatcherRule = MainDispatcherRule()

@Test
fun initialState_whenWarningNotAcknowledged_isSmsWarning() {
runTest(context = mainDispatcherRule.testDispatcher) {
val viewModel = createViewModel(
smsWarningStore = mockSmsWarningStore(isAcknowledged = false),
)

assertEquals(State.SmsWarning, viewModel.uiState.value)
}
}

@Test
fun initialState_whenWarningAcknowledged_isPermissions() {
runTest(context = mainDispatcherRule.testDispatcher) {
val viewModel = createViewModel(
smsWarningStore = mockSmsWarningStore(isAcknowledged = true),
)

assertEquals(State.Permissions(), viewModel.uiState.value)
}
}

@Test
fun onScreenResumed_onSmsWarningStep_whenPermissionsGranted_doesNotRedirect() {
runTest(context = mainDispatcherRule.testDispatcher) {
val viewModel = createViewModel(
checker = mockChecker(hasRequiredPermissions = true),
smsWarningStore = mockSmsWarningStore(isAcknowledged = false),
)

viewModel.effects.test {
viewModel.onScreenResumed()

expectNoEvents()
cancelAndIgnoreRemainingEvents()
}

assertEquals(State.SmsWarning, viewModel.uiState.value)
}
}

@Test
fun nextClicked_onSmsWarningStep_whenPermissionsMissing_acknowledgesAndShowsPermissions() {
runTest(context = mainDispatcherRule.testDispatcher) {
val smsWarningStore = mockSmsWarningStore(isAcknowledged = false)
val viewModel = createViewModel(
checker = mockChecker(hasRequiredPermissions = false),
smsWarningStore = smsWarningStore,
)

viewModel.effects.test {
viewModel.onAction(Action.NextClicked)

expectNoEvents()
cancelAndIgnoreRemainingEvents()
}

verify { smsWarningStore.acknowledge() }
assertEquals(State.Permissions(), viewModel.uiState.value)
}
}

@Test
fun nextClicked_onSmsWarningStep_whenPermissionsGranted_acknowledgesAndRedirects() {
runTest(context = mainDispatcherRule.testDispatcher) {
val smsWarningStore = mockSmsWarningStore(isAcknowledged = false)
val viewModel = createViewModel(
checker = mockChecker(hasRequiredPermissions = true),
smsWarningStore = smsWarningStore,
)

viewModel.effects.test {
viewModel.onAction(Action.NextClicked)

assertEquals(Effect.Redirect, awaitItem())
cancelAndIgnoreRemainingEvents()
}

verify { smsWarningStore.acknowledge() }
}
}

@Test
fun onScreenResumed_whenPermissionsGranted_emitsRedirect() {
runTest(context = mainDispatcherRule.testDispatcher) {
Expand Down Expand Up @@ -131,7 +216,7 @@ class PermissionCheckViewModelTest {
cancelAndIgnoreRemainingEvents()
}

assertNull(viewModel.uiState.value.settingsGuidance)
assertNull(viewModel.permissionsState().settingsGuidance)
}
}

Expand All @@ -158,8 +243,9 @@ class PermissionCheckViewModelTest {

viewModel.onRequestResult()

assertEquals(SettingsGuidance.DefaultSmsApp, viewModel.uiState.value.settingsGuidance)
assertEquals(persistentListOf<String>(), viewModel.uiState.value.missingPermissions)
val state = viewModel.permissionsState()
assertEquals(SettingsGuidance.DefaultSmsApp, state.settingsGuidance)
assertEquals(persistentListOf<String>(), state.missingPermissions)
}
}

Expand Down Expand Up @@ -190,8 +276,9 @@ class PermissionCheckViewModelTest {

viewModel.onRequestResult()

assertEquals(SettingsGuidance.Permissions, viewModel.uiState.value.settingsGuidance)
assertEquals(labels, viewModel.uiState.value.missingPermissions)
val state = viewModel.permissionsState()
assertEquals(SettingsGuidance.Permissions, state.settingsGuidance)
assertEquals(labels, state.missingPermissions)
}
}

Expand All @@ -217,7 +304,7 @@ class PermissionCheckViewModelTest {

viewModel.onRequestResult()

assertNull(viewModel.uiState.value.settingsGuidance)
assertNull(viewModel.permissionsState().settingsGuidance)
}
}

Expand All @@ -242,7 +329,7 @@ class PermissionCheckViewModelTest {

viewModel.onRequestResult()

assertNull(viewModel.uiState.value.settingsGuidance)
assertNull(viewModel.permissionsState().settingsGuidance)
}
}

Expand All @@ -255,15 +342,27 @@ class PermissionCheckViewModelTest {
persistentListOf()
},
elapsedRealtimeProvider: ElapsedRealtimeProvider = ElapsedRealtimeProvider { 0L },
): PermissionCheckViewModel {
return PermissionCheckViewModel(
smsWarningStore: SmsWarningStore = mockSmsWarningStore(isAcknowledged = true),
): OnboardingViewModel {
return OnboardingViewModel(
checker = checker,
determinePermissionRequest = determinePermissionRequest,
getMissingPermissionLabels = getMissingPermissionLabels,
elapsedRealtimeProvider = elapsedRealtimeProvider,
smsWarningStore = smsWarningStore,
)
}

private fun OnboardingViewModel.permissionsState(): State.Permissions {
return uiState.value as State.Permissions
}

private fun mockSmsWarningStore(isAcknowledged: Boolean): SmsWarningStore {
return mockk<SmsWarningStore>(relaxed = true).also {
every { it.isAcknowledged() } returns isAcknowledged
}
}

private fun mockChecker(
hasRequiredPermissions: Boolean,
isSmsRoleHeld: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.android.messaging.data.permissioncheck
package com.android.messaging.data.onboarding

import android.content.pm.PackageManager
import android.content.pm.PermissionInfo
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.android.messaging.data.onboarding.store

import com.android.messaging.FactoryTestAccess
import com.android.messaging.testutil.FakeBuglePrefs
import com.android.messaging.testutil.installTestFactory
import io.mockk.mockk
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test

class SmsWarningStoreTest {

@Before
fun setUp() {
installTestFactory(
context = mockk(relaxed = true),
prefs = FakeBuglePrefs(),
)
}

@After
fun tearDown() {
FactoryTestAccess.reset()
}

@Test
fun isAcknowledged_whenNothingStored_returnsFalse() {
assertFalse(createStore(versionCode = 42).isAcknowledged())
}

@Test
fun isAcknowledged_afterAcknowledgeOnSameBuild_returnsTrue() {
createStore(versionCode = 42).acknowledge()
assertTrue(createStore(versionCode = 42).isAcknowledged())
}

@Test
fun isAcknowledged_afterAcknowledgeOnEarlierBuild_returnsFalse() {
createStore(versionCode = 42).acknowledge()
assertFalse(createStore(versionCode = 43).isAcknowledged())
}

private fun createStore(versionCode: Int): SmsWarningStore {
return SmsWarningStoreImpl(
appVersionProvider = { versionCode },
)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.android.messaging.domain.permissioncheck.usecase
package com.android.messaging.domain.onboarding.usecase

import com.android.messaging.data.permissioncheck.RequiredPermissionsChecker
import com.android.messaging.domain.permissioncheck.model.PermissionRequest
import com.android.messaging.data.onboarding.RequiredPermissionsChecker
import com.android.messaging.domain.onboarding.model.PermissionRequest
import io.mockk.every
import io.mockk.mockk
import kotlinx.collections.immutable.ImmutableList
Expand Down
Loading
Loading