From 07b7d227776c9b651c7ee1b2debc54445e2ba7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabi=C3=A1n=20Kozynski?= Date: Tue, 11 Apr 2023 16:38:14 -0400 Subject: [PATCH] Adds Retail mode repository If the device is in retail mode, tiles are set to a different list and cannot be edited. Fixes: 277776030 Test: manual, device in demo mode Test: atest TileSpecSettingsRepositoryTest Test: atest RetailModeSettingsRepositoryTest Test: atest QSFooterViewControllerTest Change-Id: Ie3102bab7f658482ee4b128ec0689f19f69c1945 --- .../systemui/dagger/SystemUIModule.java | 2 + .../systemui/qs/QSFooterViewController.java | 9 +- .../data/repository/TileSpecRepository.kt | 34 ++++++++ .../shared/logging/QSPipelineLogger.kt | 4 + .../retail/dagger/RetailModeModule.kt | 34 ++++++++ .../data/repository/RetailModeRepository.kt | 81 ++++++++++++++++++ .../domain/interactor/RetailModeInteractor.kt | 37 ++++++++ .../qs/QSFooterViewControllerTest.java | 26 +++++- .../TileSpecSettingsRepositoryTest.kt | 27 ++++++ .../RetailModeSettingsRepositoryTest.kt | 84 +++++++++++++++++++ .../RetailModeInteractorImplTest.kt | 48 +++++++++++ .../repository/FakeRetailModeRepository.kt | 36 ++++++++ 12 files changed, 420 insertions(+), 2 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt create mode 100644 packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt create mode 100644 packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt create mode 100644 packages/SystemUI/tests/utils/src/com/android/systemui/retail/data/repository/FakeRetailModeRepository.kt diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 75f70ae8eb7aa..06ac596b89d33 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -66,6 +66,7 @@ import com.android.systemui.qs.FgsManagerControllerImpl; import com.android.systemui.qs.QSFragmentStartableModule; import com.android.systemui.qs.footer.dagger.FooterActionsModule; import com.android.systemui.recents.Recents; +import com.android.systemui.retail.dagger.RetailModeModule; import com.android.systemui.screenrecord.ScreenRecordModule; import com.android.systemui.screenshot.dagger.ScreenshotModule; import com.android.systemui.security.data.repository.SecurityRepositoryModule; @@ -170,6 +171,7 @@ import javax.inject.Named; PrivacyModule.class, QRCodeScannerModule.class, QSFragmentStartableModule.class, + RetailModeModule.class, ScreenshotModule.class, SensorModule.class, SecurityRepositoryModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java index 0d29a1abca9fb..85f557b107623 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java @@ -27,6 +27,7 @@ import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.qs.dagger.QSScope; +import com.android.systemui.retail.domain.interactor.RetailModeInteractor; import com.android.systemui.settings.UserTracker; import com.android.systemui.util.ViewController; @@ -45,18 +46,22 @@ public class QSFooterViewController extends ViewController impleme private final View mEditButton; private final FalsingManager mFalsingManager; private final ActivityStarter mActivityStarter; + private final RetailModeInteractor mRetailModeInteractor; @Inject QSFooterViewController(QSFooterView view, UserTracker userTracker, FalsingManager falsingManager, ActivityStarter activityStarter, - QSPanelController qsPanelController) { + QSPanelController qsPanelController, + RetailModeInteractor retailModeInteractor + ) { super(view); mUserTracker = userTracker; mQsPanelController = qsPanelController; mFalsingManager = falsingManager; mActivityStarter = activityStarter; + mRetailModeInteractor = retailModeInteractor; mBuildText = mView.findViewById(R.id.build); mPageIndicator = mView.findViewById(R.id.footer_page_indicator); @@ -96,6 +101,8 @@ public class QSFooterViewController extends ViewController impleme @Override public void setVisibility(int visibility) { mView.setVisibility(visibility); + mEditButton + .setVisibility(mRetailModeInteractor.isInRetailMode() ? View.GONE : View.VISIBLE); mEditButton.setClickable(visibility == View.VISIBLE); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt index 595b29a9dcb84..3b2362f2b3260 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt @@ -20,6 +20,7 @@ import android.annotation.UserIdInt import android.content.res.Resources import android.database.ContentObserver import android.provider.Settings +import com.android.systemui.R import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background @@ -27,12 +28,16 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.qs.QSHost import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger +import com.android.systemui.retail.data.repository.RetailModeRepository import com.android.systemui.util.settings.SecureSettings import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -84,6 +89,9 @@ interface TileSpecRepository { * [Settings.Secure.QS_TILES]. * * All operations against [Settings] will be performed in a background thread. + * + * If the device is in retail mode, the tiles are fixed to the value of + * [R.string.quick_settings_tiles_retail_mode]. */ @SysUISingleton class TileSpecSettingsRepository @@ -92,9 +100,31 @@ constructor( private val secureSettings: SecureSettings, @Main private val resources: Resources, private val logger: QSPipelineLogger, + private val retailModeRepository: RetailModeRepository, @Background private val backgroundDispatcher: CoroutineDispatcher, ) : TileSpecRepository { + + private val retailModeTiles by lazy { + resources + .getString(R.string.quick_settings_tiles_retail_mode) + .split(DELIMITER) + .map(TileSpec::create) + .filter { it !is TileSpec.Invalid } + } + + @OptIn(ExperimentalCoroutinesApi::class) override fun tilesSpecs(userId: Int): Flow> { + return retailModeRepository.retailMode.flatMapLatest { inRetailMode -> + if (inRetailMode) { + logger.logUsingRetailTiles() + flowOf(retailModeTiles) + } else { + settingsTiles(userId) + } + } + } + + private fun settingsTiles(userId: Int): Flow> { return conflatedCallbackFlow { val observer = object : ContentObserver(null) { @@ -157,6 +187,10 @@ constructor( } private suspend fun storeTiles(@UserIdInt forUser: Int, tiles: List) { + if (retailModeRepository.inRetailMode) { + // No storing tiles when in retail mode + return + } val toStore = tiles .filter { it !is TileSpec.Invalid } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt index 767ce919d027b..319dbf85c414d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt @@ -120,6 +120,10 @@ constructor( ) } + fun logUsingRetailTiles() { + tileListLogBuffer.log(TILE_LIST_TAG, LogLevel.DEBUG, {}, { "Using retail tiles" }) + } + /** Reasons for destroying an existing tile. */ enum class TileDestroyedReason(val readable: String) { TILE_REMOVED("Tile removed from current set"), diff --git a/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt b/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt new file mode 100644 index 0000000000000..e8639498b7c01 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.retail.dagger + +import com.android.systemui.retail.data.repository.RetailModeRepository +import com.android.systemui.retail.data.repository.RetailModeSettingsRepository +import com.android.systemui.retail.domain.interactor.RetailModeInteractor +import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl +import dagger.Binds +import dagger.Module + +@Module +abstract class RetailModeModule { + + @Binds + abstract fun bindsRetailModeRepository(impl: RetailModeSettingsRepository): RetailModeRepository + + @Binds + abstract fun bindsRetailModeInteractor(impl: RetailModeInteractorImpl): RetailModeInteractor +} diff --git a/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt b/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt new file mode 100644 index 0000000000000..3c0aa384d98c4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.retail.data.repository + +import android.database.ContentObserver +import android.provider.Settings +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.util.settings.GlobalSettings +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn + +/** Repository to track if the device is in Retail mode */ +interface RetailModeRepository { + /** Flow of whether the device is currently in retail mode. */ + val retailMode: StateFlow + + /** Last value of whether the device is in retail mode. */ + val inRetailMode: Boolean + get() = retailMode.value +} + +/** + * Tracks [Settings.Global.DEVICE_DEMO_MODE]. + * + * @see UserManager.isDeviceInDemoMode + */ +@SysUISingleton +class RetailModeSettingsRepository +@Inject +constructor( + globalSettings: GlobalSettings, + @Background backgroundDispatcher: CoroutineDispatcher, + @Application scope: CoroutineScope, +) : RetailModeRepository { + override val retailMode = + conflatedCallbackFlow { + val observer = + object : ContentObserver(null) { + override fun onChange(selfChange: Boolean) { + trySend(Unit) + } + } + + globalSettings.registerContentObserver(RETAIL_MODE_SETTING, observer) + + awaitClose { globalSettings.unregisterContentObserver(observer) } + } + .onStart { emit(Unit) } + .map { globalSettings.getInt(RETAIL_MODE_SETTING, 0) != 0 } + .flowOn(backgroundDispatcher) + .stateIn(scope, SharingStarted.Eagerly, false) + + companion object { + private const val RETAIL_MODE_SETTING = Settings.Global.DEVICE_DEMO_MODE + } +} diff --git a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt new file mode 100644 index 0000000000000..eea452c78ea57 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.retail.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.retail.data.repository.RetailModeRepository +import javax.inject.Inject + +/** Interactor to determine if the device is currently in retail mode */ +interface RetailModeInteractor { + /** Whether the device is currently in retail mode */ + val isInRetailMode: Boolean +} + +@SysUISingleton +class RetailModeInteractorImpl +@Inject +constructor( + private val repository: RetailModeRepository, +) : RetailModeInteractor { + override val isInRetailMode: Boolean + get() = repository.inRetailMode +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java index 26aa37df0c0b1..d9db60d770777 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java @@ -37,6 +37,8 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.retail.data.repository.FakeRetailModeRepository; +import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.utils.leaks.LeakCheckedTest; @@ -67,6 +69,8 @@ public class QSFooterViewControllerTest extends LeakCheckedTest { @Mock private ActivityStarter mActivityStarter; + private FakeRetailModeRepository mRetailModeRepository; + private QSFooterViewController mController; private View mEditButton; @@ -74,6 +78,9 @@ public class QSFooterViewControllerTest extends LeakCheckedTest { public void setup() throws Exception { MockitoAnnotations.initMocks(this); + mRetailModeRepository = new FakeRetailModeRepository(); + mRetailModeRepository.setRetailMode(false); + mEditButton = new View(mContext); injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); @@ -89,7 +96,8 @@ public class QSFooterViewControllerTest extends LeakCheckedTest { when(mView.findViewById(android.R.id.edit)).thenReturn(mEditButton); mController = new QSFooterViewController(mView, mUserTracker, mFalsingManager, - mActivityStarter, mQSPanelController); + mActivityStarter, mQSPanelController, + new RetailModeInteractorImpl(mRetailModeRepository)); mController.init(); } @@ -132,4 +140,20 @@ public class QSFooterViewControllerTest extends LeakCheckedTest { captor.getValue().run(); verify(mQSPanelController).showEdit(mEditButton); } + + @Test + public void testEditButton_notRetailMode_visible() { + mRetailModeRepository.setRetailMode(false); + + mController.setVisibility(View.VISIBLE); + assertThat(mEditButton.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void testEditButton_retailMode_notVisible() { + mRetailModeRepository.setRetailMode(true); + + mController.setVisibility(View.VISIBLE); + assertThat(mEditButton.getVisibility()).isEqualTo(View.GONE); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt index 50a8d2630d797..fda63ed3bede9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt @@ -25,6 +25,7 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.qs.QSHost import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger +import com.android.systemui.retail.data.repository.FakeRetailModeRepository import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -44,6 +45,7 @@ import org.mockito.MockitoAnnotations class TileSpecSettingsRepositoryTest : SysuiTestCase() { private lateinit var secureSettings: FakeSettings + private lateinit var retailModeRepository: FakeRetailModeRepository @Mock private lateinit var logger: QSPipelineLogger @@ -57,9 +59,12 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) secureSettings = FakeSettings() + retailModeRepository = FakeRetailModeRepository() + retailModeRepository.setRetailMode(false) with(context.orCreateTestableResources) { addOverride(R.string.quick_settings_tiles_default, DEFAULT_TILES) + addOverride(R.string.quick_settings_tiles_retail_mode, RETAIL_TILES) } underTest = @@ -67,6 +72,7 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { secureSettings, context.resources, logger, + retailModeRepository, testDispatcher, ) } @@ -346,6 +352,26 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { assertThat(tiles).isEqualTo("b".toTileSpecs()) } + @Test + fun retailMode_usesRetailTiles() = + testScope.runTest { + retailModeRepository.setRetailMode(true) + + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + assertThat(tiles).isEqualTo(RETAIL_TILES.toTileSpecs()) + } + + @Test + fun retailMode_cannotModifyTiles() = + testScope.runTest { + retailModeRepository.setRetailMode(true) + + underTest.setTiles(0, DEFAULT_TILES.toTileSpecs()) + + assertThat(loadTilesForUser(0)).isNull() + } + private fun getDefaultTileSpecs(): List { return QSHost.getDefaultSpecs(context.resources).map(TileSpec::create) } @@ -360,6 +386,7 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { companion object { private const val DEFAULT_TILES = "a,b,c" + private const val RETAIL_TILES = "d" private const val SETTING = Settings.Secure.QS_TILES private fun String.toTileSpecs(): List { diff --git a/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt new file mode 100644 index 0000000000000..d7682b20a98de --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.retail.data.repository + +import android.provider.Settings +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.util.settings.FakeSettings +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidTestingRunner::class) +class RetailModeSettingsRepositoryTest : SysuiTestCase() { + + private val globalSettings = FakeSettings() + + private val testDispatcher = StandardTestDispatcher() + private val testScope = TestScope(testDispatcher) + + private val underTest = + RetailModeSettingsRepository( + globalSettings, + backgroundDispatcher = testDispatcher, + scope = testScope.backgroundScope, + ) + + @Test + fun retailMode_defaultFalse() = + testScope.runTest { + val value by collectLastValue(underTest.retailMode) + + assertThat(value).isFalse() + assertThat(underTest.inRetailMode).isFalse() + } + + @Test + fun retailMode_false() = + testScope.runTest { + val value by collectLastValue(underTest.retailMode) + + globalSettings.putInt(SETTING, 0) + + assertThat(value).isFalse() + assertThat(underTest.inRetailMode).isFalse() + } + + @Test + fun retailMode_true() = + testScope.runTest { + val value by collectLastValue(underTest.retailMode) + + globalSettings.putInt(SETTING, 1) + + assertThat(value).isTrue() + assertThat(underTest.inRetailMode).isTrue() + } + + companion object { + private const val SETTING = Settings.Global.DEVICE_DEMO_MODE + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt new file mode 100644 index 0000000000000..8f131696f815e --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.retail.domain.interactor + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.retail.data.repository.FakeRetailModeRepository +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class RetailModeInteractorImplTest : SysuiTestCase() { + + private val retailModeRepository = FakeRetailModeRepository() + + private val underTest = RetailModeInteractorImpl(retailModeRepository) + + @Test + fun retailMode_false() { + retailModeRepository.setRetailMode(false) + + assertThat(underTest.isInRetailMode).isFalse() + } + + @Test + fun retailMode_true() { + retailModeRepository.setRetailMode(true) + + assertThat(underTest.isInRetailMode).isTrue() + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/retail/data/repository/FakeRetailModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/retail/data/repository/FakeRetailModeRepository.kt new file mode 100644 index 0000000000000..75b29cac10685 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/retail/data/repository/FakeRetailModeRepository.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.retail.data.repository + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeRetailModeRepository : RetailModeRepository { + + private val _retailMode = MutableStateFlow(false) + override val retailMode: StateFlow = _retailMode.asStateFlow() + + private var _retailModeValue = false + override val inRetailMode: Boolean + get() = _retailModeValue + + fun setRetailMode(value: Boolean) { + _retailMode.value = value + _retailModeValue = value + } +}