diff options
3 files changed, 119 insertions, 52 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryImplTest.kt index 30a5497d0a14..c4a8582d51b5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryImplTest.kt @@ -20,15 +20,16 @@ import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.data.repository.CommunalTutorialRepositoryImpl.Companion.CURRENT_TUTORIAL_VERSION import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.core.FakeLogBuffer -import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope +import com.android.systemui.log.logcatLogBuffer +import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.test.StandardTestDispatcher -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -38,36 +39,37 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) class CommunalTutorialRepositoryImplTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private lateinit var secureSettings: FakeSettings private lateinit var userRepository: FakeUserRepository - private lateinit var userTracker: FakeUserTracker - private lateinit var logBuffer: LogBuffer - private val testDispatcher = StandardTestDispatcher() - private val testScope = TestScope(testDispatcher) + private lateinit var underTest: CommunalTutorialRepositoryImpl @Before fun setUp() { MockitoAnnotations.initMocks(this) - logBuffer = FakeLogBuffer.Factory.create() secureSettings = FakeSettings() userRepository = FakeUserRepository() val listOfUserInfo = listOf(MAIN_USER_INFO) userRepository.setUserInfos(listOfUserInfo) - userTracker = FakeUserTracker() - userTracker.set( - userInfos = listOfUserInfo, - selectedUserIndex = 0, - ) + underTest = + CommunalTutorialRepositoryImpl( + kosmos.applicationCoroutineScope, + kosmos.testDispatcher, + userRepository, + secureSettings, + logcatLogBuffer("CommunalTutorialRepositoryImplTest"), + ) } @Test fun tutorialSettingState_defaultToNotStarted() = testScope.runTest { - val repository = initCommunalTutorialRepository() - val tutorialSettingState = collectLastValue(repository.tutorialSettingState)() + val tutorialSettingState by collectLastValue(underTest.tutorialSettingState) assertThat(tutorialSettingState) .isEqualTo(Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED) } @@ -75,31 +77,55 @@ class CommunalTutorialRepositoryImplTest : SysuiTestCase() { @Test fun tutorialSettingState_whenTutorialSettingsUpdatedToStarted() = testScope.runTest { - val repository = initCommunalTutorialRepository() - setTutorialStateSetting(Settings.Secure.HUB_MODE_TUTORIAL_STARTED) - val tutorialSettingState = collectLastValue(repository.tutorialSettingState)() + underTest.setTutorialState(Settings.Secure.HUB_MODE_TUTORIAL_STARTED) + val tutorialSettingState by collectLastValue(underTest.tutorialSettingState) assertThat(tutorialSettingState).isEqualTo(Settings.Secure.HUB_MODE_TUTORIAL_STARTED) } @Test fun tutorialSettingState_whenTutorialSettingsUpdatedToCompleted() = testScope.runTest { - val repository = initCommunalTutorialRepository() - setTutorialStateSetting(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) - val tutorialSettingState = collectLastValue(repository.tutorialSettingState)() + underTest.setTutorialState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) + val tutorialSettingState by collectLastValue(underTest.tutorialSettingState) assertThat(tutorialSettingState).isEqualTo(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) } - private fun initCommunalTutorialRepository(): CommunalTutorialRepositoryImpl { - return CommunalTutorialRepositoryImpl( - testScope.backgroundScope, - testDispatcher, - userRepository, - secureSettings, - userTracker, - logBuffer - ) - } + @Test + fun tutorialVersion_userCompletedCurrentVersion_stateCompleted() = + testScope.runTest { + // User completed the current version. + setTutorialStateSetting(CURRENT_TUTORIAL_VERSION) + + // Verify tutorial state is completed. + val tutorialSettingState by collectLastValue(underTest.tutorialSettingState) + assertThat(tutorialSettingState).isEqualTo(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) + } + + @Test + fun tutorialVersion_userCompletedPreviousVersion_stateNotStarted() = + testScope.runTest { + // User completed the previous version. + setTutorialStateSetting(CURRENT_TUTORIAL_VERSION - 1) + + // Verify tutorial state is not started. + val tutorialSettingState by collectLastValue(underTest.tutorialSettingState) + assertThat(tutorialSettingState) + .isEqualTo(Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED) + } + + @Test + fun tutorialVersion_uponTutorialCompletion_writeCurrentVersion() = + testScope.runTest { + // Tutorial not started. + setTutorialStateSetting(Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED) + + // Tutorial completed. + underTest.setTutorialState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) + + // Verify tutorial setting state is updated to current version. + val settingState = getTutorialStateSetting() + assertThat(settingState).isEqualTo(CURRENT_TUTORIAL_VERSION) + } private fun setTutorialStateSetting( @Settings.Secure.HubModeTutorialState state: Int, @@ -108,6 +134,10 @@ class CommunalTutorialRepositoryImplTest : SysuiTestCase() { secureSettings.putIntForUser(Settings.Secure.HUB_MODE_TUTORIAL_STATE, state, user.id) } + private fun getTutorialStateSetting(user: UserInfo = MAIN_USER_INFO): Int { + return secureSettings.getIntForUser(Settings.Secure.HUB_MODE_TUTORIAL_STATE, user.id) + } + companion object { private val MAIN_USER_INFO = UserInfo(/* id= */ 0, /* name= */ "primary", /* flags= */ UserInfo.FLAG_MAIN) diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt index 9a9b0e29cbc4..046aaaa33342 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt @@ -16,6 +16,7 @@ package com.android.systemui.communal.data.repository import android.provider.Settings +import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED import android.provider.Settings.Secure.HubModeTutorialState import com.android.systemui.dagger.SysUISingleton @@ -24,7 +25,6 @@ import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger import com.android.systemui.log.dagger.CommunalLog -import com.android.systemui.settings.UserTracker import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow @@ -35,6 +35,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map @@ -62,14 +63,19 @@ class CommunalTutorialRepositoryImpl constructor( @Application private val applicationScope: CoroutineScope, @Background private val backgroundDispatcher: CoroutineDispatcher, - userRepository: UserRepository, + private val userRepository: UserRepository, private val secureSettings: SecureSettings, - private val userTracker: UserTracker, @CommunalLog logBuffer: LogBuffer, ) : CommunalTutorialRepository { companion object { private const val TAG = "CommunalTutorialRepository" + + const val MIN_TUTORIAL_VERSION = HUB_MODE_TUTORIAL_COMPLETED + + // A version number which ensures that users, regardless of their completion of previous + // versions, see the updated tutorial when this number is bumped. + const val CURRENT_TUTORIAL_VERSION = MIN_TUTORIAL_VERSION + 1 } private data class SettingsState( @@ -80,7 +86,7 @@ constructor( private val settingsState: Flow<SettingsState> = userRepository.selectedUserInfo - .flatMapLatest { observeSettings() } + .flatMapLatest { userInfo -> observeSettings(userInfo.id) } .shareIn(scope = applicationScope, started = SharingStarted.WhileSubscribed()) /** Emits the state of tutorial state in settings */ @@ -91,31 +97,37 @@ constructor( .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), - initialValue = HUB_MODE_TUTORIAL_NOT_STARTED + initialValue = HUB_MODE_TUTORIAL_NOT_STARTED, ) - private fun observeSettings(): Flow<SettingsState> = + private fun observeSettings(userId: Int): Flow<SettingsState> = secureSettings .observerFlow( - userId = userTracker.userId, - names = - arrayOf( - Settings.Secure.HUB_MODE_TUTORIAL_STATE, - ) + userId = userId, + names = arrayOf(Settings.Secure.HUB_MODE_TUTORIAL_STATE), ) // Force an update .onStart { emit(Unit) } - .map { readFromSettings() } + .map { readFromSettings(userId) } - private suspend fun readFromSettings(): SettingsState = + private suspend fun readFromSettings(userId: Int): SettingsState = withContext(backgroundDispatcher) { - val userId = userTracker.userId - val hubModeTutorialState = + var hubModeTutorialState = secureSettings.getIntForUser( Settings.Secure.HUB_MODE_TUTORIAL_STATE, HUB_MODE_TUTORIAL_NOT_STARTED, userId, ) + + if (hubModeTutorialState >= CURRENT_TUTORIAL_VERSION) { + // Tutorial is considered "completed" if the user has completed the current or a + // newer version. + hubModeTutorialState = HUB_MODE_TUTORIAL_COMPLETED + } else if (hubModeTutorialState >= MIN_TUTORIAL_VERSION) { + // Tutorial is considered "not started" if the user completed a version older than + // the current. + hubModeTutorialState = HUB_MODE_TUTORIAL_NOT_STARTED + } val settingsState = SettingsState(hubModeTutorialState) logger.d({ "Communal tutorial state for user $int1 in settings: $str1" }) { int1 = userId @@ -127,18 +139,40 @@ constructor( override suspend fun setTutorialState(state: Int): Unit = withContext(backgroundDispatcher) { - val userId = userTracker.userId + val userId = userRepository.getSelectedUserInfo().id if (tutorialSettingState.value == state) { return@withContext } + val newState = + if (state == HUB_MODE_TUTORIAL_COMPLETED) CURRENT_TUTORIAL_VERSION else state logger.d({ "Update communal tutorial state to $int1 for user $int2" }) { - int1 = state + int1 = newState int2 = userId } secureSettings.putIntForUser( Settings.Secure.HUB_MODE_TUTORIAL_STATE, - state, + newState, userId, ) } } + +// TODO(b/320769333): delete me and use the real repo above when tutorial is ready. +@SysUISingleton +class CommunalTutorialDisabledRepositoryImpl +@Inject +constructor( + @Application private val applicationScope: CoroutineScope, +) : CommunalTutorialRepository { + override val tutorialSettingState: StateFlow<Int> = + emptyFlow<Int>() + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = HUB_MODE_TUTORIAL_COMPLETED, + ) + + override suspend fun setTutorialState(state: Int) { + // Do nothing + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryModule.kt index 69b0a27c55a8..b4f838ad5567 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryModule.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepositoryModule.kt @@ -22,6 +22,9 @@ import dagger.Module @Module interface CommunalTutorialRepositoryModule { + // TODO(b/320769333): use [CommunalTutorialRepositoryImpl] when tutorial is ready. @Binds - fun communalTutorialRepository(impl: CommunalTutorialRepositoryImpl): CommunalTutorialRepository + fun communalTutorialRepository( + impl: CommunalTutorialDisabledRepositoryImpl + ): CommunalTutorialRepository } |