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

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

Merge "Migrate OneHandedModeTile" into main

parents 02998af7 9e98480f
Loading
Loading
Loading
Loading
+138 −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.accessibility.data.repository

import android.os.UserHandle
import android.provider.Settings
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.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
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)
@android.platform.test.annotations.EnabledOnRavenwood
class OneHandedModeRepositoryImplTest : SysuiTestCase() {

    private val testUser1 = UserHandle.of(1)!!
    private val testUser2 = UserHandle.of(2)!!
    private val testDispatcher = StandardTestDispatcher()
    private val scope = TestScope(testDispatcher)
    private val settings: FakeSettings = FakeSettings()

    private val underTest: OneHandedModeRepository =
        OneHandedModeRepositoryImpl(
            testDispatcher,
            scope.backgroundScope,
            settings,
        )

    @Test
    fun isEnabled_settingNotInitialized_returnsFalseByDefault() =
        scope.runTest {
            val actualValue by collectLastValue(underTest.isEnabled(testUser1))

            runCurrent()

            assertThat(actualValue).isFalse()
        }

    @Test
    fun isEnabled_initiallyGetsSettingsValue() =
        scope.runTest {
            val actualValue by collectLastValue(underTest.isEnabled(testUser1))

            settings.putIntForUser(SETTING_NAME, ENABLED, testUser1.identifier)
            runCurrent()

            assertThat(actualValue).isTrue()
        }

    @Test
    fun isEnabled_settingUpdated_valueUpdated() =
        scope.runTest {
            val actualValue by collectLastValue(underTest.isEnabled(testUser1))
            runCurrent()
            assertThat(actualValue).isFalse()

            settings.putIntForUser(SETTING_NAME, ENABLED, testUser1.identifier)
            runCurrent()

            assertThat(actualValue).isTrue()
            runCurrent()

            settings.putIntForUser(SETTING_NAME, DISABLED, testUser1.identifier)
            runCurrent()
            assertThat(actualValue).isFalse()
        }

    @Test
    fun isEnabled_settingForUserOneOnly_valueUpdatedForUserOneOnly() =
        scope.runTest {
            val lastValueUser1 by collectLastValue(underTest.isEnabled(testUser1))
            val lastValueUser2 by collectLastValue(underTest.isEnabled(testUser2))

            settings.putIntForUser(SETTING_NAME, DISABLED, testUser1.identifier)
            settings.putIntForUser(SETTING_NAME, DISABLED, testUser2.identifier)
            runCurrent()
            assertThat(lastValueUser1).isFalse()
            assertThat(lastValueUser2).isFalse()

            settings.putIntForUser(SETTING_NAME, ENABLED, testUser1.identifier)
            runCurrent()
            assertThat(lastValueUser1).isTrue()
            assertThat(lastValueUser2).isFalse()
        }

    @Test
    fun setEnabled() =
        scope.runTest {
            val success = underTest.setIsEnabled(true, testUser1)
            runCurrent()
            assertThat(success).isTrue()

            val actualValue = settings.getIntForUser(SETTING_NAME, testUser1.identifier)
            assertThat(actualValue).isEqualTo(ENABLED)
        }

    @Test
    fun setDisabled() =
        scope.runTest {
            val success = underTest.setIsEnabled(false, testUser1)
            runCurrent()
            assertThat(success).isTrue()

            val actualValue = settings.getIntForUser(SETTING_NAME, testUser1.identifier)
            assertThat(actualValue).isEqualTo(DISABLED)
        }

    companion object {
        private const val SETTING_NAME = Settings.Secure.ONE_HANDED_MODE_ENABLED
        private const val DISABLED = 0
        private const val ENABLED = 1
    }
}
+71 −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.onehanded.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.accessibility.data.repository.oneHandedModeRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.impl.onehanded.domain.OneHandedModeTileDataInteractor
import com.android.wm.shell.onehanded.OneHanded
import com.google.common.truth.Truth.assertThat
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 OneHandedModeTileDataInteractorTest : SysuiTestCase() {

    private val kosmos = Kosmos()
    private val testUser = UserHandle.of(1)!!
    private val oneHandedModeRepository = kosmos.oneHandedModeRepository
    private val underTest: OneHandedModeTileDataInteractor =
        OneHandedModeTileDataInteractor(oneHandedModeRepository)

    @Test
    fun availability_matchesController() = runTest {
        val expectedAvailability = OneHanded.sIsSupportOneHandedMode
        val availability by collectLastValue(underTest.availability(testUser))

        assertThat(availability).isEqualTo(expectedAvailability)
    }

    @Test
    fun data_matchesRepository() = runTest {
        val lastData by
            collectLastValue(underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest)))
        runCurrent()
        assertThat(lastData!!.isEnabled).isFalse()

        oneHandedModeRepository.setIsEnabled(true, testUser)
        runCurrent()
        assertThat(lastData!!.isEnabled).isTrue()

        oneHandedModeRepository.setIsEnabled(false, testUser)
        runCurrent()
        assertThat(lastData!!.isEnabled).isFalse()
    }
}
+100 −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.onehanded.domain.interactor

import android.os.UserHandle
import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.accessibility.data.repository.FakeOneHandedModeRepository
import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
import com.android.systemui.qs.tiles.impl.onehanded.domain.OneHandedModeTileUserActionInteractor
import com.android.systemui.qs.tiles.impl.onehanded.domain.model.OneHandedModeTileModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class OneHandedModeTileUserActionInteractorTest : SysuiTestCase() {

    private val testUser = UserHandle.of(1)
    private val repository = FakeOneHandedModeRepository()
    private val inputHandler = FakeQSTileIntentUserInputHandler()

    private val underTest =
        OneHandedModeTileUserActionInteractor(
            repository,
            inputHandler,
        )

    @Test
    fun handleClickWhenEnabled() = runTest {
        val wasEnabled = true
        repository.setIsEnabled(wasEnabled, testUser)

        underTest.handleInput(
            QSTileInputTestKtx.click(OneHandedModeTileModel(wasEnabled), testUser)
        )

        assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
    }

    @Test
    fun handleClickWhenDisabled() = runTest {
        val wasEnabled = false
        repository.setIsEnabled(wasEnabled, testUser)

        underTest.handleInput(
            QSTileInputTestKtx.click(OneHandedModeTileModel(wasEnabled), testUser)
        )

        assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
    }

    @Test
    fun handleLongClickWhenDisabled() = runTest {
        val enabled = false

        underTest.handleInput(
            QSTileInputTestKtx.longClick(OneHandedModeTileModel(enabled), testUser)
        )

        QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
            assertThat(it.intent.action).isEqualTo(Settings.ACTION_ONE_HANDED_SETTINGS)
        }
    }

    @Test
    fun handleLongClickWhenEnabled() = runTest {
        val enabled = true

        underTest.handleInput(
            QSTileInputTestKtx.longClick(OneHandedModeTileModel(enabled), testUser)
        )

        QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
            assertThat(it.intent.action).isEqualTo(Settings.ACTION_ONE_HANDED_SETTINGS)
        }
    }
}
+111 −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.onehanded.ui

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.tileimpl.SubtitleArrayMapping
import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
import com.android.systemui.qs.tiles.impl.onehanded.domain.model.OneHandedModeTileModel
import com.android.systemui.qs.tiles.impl.onehanded.qsOneHandedModeTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileState
import com.android.systemui.res.R
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class OneHandedModeTileMapperTest : SysuiTestCase() {
    private val kosmos = Kosmos()
    private val config = kosmos.qsOneHandedModeTileConfig
    private val subtitleArrayId = SubtitleArrayMapping.getSubtitleId(config.tileSpec.spec)
    private val subtitleArray by lazy { context.resources.getStringArray(subtitleArrayId) }

    private lateinit var mapper: OneHandedModeTileMapper

    @Before
    fun setup() {
        mapper =
            OneHandedModeTileMapper(
                context.orCreateTestableResources
                    .apply {
                        addOverride(
                            com.android.internal.R.drawable.ic_qs_one_handed_mode,
                            TestStubDrawable()
                        )
                    }
                    .resources,
                context.theme
            )
    }

    @Test
    fun disabledModel() {
        val inputModel = OneHandedModeTileModel(false)

        val outputState = mapper.map(config, inputModel)

        val expectedState =
            createOneHandedModeTileState(
                QSTileState.ActivationState.INACTIVE,
                subtitleArray[1],
                com.android.internal.R.drawable.ic_qs_one_handed_mode
            )
        QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
    }

    @Test
    fun enabledModel() {
        val inputModel = OneHandedModeTileModel(true)

        val outputState = mapper.map(config, inputModel)

        val expectedState =
            createOneHandedModeTileState(
                QSTileState.ActivationState.ACTIVE,
                subtitleArray[2],
                com.android.internal.R.drawable.ic_qs_one_handed_mode
            )
        QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
    }

    private fun createOneHandedModeTileState(
        activationState: QSTileState.ActivationState,
        secondaryLabel: String,
        iconRes: Int,
    ): QSTileState {
        val label = context.getString(R.string.quick_settings_onehanded_label)
        return QSTileState(
            { Icon.Loaded(context.getDrawable(iconRes)!!, null) },
            label,
            activationState,
            secondaryLabel,
            setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK),
            label,
            null,
            QSTileState.SideViewIcon.None,
            QSTileState.EnabledState.ENABLED,
            Switch::class.qualifiedName
        )
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import com.android.systemui.accessibility.data.repository.ColorCorrectionReposit
import com.android.systemui.accessibility.data.repository.ColorCorrectionRepositoryImpl
import com.android.systemui.accessibility.data.repository.ColorInversionRepository
import com.android.systemui.accessibility.data.repository.ColorInversionRepositoryImpl
import com.android.systemui.accessibility.data.repository.OneHandedModeRepository
import com.android.systemui.accessibility.data.repository.OneHandedModeRepositoryImpl
import com.android.systemui.accessibility.qs.QSAccessibilityModule
import dagger.Binds
import dagger.Module
@@ -34,6 +36,8 @@ interface AccessibilityModule {
    @Binds
    fun colorInversionRepository(impl: ColorInversionRepositoryImpl): ColorInversionRepository

    @Binds fun oneHandedModeRepository(impl: OneHandedModeRepositoryImpl): OneHandedModeRepository

    @Binds
    fun accessibilityQsShortcutsRepository(
        impl: AccessibilityQsShortcutsRepositoryImpl
Loading