Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt +31 −6 Original line number Original line Diff line number Diff line Loading @@ -50,7 +50,8 @@ class FlashlightMapperTest : SysuiTestCase() { @Test @Test fun mapsDisabledDataToInactiveState() { fun mapsDisabledDataToInactiveState() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(false)) val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(false)) val actualActivationState = tileState.activationState val actualActivationState = tileState.activationState Loading @@ -59,7 +60,8 @@ class FlashlightMapperTest : SysuiTestCase() { @Test @Test fun mapsEnabledDataToActiveState() { fun mapsEnabledDataToActiveState() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(true)) val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(true)) val actualActivationState = tileState.activationState val actualActivationState = tileState.activationState assertEquals(QSTileState.ActivationState.ACTIVE, actualActivationState) assertEquals(QSTileState.ActivationState.ACTIVE, actualActivationState) Loading @@ -67,7 +69,8 @@ class FlashlightMapperTest : SysuiTestCase() { @Test @Test fun mapsEnabledDataToOnIconState() { fun mapsEnabledDataToOnIconState() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(true)) val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(true)) val expectedIcon = val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_on)!!, null) Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_on)!!, null) Loading @@ -77,7 +80,8 @@ class FlashlightMapperTest : SysuiTestCase() { @Test @Test fun mapsDisabledDataToOffIconState() { fun mapsDisabledDataToOffIconState() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(false)) val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(false)) val expectedIcon = val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, null) Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, null) Loading @@ -86,11 +90,32 @@ class FlashlightMapperTest : SysuiTestCase() { } } @Test @Test fun supportsOnlyClickAction() { fun mapsUnavailableDataToOffIconState() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightTemporarilyUnavailable) val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, null) val actualIcon = tileState.icon() assertThat(actualIcon).isEqualTo(expectedIcon) } @Test fun supportClickActionWhenAvailable() { val dontCare = true val dontCare = true val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(dontCare)) val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(dontCare)) val supportedActions = tileState.supportedActions val supportedActions = tileState.supportedActions assertThat(supportedActions).containsExactly(QSTileState.UserAction.CLICK) assertThat(supportedActions).containsExactly(QSTileState.UserAction.CLICK) } } @Test fun doesNotSupportClickActionWhenUnavailable() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightTemporarilyUnavailable) val supportedActions = tileState.supportedActions assertThat(supportedActions).isEmpty() } } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractorTest.kt +30 −4 Original line number Original line Diff line number Diff line Loading @@ -70,8 +70,7 @@ class FlashlightTileDataInteractorTest : SysuiTestCase() { } } @Test @Test fun dataMatchesController() = runTest { fun isEnabledDataMatchesControllerWhenAvailable() = runTest { controller.setFlashlight(false) val flowValues: List<FlashlightTileModel> by val flowValues: List<FlashlightTileModel> by collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))) collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))) Loading @@ -81,8 +80,35 @@ class FlashlightTileDataInteractorTest : SysuiTestCase() { controller.setFlashlight(false) controller.setFlashlight(false) runCurrent() runCurrent() assertThat(flowValues.size).isEqualTo(3) assertThat(flowValues.size).isEqualTo(4) // 2 from setup(), 2 from this test assertThat(flowValues.map { it.isEnabled }).containsExactly(false, true, false).inOrder() assertThat( flowValues.filterIsInstance<FlashlightTileModel.FlashlightAvailable>().map { it.isEnabled } ) .containsExactly(false, false, true, false) .inOrder() } /** * Simulates the scenario of changes in flashlight tile availability when camera is initially * closed, then opened, and closed again. */ @Test fun availabilityDataMatchesControllerAvailability() = runTest { val flowValues: List<FlashlightTileModel> by collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))) runCurrent() controller.onFlashlightAvailabilityChanged(false) runCurrent() controller.onFlashlightAvailabilityChanged(true) runCurrent() assertThat(flowValues.size).isEqualTo(4) // 2 from setup + 2 from this test assertThat(flowValues.map { it is FlashlightTileModel.FlashlightAvailable }) .containsExactly(true, true, false, true) .inOrder() } } private companion object { private companion object { Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileUserActionInteractorTest.kt +13 −2 Original line number Original line Diff line number Diff line Loading @@ -29,7 +29,9 @@ import org.junit.Assume.assumeFalse import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test import org.junit.runner.RunWith import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.Mock import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.verify @SmallTest @SmallTest Loading @@ -51,7 +53,7 @@ class FlashlightTileUserActionInteractorTest : SysuiTestCase() { assumeFalse(ActivityManager.isUserAMonkey()) assumeFalse(ActivityManager.isUserAMonkey()) val stateBeforeClick = false val stateBeforeClick = false underTest.handleInput(click(FlashlightTileModel(stateBeforeClick))) underTest.handleInput(click(FlashlightTileModel.FlashlightAvailable(stateBeforeClick))) verify(controller).setFlashlight(!stateBeforeClick) verify(controller).setFlashlight(!stateBeforeClick) } } Loading @@ -61,8 +63,17 @@ class FlashlightTileUserActionInteractorTest : SysuiTestCase() { assumeFalse(ActivityManager.isUserAMonkey()) assumeFalse(ActivityManager.isUserAMonkey()) val stateBeforeClick = true val stateBeforeClick = true underTest.handleInput(click(FlashlightTileModel(stateBeforeClick))) underTest.handleInput(click(FlashlightTileModel.FlashlightAvailable(stateBeforeClick))) verify(controller).setFlashlight(!stateBeforeClick) verify(controller).setFlashlight(!stateBeforeClick) } } @Test fun handleClickWhenUnavailable() = runTest { assumeFalse(ActivityManager.isUserAMonkey()) underTest.handleInput(click(FlashlightTileModel.FlashlightTemporarilyUnavailable)) verify(controller, never()).setFlashlight(anyBoolean()) } } } packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt +12 −7 Original line number Original line Diff line number Diff line Loading @@ -40,7 +40,7 @@ constructor( val icon = val icon = Icon.Loaded( Icon.Loaded( resources.getDrawable( resources.getDrawable( if (data.isEnabled) { if (data is FlashlightTileModel.FlashlightAvailable && data.isEnabled) { R.drawable.qs_flashlight_icon_on R.drawable.qs_flashlight_icon_on } else { } else { R.drawable.qs_flashlight_icon_off R.drawable.qs_flashlight_icon_off Loading @@ -51,17 +51,22 @@ constructor( ) ) this.icon = { icon } this.icon = { icon } if (data.isEnabled) { contentDescription = label if (data is FlashlightTileModel.FlashlightTemporarilyUnavailable) { activationState = QSTileState.ActivationState.UNAVAILABLE secondaryLabel = resources.getString(R.string.quick_settings_flashlight_camera_in_use) stateDescription = secondaryLabel supportedActions = setOf() return@build } else if (data is FlashlightTileModel.FlashlightAvailable && data.isEnabled) { activationState = QSTileState.ActivationState.ACTIVE activationState = QSTileState.ActivationState.ACTIVE secondaryLabel = resources.getStringArray(R.array.tile_states_flashlight)[2] secondaryLabel = resources.getStringArray(R.array.tile_states_flashlight)[2] } else { } else { activationState = QSTileState.ActivationState.INACTIVE activationState = QSTileState.ActivationState.INACTIVE secondaryLabel = resources.getStringArray(R.array.tile_states_flashlight)[1] secondaryLabel = resources.getStringArray(R.array.tile_states_flashlight)[1] } } contentDescription = label supportedActions = setOf(QSTileState.UserAction.CLICK) supportedActions = setOf( QSTileState.UserAction.CLICK, ) } } } } packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractor.kt +11 −6 Original line number Original line Diff line number Diff line Loading @@ -38,25 +38,30 @@ constructor( user: UserHandle, user: UserHandle, triggers: Flow<DataUpdateTrigger> triggers: Flow<DataUpdateTrigger> ): Flow<FlashlightTileModel> = conflatedCallbackFlow { ): Flow<FlashlightTileModel> = conflatedCallbackFlow { val initialValue = flashlightController.isEnabled trySend(FlashlightTileModel(initialValue)) val callback = val callback = object : FlashlightController.FlashlightListener { object : FlashlightController.FlashlightListener { override fun onFlashlightChanged(enabled: Boolean) { override fun onFlashlightChanged(enabled: Boolean) { trySend(FlashlightTileModel(enabled)) trySend(FlashlightTileModel.FlashlightAvailable(enabled)) } } override fun onFlashlightError() { override fun onFlashlightError() { trySend(FlashlightTileModel(false)) trySend(FlashlightTileModel.FlashlightAvailable(false)) } } override fun onFlashlightAvailabilityChanged(available: Boolean) { override fun onFlashlightAvailabilityChanged(available: Boolean) { trySend(FlashlightTileModel(flashlightController.isEnabled)) trySend( if (available) FlashlightTileModel.FlashlightAvailable(flashlightController.isEnabled) else FlashlightTileModel.FlashlightTemporarilyUnavailable ) } } } } flashlightController.addCallback(callback) flashlightController.addCallback(callback) awaitClose { flashlightController.removeCallback(callback) } awaitClose { flashlightController.removeCallback(callback) } } } /** * Used to determine if the tile should be displayed. Not to be confused with the availability * in the data model above. This flow signals whether the tile should be shown or hidden. */ override fun availability(user: UserHandle): Flow<Boolean> = override fun availability(user: UserHandle): Flow<Boolean> = flowOf(flashlightController.hasFlashlight()) flowOf(flashlightController.hasFlashlight()) } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt +31 −6 Original line number Original line Diff line number Diff line Loading @@ -50,7 +50,8 @@ class FlashlightMapperTest : SysuiTestCase() { @Test @Test fun mapsDisabledDataToInactiveState() { fun mapsDisabledDataToInactiveState() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(false)) val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(false)) val actualActivationState = tileState.activationState val actualActivationState = tileState.activationState Loading @@ -59,7 +60,8 @@ class FlashlightMapperTest : SysuiTestCase() { @Test @Test fun mapsEnabledDataToActiveState() { fun mapsEnabledDataToActiveState() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(true)) val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(true)) val actualActivationState = tileState.activationState val actualActivationState = tileState.activationState assertEquals(QSTileState.ActivationState.ACTIVE, actualActivationState) assertEquals(QSTileState.ActivationState.ACTIVE, actualActivationState) Loading @@ -67,7 +69,8 @@ class FlashlightMapperTest : SysuiTestCase() { @Test @Test fun mapsEnabledDataToOnIconState() { fun mapsEnabledDataToOnIconState() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(true)) val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(true)) val expectedIcon = val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_on)!!, null) Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_on)!!, null) Loading @@ -77,7 +80,8 @@ class FlashlightMapperTest : SysuiTestCase() { @Test @Test fun mapsDisabledDataToOffIconState() { fun mapsDisabledDataToOffIconState() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(false)) val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(false)) val expectedIcon = val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, null) Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, null) Loading @@ -86,11 +90,32 @@ class FlashlightMapperTest : SysuiTestCase() { } } @Test @Test fun supportsOnlyClickAction() { fun mapsUnavailableDataToOffIconState() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightTemporarilyUnavailable) val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, null) val actualIcon = tileState.icon() assertThat(actualIcon).isEqualTo(expectedIcon) } @Test fun supportClickActionWhenAvailable() { val dontCare = true val dontCare = true val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel(dontCare)) val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(dontCare)) val supportedActions = tileState.supportedActions val supportedActions = tileState.supportedActions assertThat(supportedActions).containsExactly(QSTileState.UserAction.CLICK) assertThat(supportedActions).containsExactly(QSTileState.UserAction.CLICK) } } @Test fun doesNotSupportClickActionWhenUnavailable() { val tileState: QSTileState = mapper.map(qsTileConfig, FlashlightTileModel.FlashlightTemporarilyUnavailable) val supportedActions = tileState.supportedActions assertThat(supportedActions).isEmpty() } } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractorTest.kt +30 −4 Original line number Original line Diff line number Diff line Loading @@ -70,8 +70,7 @@ class FlashlightTileDataInteractorTest : SysuiTestCase() { } } @Test @Test fun dataMatchesController() = runTest { fun isEnabledDataMatchesControllerWhenAvailable() = runTest { controller.setFlashlight(false) val flowValues: List<FlashlightTileModel> by val flowValues: List<FlashlightTileModel> by collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))) collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))) Loading @@ -81,8 +80,35 @@ class FlashlightTileDataInteractorTest : SysuiTestCase() { controller.setFlashlight(false) controller.setFlashlight(false) runCurrent() runCurrent() assertThat(flowValues.size).isEqualTo(3) assertThat(flowValues.size).isEqualTo(4) // 2 from setup(), 2 from this test assertThat(flowValues.map { it.isEnabled }).containsExactly(false, true, false).inOrder() assertThat( flowValues.filterIsInstance<FlashlightTileModel.FlashlightAvailable>().map { it.isEnabled } ) .containsExactly(false, false, true, false) .inOrder() } /** * Simulates the scenario of changes in flashlight tile availability when camera is initially * closed, then opened, and closed again. */ @Test fun availabilityDataMatchesControllerAvailability() = runTest { val flowValues: List<FlashlightTileModel> by collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))) runCurrent() controller.onFlashlightAvailabilityChanged(false) runCurrent() controller.onFlashlightAvailabilityChanged(true) runCurrent() assertThat(flowValues.size).isEqualTo(4) // 2 from setup + 2 from this test assertThat(flowValues.map { it is FlashlightTileModel.FlashlightAvailable }) .containsExactly(true, true, false, true) .inOrder() } } private companion object { private companion object { Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileUserActionInteractorTest.kt +13 −2 Original line number Original line Diff line number Diff line Loading @@ -29,7 +29,9 @@ import org.junit.Assume.assumeFalse import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test import org.junit.runner.RunWith import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.Mock import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.verify @SmallTest @SmallTest Loading @@ -51,7 +53,7 @@ class FlashlightTileUserActionInteractorTest : SysuiTestCase() { assumeFalse(ActivityManager.isUserAMonkey()) assumeFalse(ActivityManager.isUserAMonkey()) val stateBeforeClick = false val stateBeforeClick = false underTest.handleInput(click(FlashlightTileModel(stateBeforeClick))) underTest.handleInput(click(FlashlightTileModel.FlashlightAvailable(stateBeforeClick))) verify(controller).setFlashlight(!stateBeforeClick) verify(controller).setFlashlight(!stateBeforeClick) } } Loading @@ -61,8 +63,17 @@ class FlashlightTileUserActionInteractorTest : SysuiTestCase() { assumeFalse(ActivityManager.isUserAMonkey()) assumeFalse(ActivityManager.isUserAMonkey()) val stateBeforeClick = true val stateBeforeClick = true underTest.handleInput(click(FlashlightTileModel(stateBeforeClick))) underTest.handleInput(click(FlashlightTileModel.FlashlightAvailable(stateBeforeClick))) verify(controller).setFlashlight(!stateBeforeClick) verify(controller).setFlashlight(!stateBeforeClick) } } @Test fun handleClickWhenUnavailable() = runTest { assumeFalse(ActivityManager.isUserAMonkey()) underTest.handleInput(click(FlashlightTileModel.FlashlightTemporarilyUnavailable)) verify(controller, never()).setFlashlight(anyBoolean()) } } }
packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt +12 −7 Original line number Original line Diff line number Diff line Loading @@ -40,7 +40,7 @@ constructor( val icon = val icon = Icon.Loaded( Icon.Loaded( resources.getDrawable( resources.getDrawable( if (data.isEnabled) { if (data is FlashlightTileModel.FlashlightAvailable && data.isEnabled) { R.drawable.qs_flashlight_icon_on R.drawable.qs_flashlight_icon_on } else { } else { R.drawable.qs_flashlight_icon_off R.drawable.qs_flashlight_icon_off Loading @@ -51,17 +51,22 @@ constructor( ) ) this.icon = { icon } this.icon = { icon } if (data.isEnabled) { contentDescription = label if (data is FlashlightTileModel.FlashlightTemporarilyUnavailable) { activationState = QSTileState.ActivationState.UNAVAILABLE secondaryLabel = resources.getString(R.string.quick_settings_flashlight_camera_in_use) stateDescription = secondaryLabel supportedActions = setOf() return@build } else if (data is FlashlightTileModel.FlashlightAvailable && data.isEnabled) { activationState = QSTileState.ActivationState.ACTIVE activationState = QSTileState.ActivationState.ACTIVE secondaryLabel = resources.getStringArray(R.array.tile_states_flashlight)[2] secondaryLabel = resources.getStringArray(R.array.tile_states_flashlight)[2] } else { } else { activationState = QSTileState.ActivationState.INACTIVE activationState = QSTileState.ActivationState.INACTIVE secondaryLabel = resources.getStringArray(R.array.tile_states_flashlight)[1] secondaryLabel = resources.getStringArray(R.array.tile_states_flashlight)[1] } } contentDescription = label supportedActions = setOf(QSTileState.UserAction.CLICK) supportedActions = setOf( QSTileState.UserAction.CLICK, ) } } } }
packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractor.kt +11 −6 Original line number Original line Diff line number Diff line Loading @@ -38,25 +38,30 @@ constructor( user: UserHandle, user: UserHandle, triggers: Flow<DataUpdateTrigger> triggers: Flow<DataUpdateTrigger> ): Flow<FlashlightTileModel> = conflatedCallbackFlow { ): Flow<FlashlightTileModel> = conflatedCallbackFlow { val initialValue = flashlightController.isEnabled trySend(FlashlightTileModel(initialValue)) val callback = val callback = object : FlashlightController.FlashlightListener { object : FlashlightController.FlashlightListener { override fun onFlashlightChanged(enabled: Boolean) { override fun onFlashlightChanged(enabled: Boolean) { trySend(FlashlightTileModel(enabled)) trySend(FlashlightTileModel.FlashlightAvailable(enabled)) } } override fun onFlashlightError() { override fun onFlashlightError() { trySend(FlashlightTileModel(false)) trySend(FlashlightTileModel.FlashlightAvailable(false)) } } override fun onFlashlightAvailabilityChanged(available: Boolean) { override fun onFlashlightAvailabilityChanged(available: Boolean) { trySend(FlashlightTileModel(flashlightController.isEnabled)) trySend( if (available) FlashlightTileModel.FlashlightAvailable(flashlightController.isEnabled) else FlashlightTileModel.FlashlightTemporarilyUnavailable ) } } } } flashlightController.addCallback(callback) flashlightController.addCallback(callback) awaitClose { flashlightController.removeCallback(callback) } awaitClose { flashlightController.removeCallback(callback) } } } /** * Used to determine if the tile should be displayed. Not to be confused with the availability * in the data model above. This flow signals whether the tile should be shown or hidden. */ override fun availability(user: UserHandle): Flow<Boolean> = override fun availability(user: UserHandle): Flow<Boolean> = flowOf(flashlightController.hasFlashlight()) flowOf(flashlightController.hasFlashlight()) } }