Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt 0 → 100644 +95 −0 Original line number Diff line number Diff line /* * 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.qs.pipeline.data.restoreprocessors import android.os.UserHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.shared.TileSpec import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) @OptIn(ExperimentalCoroutinesApi::class) class WorkTileRestoreProcessorTest : SysuiTestCase() { private val underTest = WorkTileRestoreProcessor() @Test fun restoreWithWorkTile_removeTracking() = runTest { val removeTracking by collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER))) runCurrent() val restoreData = RestoreData( restoredTiles = listOf(TILE_SPEC), restoredAutoAddedTiles = setOf(TILE_SPEC), USER, ) underTest.postProcessRestore(restoreData) assertThat(removeTracking).isEqualTo(Unit) } @Test fun restoreWithWorkTile_otherUser_noRemoveTracking() = runTest { val removeTracking by collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER + 1))) runCurrent() val restoreData = RestoreData( restoredTiles = listOf(TILE_SPEC), restoredAutoAddedTiles = setOf(TILE_SPEC), USER, ) underTest.postProcessRestore(restoreData) assertThat(removeTracking).isNull() } @Test fun restoreWithoutWorkTile_noSignal() = runTest { val removeTracking by collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER))) runCurrent() val restoreData = RestoreData( restoredTiles = emptyList(), restoredAutoAddedTiles = emptySet(), USER, ) underTest.postProcessRestore(restoreData) assertThat(removeTracking).isNull() } companion object { private const val USER = 10 private val TILE_SPEC = TileSpec.Companion.create("work") } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt +82 −4 Original line number Diff line number Diff line Loading @@ -25,6 +25,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.data.model.RestoreProcessor import com.android.systemui.qs.pipeline.data.model.workTileRestoreProcessor import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking import com.android.systemui.qs.pipeline.shared.TileSpec Loading @@ -32,25 +37,28 @@ import com.android.systemui.qs.tiles.WorkModeTile import com.android.systemui.settings.FakeUserTracker import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class WorkTileAutoAddableTest : SysuiTestCase() { private val kosmos = Kosmos() private val restoreProcessor: RestoreProcessor get() = kosmos.workTileRestoreProcessor private lateinit var userTracker: FakeUserTracker private lateinit var underTest: WorkTileAutoAddable @Before fun setup() { MockitoAnnotations.initMocks(this) userTracker = FakeUserTracker( _userId = USER_INFO_0.id, Loading @@ -58,7 +66,7 @@ class WorkTileAutoAddableTest : SysuiTestCase() { _userProfiles = listOf(USER_INFO_0) ) underTest = WorkTileAutoAddable(userTracker) underTest = WorkTileAutoAddable(userTracker, kosmos.workTileRestoreProcessor) } @Test Loading Loading @@ -114,10 +122,80 @@ class WorkTileAutoAddableTest : SysuiTestCase() { assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Always) } @Test fun restoreDataWithWorkTile_noCurrentManagedProfile_triggersRemove() = runTest { val userId = 0 val signal by collectLastValue(underTest.autoAddSignal(userId)) runCurrent() val restoreData = createRestoreWithWorkTile(userId) restoreProcessor.postProcessRestore(restoreData) assertThat(signal!!).isEqualTo(AutoAddSignal.RemoveTracking(SPEC)) } @Test fun restoreDataWithWorkTile_currentlyManagedProfile_doesntTriggerRemove() = runTest { userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0) val userId = 0 val signals by collectValues(underTest.autoAddSignal(userId)) runCurrent() val restoreData = createRestoreWithWorkTile(userId) restoreProcessor.postProcessRestore(restoreData) assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC)) } @Test fun restoreDataWithoutWorkTile_noManagedProfile_doesntTriggerRemove() = runTest { val userId = 0 val signals by collectValues(underTest.autoAddSignal(userId)) runCurrent() val restoreData = createRestoreWithoutWorkTile(userId) restoreProcessor.postProcessRestore(restoreData) assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC)) } @Test fun restoreDataWithoutWorkTile_managedProfile_doesntTriggerRemove() = runTest { userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0) val userId = 0 val signals by collectValues(underTest.autoAddSignal(userId)) runCurrent() val restoreData = createRestoreWithoutWorkTile(userId) restoreProcessor.postProcessRestore(restoreData) assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC)) } companion object { private val SPEC = TileSpec.create(WorkModeTile.TILE_SPEC) private val USER_INFO_0 = UserInfo(0, "", FLAG_PRIMARY or FLAG_FULL) private val USER_INFO_1 = UserInfo(1, "", FLAG_FULL) private val USER_INFO_WORK = UserInfo(10, "", FLAG_PROFILE or FLAG_MANAGED_PROFILE) private fun createRestoreWithWorkTile(userId: Int): RestoreData { return RestoreData( listOf(TileSpec.create("a"), SPEC, TileSpec.create("b")), setOf(SPEC), userId, ) } private fun createRestoreWithoutWorkTile(userId: Int): RestoreData { return RestoreData( listOf(TileSpec.create("a"), TileSpec.create("b")), emptySet(), userId, ) } } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt +16 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,22 @@ class AutoAddInteractorTest : SysuiTestCase() { assertThat(autoAddedTiles).contains(SPEC) } @Test fun autoAddable_removeTrackingSignal_notRemovedButUnmarked() = testScope.runTest { autoAddRepository.markTileAdded(USER, SPEC) val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER)) val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Always) underTest = createInteractor(setOf(fakeAutoAddable)) fakeAutoAddable.sendRemoveTrackingSignal(USER) runCurrent() verify(currentTilesInteractor, never()).removeTiles(any()) assertThat(autoAddedTiles).doesNotContain(SPEC) } private fun createInteractor(autoAddables: Set<AutoAddable>): AutoAddInteractor { return AutoAddInteractor( autoAddables, Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt +49 −3 Original line number Diff line number Diff line Loading @@ -5,10 +5,15 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.data.model.RestoreProcessor import com.android.systemui.qs.pipeline.data.repository.FakeAutoAddRepository import com.android.systemui.qs.pipeline.data.repository.FakeQSSettingsRestoredRepository import com.android.systemui.qs.pipeline.data.repository.FakeTileSpecRepository import com.android.systemui.qs.pipeline.data.repository.TilesSettingConverter import com.android.systemui.qs.pipeline.domain.interactor.RestoreReconciliationInteractorTest.TestableRestoreProcessor.Companion.POSTPROCESS import com.android.systemui.qs.pipeline.domain.interactor.RestoreReconciliationInteractorTest.TestableRestoreProcessor.Companion.PREPROCESS import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope Loading @@ -17,7 +22,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.MockitoAnnotations import org.mockito.Mockito.inOrder @RunWith(AndroidJUnit4::class) @SmallTest Loading @@ -28,6 +33,9 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() { private val qsSettingsRestoredRepository = FakeQSSettingsRestoredRepository() private val restoreProcessor: TestableRestoreProcessor = TestableRestoreProcessor() private val qsLogger: QSPipelineLogger = mock() private lateinit var underTest: RestoreReconciliationInteractor private val testDispatcher = StandardTestDispatcher() Loading @@ -35,13 +43,13 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) underTest = RestoreReconciliationInteractor( tileSpecRepository, autoAddRepository, qsSettingsRestoredRepository, setOf(restoreProcessor), qsLogger, testScope.backgroundScope, testDispatcher ) Loading Loading @@ -85,6 +93,44 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() { assertThat(autoAdd).isEqualTo(expectedAutoAdd.toTilesSet()) } @Test fun restoreProcessorsCalled() = testScope.runTest { val user = 10 val restoredSpecs = "a,c,d,f" val restoredAutoAdded = "d,e" val restoreData = RestoreData( restoredSpecs.toTilesList(), restoredAutoAdded.toTilesSet(), user, ) qsSettingsRestoredRepository.onDataRestored(restoreData) runCurrent() assertThat(restoreProcessor.calls).containsExactly(PREPROCESS, POSTPROCESS).inOrder() } private class TestableRestoreProcessor : RestoreProcessor { val calls = mutableListOf<Any>() override suspend fun preProcessRestore(restoreData: RestoreData) { calls.add(PREPROCESS) } override suspend fun postProcessRestore(restoreData: RestoreData) { calls.add(POSTPROCESS) } companion object { val PREPROCESS = Any() val POSTPROCESS = Any() } } companion object { private fun String.toTilesList() = TilesSettingConverter.toTilesList(this) private fun String.toTilesSet() = TilesSettingConverter.toTilesSet(this) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/WorkProfileAutoAddedAfterRestoreTest.kt 0 → 100644 +176 −0 Original line number Diff line number Diff line /* * 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.qs.pipeline.domain.interactor import android.content.pm.UserInfo import android.os.UserManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import com.android.systemui.Flags.FLAG_QS_NEW_PIPELINE import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.qs.QSTile import com.android.systemui.qs.FakeQSFactory import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.data.repository.fakeRestoreRepository import com.android.systemui.qs.pipeline.data.repository.fakeTileSpecRepository import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.qsTileFactory import com.android.systemui.settings.fakeUserTracker import com.android.systemui.settings.userTracker import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith /** * This integration test is for testing the solution to b/314781280. In particular, there are two * issues we want to verify after a restore of a device with a work profile and a work mode tile: * * When the work profile is re-enabled in the target device, it is auto-added. * * The tile is auto-added in the same position that it was in the restored device. */ @MediumTest @RunWith(AndroidJUnit4::class) @OptIn(ExperimentalCoroutinesApi::class) class WorkProfileAutoAddedAfterRestoreTest : SysuiTestCase() { private val kosmos = Kosmos().apply { fakeUserTracker.set(listOf(USER_0_INFO), 0) } // Getter here so it can change when there is a managed profile. private val workTileAvailable: Boolean get() = hasManagedProfile() private val currentUser: Int get() = kosmos.userTracker.userId private val testScope: TestScope get() = kosmos.testScope @Before fun setUp() { mSetFlagsRule.enableFlags(FLAG_QS_NEW_PIPELINE) kosmos.qsTileFactory = FakeQSFactory(::tileCreator) kosmos.restoreReconciliationInteractor.start() kosmos.autoAddInteractor.init(kosmos.currentTilesInteractor) } @Test fun workTileRestoredAndPreviouslyAutoAdded_notAvailable_willBeAutoaddedInCorrectPosition() = testScope.runTest { val tiles by collectLastValue(kosmos.currentTilesInteractor.currentTiles) // Set up val currentTiles = listOf("a".toTileSpec()) kosmos.fakeTileSpecRepository.setTiles(currentUser, currentTiles) val restoredTiles = listOf(WORK_TILE_SPEC) + listOf("b", "c", "d").map { it.toTileSpec() } val restoredAutoAdded = setOf(WORK_TILE_SPEC) val restoreData = RestoreData(restoredTiles, restoredAutoAdded, currentUser) // WHEN we restore tiles that auto-added the WORK tile and it's not available (there // are no managed profiles) kosmos.fakeRestoreRepository.onDataRestored(restoreData) // THEN the work tile is not part of the current tiles assertThat(tiles!!).hasSize(3) assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC) // WHEN we add a work profile createManagedProfileAndAdd() // THEN the work profile is added in the correct place assertThat(tiles!!.first().spec).isEqualTo(WORK_TILE_SPEC) } @Test fun workTileNotRestoredAndPreviouslyAutoAdded_wontBeAutoAddedWhenWorkProfileIsAdded() = testScope.runTest { val tiles by collectLastValue(kosmos.currentTilesInteractor.currentTiles) // Set up val currentTiles = listOf("a".toTileSpec()) kosmos.fakeTileSpecRepository.setTiles(currentUser, currentTiles) runCurrent() val restoredTiles = listOf("b", "c", "d").map { it.toTileSpec() } val restoredAutoAdded = setOf(WORK_TILE_SPEC) val restoreData = RestoreData(restoredTiles, restoredAutoAdded, currentUser) // WHEN we restore tiles that auto-added the WORK tile kosmos.fakeRestoreRepository.onDataRestored(restoreData) // THEN the work tile is not part of the current tiles assertThat(tiles!!).hasSize(3) assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC) // WHEN we add a work profile createManagedProfileAndAdd() // THEN the work profile is not added because the user had manually removed it in the // past assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC) } private fun tileCreator(spec: String): QSTile { return if (spec == WORK_TILE_SPEC.spec) { FakeQSTile(currentUser, workTileAvailable) } else { FakeQSTile(currentUser) } } private fun hasManagedProfile(): Boolean { return kosmos.userTracker.userProfiles.any { it.isManagedProfile } } private fun TestScope.createManagedProfileAndAdd() { kosmos.fakeUserTracker.set( listOf(USER_0_INFO, MANAGED_USER_INFO), 0, ) runCurrent() } private companion object { val WORK_TILE_SPEC = "work".toTileSpec() val USER_0_INFO = UserInfo( 0, "zero", "", UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL, ) val MANAGED_USER_INFO = UserInfo( 10, "ten-managed", "", 0, UserManager.USER_TYPE_PROFILE_MANAGED, ) fun String.toTileSpec() = TileSpec.create(this) } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt 0 → 100644 +95 −0 Original line number Diff line number Diff line /* * 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.qs.pipeline.data.restoreprocessors import android.os.UserHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.shared.TileSpec import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) @OptIn(ExperimentalCoroutinesApi::class) class WorkTileRestoreProcessorTest : SysuiTestCase() { private val underTest = WorkTileRestoreProcessor() @Test fun restoreWithWorkTile_removeTracking() = runTest { val removeTracking by collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER))) runCurrent() val restoreData = RestoreData( restoredTiles = listOf(TILE_SPEC), restoredAutoAddedTiles = setOf(TILE_SPEC), USER, ) underTest.postProcessRestore(restoreData) assertThat(removeTracking).isEqualTo(Unit) } @Test fun restoreWithWorkTile_otherUser_noRemoveTracking() = runTest { val removeTracking by collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER + 1))) runCurrent() val restoreData = RestoreData( restoredTiles = listOf(TILE_SPEC), restoredAutoAddedTiles = setOf(TILE_SPEC), USER, ) underTest.postProcessRestore(restoreData) assertThat(removeTracking).isNull() } @Test fun restoreWithoutWorkTile_noSignal() = runTest { val removeTracking by collectLastValue(underTest.removeTrackingForUser(UserHandle.of(USER))) runCurrent() val restoreData = RestoreData( restoredTiles = emptyList(), restoredAutoAddedTiles = emptySet(), USER, ) underTest.postProcessRestore(restoreData) assertThat(removeTracking).isNull() } companion object { private const val USER = 10 private val TILE_SPEC = TileSpec.Companion.create("work") } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt +82 −4 Original line number Diff line number Diff line Loading @@ -25,6 +25,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.data.model.RestoreProcessor import com.android.systemui.qs.pipeline.data.model.workTileRestoreProcessor import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking import com.android.systemui.qs.pipeline.shared.TileSpec Loading @@ -32,25 +37,28 @@ import com.android.systemui.qs.tiles.WorkModeTile import com.android.systemui.settings.FakeUserTracker import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class WorkTileAutoAddableTest : SysuiTestCase() { private val kosmos = Kosmos() private val restoreProcessor: RestoreProcessor get() = kosmos.workTileRestoreProcessor private lateinit var userTracker: FakeUserTracker private lateinit var underTest: WorkTileAutoAddable @Before fun setup() { MockitoAnnotations.initMocks(this) userTracker = FakeUserTracker( _userId = USER_INFO_0.id, Loading @@ -58,7 +66,7 @@ class WorkTileAutoAddableTest : SysuiTestCase() { _userProfiles = listOf(USER_INFO_0) ) underTest = WorkTileAutoAddable(userTracker) underTest = WorkTileAutoAddable(userTracker, kosmos.workTileRestoreProcessor) } @Test Loading Loading @@ -114,10 +122,80 @@ class WorkTileAutoAddableTest : SysuiTestCase() { assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Always) } @Test fun restoreDataWithWorkTile_noCurrentManagedProfile_triggersRemove() = runTest { val userId = 0 val signal by collectLastValue(underTest.autoAddSignal(userId)) runCurrent() val restoreData = createRestoreWithWorkTile(userId) restoreProcessor.postProcessRestore(restoreData) assertThat(signal!!).isEqualTo(AutoAddSignal.RemoveTracking(SPEC)) } @Test fun restoreDataWithWorkTile_currentlyManagedProfile_doesntTriggerRemove() = runTest { userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0) val userId = 0 val signals by collectValues(underTest.autoAddSignal(userId)) runCurrent() val restoreData = createRestoreWithWorkTile(userId) restoreProcessor.postProcessRestore(restoreData) assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC)) } @Test fun restoreDataWithoutWorkTile_noManagedProfile_doesntTriggerRemove() = runTest { val userId = 0 val signals by collectValues(underTest.autoAddSignal(userId)) runCurrent() val restoreData = createRestoreWithoutWorkTile(userId) restoreProcessor.postProcessRestore(restoreData) assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC)) } @Test fun restoreDataWithoutWorkTile_managedProfile_doesntTriggerRemove() = runTest { userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0) val userId = 0 val signals by collectValues(underTest.autoAddSignal(userId)) runCurrent() val restoreData = createRestoreWithoutWorkTile(userId) restoreProcessor.postProcessRestore(restoreData) assertThat(signals).doesNotContain(AutoAddSignal.RemoveTracking(SPEC)) } companion object { private val SPEC = TileSpec.create(WorkModeTile.TILE_SPEC) private val USER_INFO_0 = UserInfo(0, "", FLAG_PRIMARY or FLAG_FULL) private val USER_INFO_1 = UserInfo(1, "", FLAG_FULL) private val USER_INFO_WORK = UserInfo(10, "", FLAG_PROFILE or FLAG_MANAGED_PROFILE) private fun createRestoreWithWorkTile(userId: Int): RestoreData { return RestoreData( listOf(TileSpec.create("a"), SPEC, TileSpec.create("b")), setOf(SPEC), userId, ) } private fun createRestoreWithoutWorkTile(userId: Int): RestoreData { return RestoreData( listOf(TileSpec.create("a"), TileSpec.create("b")), emptySet(), userId, ) } } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt +16 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,22 @@ class AutoAddInteractorTest : SysuiTestCase() { assertThat(autoAddedTiles).contains(SPEC) } @Test fun autoAddable_removeTrackingSignal_notRemovedButUnmarked() = testScope.runTest { autoAddRepository.markTileAdded(USER, SPEC) val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER)) val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Always) underTest = createInteractor(setOf(fakeAutoAddable)) fakeAutoAddable.sendRemoveTrackingSignal(USER) runCurrent() verify(currentTilesInteractor, never()).removeTiles(any()) assertThat(autoAddedTiles).doesNotContain(SPEC) } private fun createInteractor(autoAddables: Set<AutoAddable>): AutoAddInteractor { return AutoAddInteractor( autoAddables, Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt +49 −3 Original line number Diff line number Diff line Loading @@ -5,10 +5,15 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.data.model.RestoreProcessor import com.android.systemui.qs.pipeline.data.repository.FakeAutoAddRepository import com.android.systemui.qs.pipeline.data.repository.FakeQSSettingsRestoredRepository import com.android.systemui.qs.pipeline.data.repository.FakeTileSpecRepository import com.android.systemui.qs.pipeline.data.repository.TilesSettingConverter import com.android.systemui.qs.pipeline.domain.interactor.RestoreReconciliationInteractorTest.TestableRestoreProcessor.Companion.POSTPROCESS import com.android.systemui.qs.pipeline.domain.interactor.RestoreReconciliationInteractorTest.TestableRestoreProcessor.Companion.PREPROCESS import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope Loading @@ -17,7 +22,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.MockitoAnnotations import org.mockito.Mockito.inOrder @RunWith(AndroidJUnit4::class) @SmallTest Loading @@ -28,6 +33,9 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() { private val qsSettingsRestoredRepository = FakeQSSettingsRestoredRepository() private val restoreProcessor: TestableRestoreProcessor = TestableRestoreProcessor() private val qsLogger: QSPipelineLogger = mock() private lateinit var underTest: RestoreReconciliationInteractor private val testDispatcher = StandardTestDispatcher() Loading @@ -35,13 +43,13 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) underTest = RestoreReconciliationInteractor( tileSpecRepository, autoAddRepository, qsSettingsRestoredRepository, setOf(restoreProcessor), qsLogger, testScope.backgroundScope, testDispatcher ) Loading Loading @@ -85,6 +93,44 @@ class RestoreReconciliationInteractorTest : SysuiTestCase() { assertThat(autoAdd).isEqualTo(expectedAutoAdd.toTilesSet()) } @Test fun restoreProcessorsCalled() = testScope.runTest { val user = 10 val restoredSpecs = "a,c,d,f" val restoredAutoAdded = "d,e" val restoreData = RestoreData( restoredSpecs.toTilesList(), restoredAutoAdded.toTilesSet(), user, ) qsSettingsRestoredRepository.onDataRestored(restoreData) runCurrent() assertThat(restoreProcessor.calls).containsExactly(PREPROCESS, POSTPROCESS).inOrder() } private class TestableRestoreProcessor : RestoreProcessor { val calls = mutableListOf<Any>() override suspend fun preProcessRestore(restoreData: RestoreData) { calls.add(PREPROCESS) } override suspend fun postProcessRestore(restoreData: RestoreData) { calls.add(POSTPROCESS) } companion object { val PREPROCESS = Any() val POSTPROCESS = Any() } } companion object { private fun String.toTilesList() = TilesSettingConverter.toTilesList(this) private fun String.toTilesSet() = TilesSettingConverter.toTilesSet(this) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/WorkProfileAutoAddedAfterRestoreTest.kt 0 → 100644 +176 −0 Original line number Diff line number Diff line /* * 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.qs.pipeline.domain.interactor import android.content.pm.UserInfo import android.os.UserManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import com.android.systemui.Flags.FLAG_QS_NEW_PIPELINE import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.qs.QSTile import com.android.systemui.qs.FakeQSFactory import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.data.repository.fakeRestoreRepository import com.android.systemui.qs.pipeline.data.repository.fakeTileSpecRepository import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.qsTileFactory import com.android.systemui.settings.fakeUserTracker import com.android.systemui.settings.userTracker import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith /** * This integration test is for testing the solution to b/314781280. In particular, there are two * issues we want to verify after a restore of a device with a work profile and a work mode tile: * * When the work profile is re-enabled in the target device, it is auto-added. * * The tile is auto-added in the same position that it was in the restored device. */ @MediumTest @RunWith(AndroidJUnit4::class) @OptIn(ExperimentalCoroutinesApi::class) class WorkProfileAutoAddedAfterRestoreTest : SysuiTestCase() { private val kosmos = Kosmos().apply { fakeUserTracker.set(listOf(USER_0_INFO), 0) } // Getter here so it can change when there is a managed profile. private val workTileAvailable: Boolean get() = hasManagedProfile() private val currentUser: Int get() = kosmos.userTracker.userId private val testScope: TestScope get() = kosmos.testScope @Before fun setUp() { mSetFlagsRule.enableFlags(FLAG_QS_NEW_PIPELINE) kosmos.qsTileFactory = FakeQSFactory(::tileCreator) kosmos.restoreReconciliationInteractor.start() kosmos.autoAddInteractor.init(kosmos.currentTilesInteractor) } @Test fun workTileRestoredAndPreviouslyAutoAdded_notAvailable_willBeAutoaddedInCorrectPosition() = testScope.runTest { val tiles by collectLastValue(kosmos.currentTilesInteractor.currentTiles) // Set up val currentTiles = listOf("a".toTileSpec()) kosmos.fakeTileSpecRepository.setTiles(currentUser, currentTiles) val restoredTiles = listOf(WORK_TILE_SPEC) + listOf("b", "c", "d").map { it.toTileSpec() } val restoredAutoAdded = setOf(WORK_TILE_SPEC) val restoreData = RestoreData(restoredTiles, restoredAutoAdded, currentUser) // WHEN we restore tiles that auto-added the WORK tile and it's not available (there // are no managed profiles) kosmos.fakeRestoreRepository.onDataRestored(restoreData) // THEN the work tile is not part of the current tiles assertThat(tiles!!).hasSize(3) assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC) // WHEN we add a work profile createManagedProfileAndAdd() // THEN the work profile is added in the correct place assertThat(tiles!!.first().spec).isEqualTo(WORK_TILE_SPEC) } @Test fun workTileNotRestoredAndPreviouslyAutoAdded_wontBeAutoAddedWhenWorkProfileIsAdded() = testScope.runTest { val tiles by collectLastValue(kosmos.currentTilesInteractor.currentTiles) // Set up val currentTiles = listOf("a".toTileSpec()) kosmos.fakeTileSpecRepository.setTiles(currentUser, currentTiles) runCurrent() val restoredTiles = listOf("b", "c", "d").map { it.toTileSpec() } val restoredAutoAdded = setOf(WORK_TILE_SPEC) val restoreData = RestoreData(restoredTiles, restoredAutoAdded, currentUser) // WHEN we restore tiles that auto-added the WORK tile kosmos.fakeRestoreRepository.onDataRestored(restoreData) // THEN the work tile is not part of the current tiles assertThat(tiles!!).hasSize(3) assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC) // WHEN we add a work profile createManagedProfileAndAdd() // THEN the work profile is not added because the user had manually removed it in the // past assertThat(tiles!!.map { it.spec }).doesNotContain(WORK_TILE_SPEC) } private fun tileCreator(spec: String): QSTile { return if (spec == WORK_TILE_SPEC.spec) { FakeQSTile(currentUser, workTileAvailable) } else { FakeQSTile(currentUser) } } private fun hasManagedProfile(): Boolean { return kosmos.userTracker.userProfiles.any { it.isManagedProfile } } private fun TestScope.createManagedProfileAndAdd() { kosmos.fakeUserTracker.set( listOf(USER_0_INFO, MANAGED_USER_INFO), 0, ) runCurrent() } private companion object { val WORK_TILE_SPEC = "work".toTileSpec() val USER_0_INFO = UserInfo( 0, "zero", "", UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL, ) val MANAGED_USER_INFO = UserInfo( 10, "ten-managed", "", 0, UserManager.USER_TYPE_PROFILE_MANAGED, ) fun String.toTileSpec() = TileSpec.create(this) } }