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

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

Merge "Migrate FontScalingTile" into main

parents 9612fe39 c4d75ec3
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