Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 577a1707 authored by Behnam Heydarshahi's avatar Behnam Heydarshahi Committed by Android (Google) Code Review
Browse files

Merge "Allow temporarily unavailable flashlight tile" into main

parents 058402dd ecf0cb0f
Loading
Loading
Loading
Loading
+31 −6
Original line number Original line Diff line number Diff line
@@ -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


@@ -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)
@@ -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)
@@ -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)
@@ -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()
    }
}
}
+30 −4
Original line number Original line Diff line number Diff line
@@ -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)))


@@ -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 {
+13 −2
Original line number Original line Diff line number Diff line
@@ -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
@@ -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)
    }
    }
@@ -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())
    }
}
}
+12 −7
Original line number Original line Diff line number Diff line
@@ -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
@@ -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,
                )
        }
        }
}
}
+11 −6
Original line number Original line Diff line number Diff line
@@ -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