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

Commit c4d75ec3 authored by Behnam Heydarshahi's avatar Behnam Heydarshahi
Browse files

Migrate FontScalingTile

Fixes: 301056434
Flag: aconfig com.android.systemui.qs_new_tiles DEVELOPMENT
Test: atest SystemUiRoboTests
Test: atest FontScalingTileDataInteractorTest
FontScalingTileUserActionInteractorTest FontScalingTileMapperTest

Change-Id: I81777fe908e6c17a0cb6bbd3565f66ef59c9bade
parent 48312dcc
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.tiles.impl.fontscaling.domain

import android.graphics.drawable.TestStubDrawable
import android.widget.Switch
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
import com.android.systemui.qs.tiles.impl.fontscaling.domain.model.FontScalingTileModel
import com.android.systemui.qs.tiles.impl.fontscaling.qsFontScalingTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileState
import com.android.systemui.res.R
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class FontScalingTileMapperTest : SysuiTestCase() {
    private val kosmos = Kosmos()
    private val fontScalingTileConfig = kosmos.qsFontScalingTileConfig

    private val mapper by lazy {
        FontScalingTileMapper(
            context.orCreateTestableResources
                .apply { addOverride(R.drawable.ic_qs_font_scaling, TestStubDrawable()) }
                .resources,
            context.theme
        )
    }

    @Test
    fun activeStateMatchesEnabledModel() {
        val inputModel = FontScalingTileModel

        val outputState = mapper.map(fontScalingTileConfig, inputModel)

        val expectedState = createFontScalingTileState()
        QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
    }

    private fun createFontScalingTileState(): QSTileState =
        QSTileState(
            {
                Icon.Loaded(
                    context.getDrawable(
                        R.drawable.ic_qs_font_scaling,
                    )!!,
                    null
                )
            },
            context.getString(R.string.quick_settings_font_scaling_label),
            QSTileState.ActivationState.ACTIVE,
            null,
            setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK),
            context.getString(R.string.quick_settings_font_scaling_label),
            null,
            QSTileState.SideViewIcon.Chevron,
            QSTileState.EnabledState.ENABLED,
            Switch::class.qualifiedName
        )
}
+67 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.tiles.impl.fontscaling.domain.interactor

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.coroutines.collectValues
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.google.common.truth.Truth
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class FontScalingTileDataInteractorTest : SysuiTestCase() {
    private val underTest: FontScalingTileDataInteractor = FontScalingTileDataInteractor()
    private val testUser = UserHandle.of(1)

    @Test
    fun collectsExactlyOneValue() = runTest {
        val flowValues by
            collectValues(underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest)))

        runCurrent()

        Truth.assertThat(flowValues.size).isEqualTo(1)
    }

    @Test
    fun lastValueIsNotEmpty() = runTest {
        val flowValue by
            collectLastValue(underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest)))

        runCurrent()

        Truth.assertThat(flowValue).isNotNull()
    }

    @Test
    fun isAvailable() = runTest {
        val availability by collectLastValue(underTest.availability(testUser))

        Truth.assertThat(availability).isTrue()
    }
}
+142 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.tiles.impl.fontscaling.domain.interactor

import android.provider.Settings
import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.accessibility.fontscaling.FontScalingDialogDelegate
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
import com.android.systemui.qs.tiles.base.actions.intentInputs
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.click
import com.android.systemui.qs.tiles.impl.fontscaling.domain.model.FontScalingTileModel
import com.android.systemui.statusbar.phone.FakeKeyguardStateController
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify

@SmallTest
@RunWith(AndroidJUnit4::class)
class FontScalingUserActionInteractorTest : SysuiTestCase() {
    private val kosmos = Kosmos()
    private val qsTileIntentUserActionHandler = FakeQSTileIntentUserInputHandler()
    private val keyguardStateController = FakeKeyguardStateController()

    private lateinit var underTest: FontScalingTileUserActionInteractor

    @Mock private lateinit var fontScalingDialogDelegate: FontScalingDialogDelegate
    @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
    @Mock private lateinit var dialog: SystemUIDialog
    @Mock private lateinit var activityStarter: ActivityStarter

    @Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable>

    @Before
    fun setup() {
        activityStarter = mock<ActivityStarter>()
        dialogLaunchAnimator = mock<DialogLaunchAnimator>()
        dialog = mock<SystemUIDialog>()
        fontScalingDialogDelegate =
            mock<FontScalingDialogDelegate> { whenever(createDialog()).thenReturn(dialog) }
        argumentCaptor = ArgumentCaptor.forClass(Runnable::class.java)

        underTest =
            FontScalingTileUserActionInteractor(
                kosmos.testScope.coroutineContext,
                qsTileIntentUserActionHandler,
                { fontScalingDialogDelegate },
                keyguardStateController,
                dialogLaunchAnimator,
                activityStarter
            )
    }

    @Test
    fun clickTile_screenUnlocked_showDialogAnimationFromView() =
        kosmos.testScope.runTest {
            keyguardStateController.isShowing = false
            val testView = View(context)

            underTest.handleInput(click(FontScalingTileModel, view = testView))

            verify(activityStarter)
                .executeRunnableDismissingKeyguard(
                    argumentCaptor.capture(),
                    eq(null),
                    eq(true),
                    eq(true),
                    eq(false)
                )
            argumentCaptor.value.run()
            verify(dialogLaunchAnimator).showFromView(any(), eq(testView), nullable(), anyBoolean())
        }

    @Test
    fun clickTile_onLockScreen_neverShowDialogAnimationFromView_butShowsDialog() =
        kosmos.testScope.runTest {
            keyguardStateController.isShowing = true
            val testView = View(context)

            underTest.handleInput(click(FontScalingTileModel, view = testView))

            verify(activityStarter)
                .executeRunnableDismissingKeyguard(
                    argumentCaptor.capture(),
                    eq(null),
                    eq(true),
                    eq(true),
                    eq(false)
                )
            argumentCaptor.value.run()
            verify(dialogLaunchAnimator, never())
                .showFromView(any(), eq(testView), nullable(), anyBoolean())
            verify(dialog).show()
        }

    @Test
    fun handleLongClick() =
        kosmos.testScope.runTest {
            underTest.handleInput(QSTileInputTestKtx.longClick(FontScalingTileModel))

            Truth.assertThat(qsTileIntentUserActionHandler.handledInputs).hasSize(1)
            val intentInput = qsTileIntentUserActionHandler.intentInputs.last()
            val actualIntentAction = intentInput.intent.action
            val expectedIntentAction = Settings.ACTION_TEXT_READING_SETTINGS
            Truth.assertThat(actualIntentAction).isEqualTo(expectedIntentAction)
        }
}
+4 −0
Original line number Diff line number Diff line
@@ -33,6 +33,10 @@ public class FakeKeyguardStateController implements KeyguardStateController {
        mOccluded = occluded;
    }

    public void setShowing(boolean isShowing) {
        mShowing = isShowing;
    }

    @Override
    public boolean isShowing() {
        return mShowing;
+36 −0
Original line number Diff line number Diff line
@@ -31,6 +31,10 @@ import com.android.systemui.qs.tiles.impl.colorcorrection.domain.ColorCorrection
import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionTileDataInteractor
import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionUserActionInteractor
import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
import com.android.systemui.qs.tiles.impl.fontscaling.domain.FontScalingTileMapper
import com.android.systemui.qs.tiles.impl.fontscaling.domain.interactor.FontScalingTileDataInteractor
import com.android.systemui.qs.tiles.impl.fontscaling.domain.interactor.FontScalingTileUserActionInteractor
import com.android.systemui.qs.tiles.impl.fontscaling.domain.model.FontScalingTileModel
import com.android.systemui.qs.tiles.impl.inversion.domain.ColorInversionTileMapper
import com.android.systemui.qs.tiles.impl.inversion.domain.interactor.ColorInversionTileDataInteractor
import com.android.systemui.qs.tiles.impl.inversion.domain.interactor.ColorInversionUserActionInteractor
@@ -93,6 +97,7 @@ interface QSAccessibilityModule {
    companion object {
        const val COLOR_CORRECTION_TILE_SPEC = "color_correction"
        const val COLOR_INVERSION_TILE_SPEC = "inversion"
        const val FONT_SCALING_TILE_SPEC = "font_scaling"

        @Provides
        @IntoMap
@@ -155,5 +160,36 @@ interface QSAccessibilityModule {
                stateInteractor,
                mapper,
            )

        @Provides
        @IntoMap
        @StringKey(FONT_SCALING_TILE_SPEC)
        fun provideFontScalingTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
            QSTileConfig(
                tileSpec = TileSpec.create(FONT_SCALING_TILE_SPEC),
                uiConfig =
                    QSTileUIConfig.Resource(
                        iconRes = R.drawable.ic_qs_font_scaling,
                        labelRes = R.string.quick_settings_font_scaling_label,
                    ),
                instanceId = uiEventLogger.getNewInstanceId(),
            )

        /** Inject FontScaling Tile into tileViewModelMap in QSModule */
        @Provides
        @IntoMap
        @StringKey(FONT_SCALING_TILE_SPEC)
        fun provideFontScalingTileViewModel(
            factory: QSTileViewModelFactory.Static<FontScalingTileModel>,
            mapper: FontScalingTileMapper,
            stateInteractor: FontScalingTileDataInteractor,
            userActionInteractor: FontScalingTileUserActionInteractor
        ): QSTileViewModel =
            factory.create(
                TileSpec.create(FONT_SCALING_TILE_SPEC),
                userActionInteractor,
                stateInteractor,
                mapper,
            )
    }
}
Loading