Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractorTest.kt 0 → 100644 +87 −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.reducebrightness.domain.interactor import android.os.UserHandle import android.platform.test.annotations.EnabledOnRavenwood import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.accessibility.reduceBrightColorsController import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger import com.android.systemui.qs.tiles.impl.reducebrightness.domain.model.ReduceBrightColorsTileModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.toCollection import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @EnabledOnRavenwood @RunWith(AndroidJUnit4::class) class ReduceBrightColorsTileDataInteractorTest : SysuiTestCase() { private val isAvailable = true private val kosmos = Kosmos() private val testScope = kosmos.testScope private val reduceBrightColorsController = kosmos.reduceBrightColorsController private val underTest: ReduceBrightColorsTileDataInteractor = ReduceBrightColorsTileDataInteractor( testScope.testScheduler, isAvailable, reduceBrightColorsController ) @Test fun alwaysAvailable() = testScope.runTest { val availability = underTest.availability(TEST_USER).toCollection(mutableListOf()) assertThat(availability).hasSize(1) assertThat(availability.last()).isEqualTo(isAvailable) } @Test fun dataMatchesTheRepository() = testScope.runTest { val dataList: List<ReduceBrightColorsTileModel> by collectValues( underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)) ) runCurrent() reduceBrightColorsController.isReduceBrightColorsActivated = true runCurrent() reduceBrightColorsController.isReduceBrightColorsActivated = false runCurrent() assertThat(dataList).hasSize(3) assertThat(dataList.map { it.isEnabled }).isEqualTo(listOf(false, true, false)) } private companion object { val TEST_USER = UserHandle.of(1)!! } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt 0 → 100644 +91 −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.reducebrightness.domain.interactor 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.reduceBrightColorsController import com.android.systemui.kosmos.Kosmos 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.reducebrightness.domain.model.ReduceBrightColorsTileModel 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 ReduceBrightColorsTileUserActionInteractorTest : SysuiTestCase() { private val kosmos = Kosmos() private val inputHandler = FakeQSTileIntentUserInputHandler() private val controller = kosmos.reduceBrightColorsController private val underTest = ReduceBrightColorsTileUserActionInteractor( inputHandler, controller, ) @Test fun handleClickWhenEnabled() = runTest { val wasEnabled = true controller.isReduceBrightColorsActivated = wasEnabled underTest.handleInput(QSTileInputTestKtx.click(ReduceBrightColorsTileModel(wasEnabled))) assertThat(controller.isReduceBrightColorsActivated).isEqualTo(!wasEnabled) } @Test fun handleClickWhenDisabled() = runTest { val wasEnabled = false controller.isReduceBrightColorsActivated = wasEnabled underTest.handleInput(QSTileInputTestKtx.click(ReduceBrightColorsTileModel(wasEnabled))) assertThat(controller.isReduceBrightColorsActivated).isEqualTo(!wasEnabled) } @Test fun handleLongClickWhenDisabled() = runTest { val enabled = false underTest.handleInput(QSTileInputTestKtx.longClick(ReduceBrightColorsTileModel(enabled))) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { assertThat(it.intent.action).isEqualTo(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS) } } @Test fun handleLongClickWhenEnabled() = runTest { val enabled = true underTest.handleInput(QSTileInputTestKtx.longClick(ReduceBrightColorsTileModel(enabled))) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { assertThat(it.intent.action).isEqualTo(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS) } } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapperTest.kt 0 → 100644 +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.reducebrightness.ui import android.graphics.drawable.TestStubDrawable import android.service.quicksettings.Tile 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.reducebrightness.domain.model.ReduceBrightColorsTileModel import com.android.systemui.qs.tiles.impl.reducebrightness.qsReduceBrightColorsTileConfig 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 ReduceBrightColorsTileMapperTest : SysuiTestCase() { private val kosmos = Kosmos() private val config = kosmos.qsReduceBrightColorsTileConfig private lateinit var mapper: ReduceBrightColorsTileMapper @Before fun setup() { mapper = ReduceBrightColorsTileMapper( context.orCreateTestableResources .apply { addOverride(R.drawable.qs_extra_dim_icon_on, TestStubDrawable()) addOverride(R.drawable.qs_extra_dim_icon_off, TestStubDrawable()) } .resources, context.theme ) } @Test fun disabledModel() { val inputModel = ReduceBrightColorsTileModel(false) val outputState = mapper.map(config, inputModel) val expectedState = createReduceBrightColorsTileState( QSTileState.ActivationState.INACTIVE, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun enabledModel() { val inputModel = ReduceBrightColorsTileModel(true) val outputState = mapper.map(config, inputModel) val expectedState = createReduceBrightColorsTileState(QSTileState.ActivationState.ACTIVE) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } private fun createReduceBrightColorsTileState( activationState: QSTileState.ActivationState, ): QSTileState { val label = context.getString(com.android.internal.R.string.reduce_bright_colors_feature_name) return QSTileState( { Icon.Loaded( context.getDrawable( if (activationState == QSTileState.ActivationState.ACTIVE) R.drawable.qs_extra_dim_icon_on else R.drawable.qs_extra_dim_icon_off )!!, null ) }, label, activationState, context.resources .getStringArray(R.array.tile_states_reduce_brightness)[ if (activationState == QSTileState.ActivationState.ACTIVE) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE], setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK), label, null, QSTileState.SideViewIcon.None, QSTileState.EnabledState.ENABLED, Switch::class.qualifiedName ) } } packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt +43 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.accessibility.qs import com.android.systemui.Flags import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tileimpl.QSTileImpl Loading @@ -40,9 +41,14 @@ import com.android.systemui.qs.tiles.impl.inversion.domain.ColorInversionTileMap import com.android.systemui.qs.tiles.impl.inversion.domain.interactor.ColorInversionTileDataInteractor import com.android.systemui.qs.tiles.impl.inversion.domain.interactor.ColorInversionUserActionInteractor import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel import com.android.systemui.qs.tiles.impl.reducebrightness.domain.interactor.ReduceBrightColorsTileDataInteractor import com.android.systemui.qs.tiles.impl.reducebrightness.domain.interactor.ReduceBrightColorsTileUserActionInteractor import com.android.systemui.qs.tiles.impl.reducebrightness.domain.model.ReduceBrightColorsTileModel import com.android.systemui.qs.tiles.impl.reducebrightness.ui.ReduceBrightColorsTileMapper import com.android.systemui.qs.tiles.viewmodel.QSTileConfig import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel import com.android.systemui.qs.tiles.viewmodel.StubQSTileViewModel import com.android.systemui.res.R import dagger.Binds import dagger.Module Loading Loading @@ -105,6 +111,7 @@ interface QSAccessibilityModule { const val COLOR_CORRECTION_TILE_SPEC = "color_correction" const val COLOR_INVERSION_TILE_SPEC = "inversion" const val FONT_SCALING_TILE_SPEC = "font_scaling" const val REDUCE_BRIGHTNESS_TILE_SPEC = "reduce_brightness" @Provides @IntoMap Loading Loading @@ -198,5 +205,41 @@ interface QSAccessibilityModule { stateInteractor, mapper, ) @Provides @IntoMap @StringKey(REDUCE_BRIGHTNESS_TILE_SPEC) fun provideReduceBrightColorsTileConfig(uiEventLogger: QsEventLogger): QSTileConfig = QSTileConfig( tileSpec = TileSpec.create(REDUCE_BRIGHTNESS_TILE_SPEC), uiConfig = QSTileUIConfig.Resource( iconRes = R.drawable.qs_extra_dim_icon_on, labelRes = com.android.internal.R.string.reduce_bright_colors_feature_name, ), instanceId = uiEventLogger.getNewInstanceId(), ) /** * Inject Reduce Bright Colors Tile into tileViewModelMap in QSModule. The tile is hidden * behind a flag. */ @Provides @IntoMap @StringKey(REDUCE_BRIGHTNESS_TILE_SPEC) fun provideReduceBrightColorsTileViewModel( factory: QSTileViewModelFactory.Static<ReduceBrightColorsTileModel>, mapper: ReduceBrightColorsTileMapper, stateInteractor: ReduceBrightColorsTileDataInteractor, userActionInteractor: ReduceBrightColorsTileUserActionInteractor ): QSTileViewModel = if (Flags.qsNewTilesFuture()) factory.create( TileSpec.create(REDUCE_BRIGHTNESS_TILE_SPEC), userActionInteractor, stateInteractor, mapper, ) else StubQSTileViewModel } } packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java +6 −109 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * 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. Loading @@ -16,124 +16,21 @@ package com.android.systemui.qs; import android.content.Context; import android.database.ContentObserver; import android.hardware.display.ColorDisplayManager; import android.net.Uri; import android.os.Handler; import android.os.HandlerExecutor; import android.provider.Settings; import androidx.annotation.NonNull; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.CallbackController; import com.android.systemui.util.settings.SecureSettings; import java.util.ArrayList; import javax.inject.Inject; /** * @hide */ @SysUISingleton public class ReduceBrightColorsController implements public interface ReduceBrightColorsController extends CallbackController<ReduceBrightColorsController.Listener> { private final ColorDisplayManager mManager; private final UserTracker mUserTracker; private UserTracker.Callback mCurrentUserTrackerCallback; private final Handler mHandler; private final ContentObserver mContentObserver; private final SecureSettings mSecureSettings; private final ArrayList<ReduceBrightColorsController.Listener> mListeners = new ArrayList<>(); @Inject public ReduceBrightColorsController(UserTracker userTracker, @Background Handler handler, ColorDisplayManager colorDisplayManager, SecureSettings secureSettings) { mManager = colorDisplayManager; mUserTracker = userTracker; mHandler = handler; mSecureSettings = secureSettings; mContentObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); final String setting = uri == null ? null : uri.getLastPathSegment(); synchronized (mListeners) { if (setting != null && mListeners.size() != 0) { if (setting.equals(Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED)) { dispatchOnActivated(mManager.isReduceBrightColorsActivated()); } } } } }; mCurrentUserTrackerCallback = new UserTracker.Callback() { @Override public void onUserChanged(int newUser, Context userContext) { synchronized (mListeners) { if (mListeners.size() > 0) { mSecureSettings.unregisterContentObserver(mContentObserver); mSecureSettings.registerContentObserverForUser( Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, false, mContentObserver, newUser); } } } }; mUserTracker.addCallback(mCurrentUserTrackerCallback, new HandlerExecutor(handler)); } @Override public void addCallback(@NonNull Listener listener) { synchronized (mListeners) { if (!mListeners.contains(listener)) { mListeners.add(listener); if (mListeners.size() == 1) { mSecureSettings.registerContentObserverForUser( Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, false, mContentObserver, mUserTracker.getUserId()); } } } } @Override public void removeCallback(@androidx.annotation.NonNull Listener listener) { synchronized (mListeners) { if (mListeners.remove(listener) && mListeners.size() == 0) { mSecureSettings.unregisterContentObserver(mContentObserver); } } } /** Returns {@code true} if Reduce Bright Colors is activated */ public boolean isReduceBrightColorsActivated() { return mManager.isReduceBrightColorsActivated(); } boolean isReduceBrightColorsActivated(); /** Sets the activation state of Reduce Bright Colors */ public void setReduceBrightColorsActivated(boolean activated) { mManager.setReduceBrightColorsActivated(activated); } private void dispatchOnActivated(boolean activated) { ArrayList<Listener> copy = new ArrayList<>(mListeners); for (Listener l : copy) { l.onActivated(activated); } } void setReduceBrightColorsActivated(boolean activated); /** * Listener invoked whenever the Reduce Bright Colors settings are changed. */ public interface Listener { interface Listener { /** * Listener invoked when the activated state changes. * Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileDataInteractorTest.kt 0 → 100644 +87 −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.reducebrightness.domain.interactor import android.os.UserHandle import android.platform.test.annotations.EnabledOnRavenwood import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.accessibility.reduceBrightColorsController import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger import com.android.systemui.qs.tiles.impl.reducebrightness.domain.model.ReduceBrightColorsTileModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.toCollection import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @EnabledOnRavenwood @RunWith(AndroidJUnit4::class) class ReduceBrightColorsTileDataInteractorTest : SysuiTestCase() { private val isAvailable = true private val kosmos = Kosmos() private val testScope = kosmos.testScope private val reduceBrightColorsController = kosmos.reduceBrightColorsController private val underTest: ReduceBrightColorsTileDataInteractor = ReduceBrightColorsTileDataInteractor( testScope.testScheduler, isAvailable, reduceBrightColorsController ) @Test fun alwaysAvailable() = testScope.runTest { val availability = underTest.availability(TEST_USER).toCollection(mutableListOf()) assertThat(availability).hasSize(1) assertThat(availability.last()).isEqualTo(isAvailable) } @Test fun dataMatchesTheRepository() = testScope.runTest { val dataList: List<ReduceBrightColorsTileModel> by collectValues( underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)) ) runCurrent() reduceBrightColorsController.isReduceBrightColorsActivated = true runCurrent() reduceBrightColorsController.isReduceBrightColorsActivated = false runCurrent() assertThat(dataList).hasSize(3) assertThat(dataList.map { it.isEnabled }).isEqualTo(listOf(false, true, false)) } private companion object { val TEST_USER = UserHandle.of(1)!! } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt 0 → 100644 +91 −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.reducebrightness.domain.interactor 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.reduceBrightColorsController import com.android.systemui.kosmos.Kosmos 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.reducebrightness.domain.model.ReduceBrightColorsTileModel 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 ReduceBrightColorsTileUserActionInteractorTest : SysuiTestCase() { private val kosmos = Kosmos() private val inputHandler = FakeQSTileIntentUserInputHandler() private val controller = kosmos.reduceBrightColorsController private val underTest = ReduceBrightColorsTileUserActionInteractor( inputHandler, controller, ) @Test fun handleClickWhenEnabled() = runTest { val wasEnabled = true controller.isReduceBrightColorsActivated = wasEnabled underTest.handleInput(QSTileInputTestKtx.click(ReduceBrightColorsTileModel(wasEnabled))) assertThat(controller.isReduceBrightColorsActivated).isEqualTo(!wasEnabled) } @Test fun handleClickWhenDisabled() = runTest { val wasEnabled = false controller.isReduceBrightColorsActivated = wasEnabled underTest.handleInput(QSTileInputTestKtx.click(ReduceBrightColorsTileModel(wasEnabled))) assertThat(controller.isReduceBrightColorsActivated).isEqualTo(!wasEnabled) } @Test fun handleLongClickWhenDisabled() = runTest { val enabled = false underTest.handleInput(QSTileInputTestKtx.longClick(ReduceBrightColorsTileModel(enabled))) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { assertThat(it.intent.action).isEqualTo(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS) } } @Test fun handleLongClickWhenEnabled() = runTest { val enabled = true underTest.handleInput(QSTileInputTestKtx.longClick(ReduceBrightColorsTileModel(enabled))) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { assertThat(it.intent.action).isEqualTo(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS) } } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapperTest.kt 0 → 100644 +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.reducebrightness.ui import android.graphics.drawable.TestStubDrawable import android.service.quicksettings.Tile 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.reducebrightness.domain.model.ReduceBrightColorsTileModel import com.android.systemui.qs.tiles.impl.reducebrightness.qsReduceBrightColorsTileConfig 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 ReduceBrightColorsTileMapperTest : SysuiTestCase() { private val kosmos = Kosmos() private val config = kosmos.qsReduceBrightColorsTileConfig private lateinit var mapper: ReduceBrightColorsTileMapper @Before fun setup() { mapper = ReduceBrightColorsTileMapper( context.orCreateTestableResources .apply { addOverride(R.drawable.qs_extra_dim_icon_on, TestStubDrawable()) addOverride(R.drawable.qs_extra_dim_icon_off, TestStubDrawable()) } .resources, context.theme ) } @Test fun disabledModel() { val inputModel = ReduceBrightColorsTileModel(false) val outputState = mapper.map(config, inputModel) val expectedState = createReduceBrightColorsTileState( QSTileState.ActivationState.INACTIVE, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun enabledModel() { val inputModel = ReduceBrightColorsTileModel(true) val outputState = mapper.map(config, inputModel) val expectedState = createReduceBrightColorsTileState(QSTileState.ActivationState.ACTIVE) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } private fun createReduceBrightColorsTileState( activationState: QSTileState.ActivationState, ): QSTileState { val label = context.getString(com.android.internal.R.string.reduce_bright_colors_feature_name) return QSTileState( { Icon.Loaded( context.getDrawable( if (activationState == QSTileState.ActivationState.ACTIVE) R.drawable.qs_extra_dim_icon_on else R.drawable.qs_extra_dim_icon_off )!!, null ) }, label, activationState, context.resources .getStringArray(R.array.tile_states_reduce_brightness)[ if (activationState == QSTileState.ActivationState.ACTIVE) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE], setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK), label, null, QSTileState.SideViewIcon.None, QSTileState.EnabledState.ENABLED, Switch::class.qualifiedName ) } }
packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt +43 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.accessibility.qs import com.android.systemui.Flags import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tileimpl.QSTileImpl Loading @@ -40,9 +41,14 @@ import com.android.systemui.qs.tiles.impl.inversion.domain.ColorInversionTileMap import com.android.systemui.qs.tiles.impl.inversion.domain.interactor.ColorInversionTileDataInteractor import com.android.systemui.qs.tiles.impl.inversion.domain.interactor.ColorInversionUserActionInteractor import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel import com.android.systemui.qs.tiles.impl.reducebrightness.domain.interactor.ReduceBrightColorsTileDataInteractor import com.android.systemui.qs.tiles.impl.reducebrightness.domain.interactor.ReduceBrightColorsTileUserActionInteractor import com.android.systemui.qs.tiles.impl.reducebrightness.domain.model.ReduceBrightColorsTileModel import com.android.systemui.qs.tiles.impl.reducebrightness.ui.ReduceBrightColorsTileMapper import com.android.systemui.qs.tiles.viewmodel.QSTileConfig import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel import com.android.systemui.qs.tiles.viewmodel.StubQSTileViewModel import com.android.systemui.res.R import dagger.Binds import dagger.Module Loading Loading @@ -105,6 +111,7 @@ interface QSAccessibilityModule { const val COLOR_CORRECTION_TILE_SPEC = "color_correction" const val COLOR_INVERSION_TILE_SPEC = "inversion" const val FONT_SCALING_TILE_SPEC = "font_scaling" const val REDUCE_BRIGHTNESS_TILE_SPEC = "reduce_brightness" @Provides @IntoMap Loading Loading @@ -198,5 +205,41 @@ interface QSAccessibilityModule { stateInteractor, mapper, ) @Provides @IntoMap @StringKey(REDUCE_BRIGHTNESS_TILE_SPEC) fun provideReduceBrightColorsTileConfig(uiEventLogger: QsEventLogger): QSTileConfig = QSTileConfig( tileSpec = TileSpec.create(REDUCE_BRIGHTNESS_TILE_SPEC), uiConfig = QSTileUIConfig.Resource( iconRes = R.drawable.qs_extra_dim_icon_on, labelRes = com.android.internal.R.string.reduce_bright_colors_feature_name, ), instanceId = uiEventLogger.getNewInstanceId(), ) /** * Inject Reduce Bright Colors Tile into tileViewModelMap in QSModule. The tile is hidden * behind a flag. */ @Provides @IntoMap @StringKey(REDUCE_BRIGHTNESS_TILE_SPEC) fun provideReduceBrightColorsTileViewModel( factory: QSTileViewModelFactory.Static<ReduceBrightColorsTileModel>, mapper: ReduceBrightColorsTileMapper, stateInteractor: ReduceBrightColorsTileDataInteractor, userActionInteractor: ReduceBrightColorsTileUserActionInteractor ): QSTileViewModel = if (Flags.qsNewTilesFuture()) factory.create( TileSpec.create(REDUCE_BRIGHTNESS_TILE_SPEC), userActionInteractor, stateInteractor, mapper, ) else StubQSTileViewModel } }
packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java +6 −109 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * 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. Loading @@ -16,124 +16,21 @@ package com.android.systemui.qs; import android.content.Context; import android.database.ContentObserver; import android.hardware.display.ColorDisplayManager; import android.net.Uri; import android.os.Handler; import android.os.HandlerExecutor; import android.provider.Settings; import androidx.annotation.NonNull; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.CallbackController; import com.android.systemui.util.settings.SecureSettings; import java.util.ArrayList; import javax.inject.Inject; /** * @hide */ @SysUISingleton public class ReduceBrightColorsController implements public interface ReduceBrightColorsController extends CallbackController<ReduceBrightColorsController.Listener> { private final ColorDisplayManager mManager; private final UserTracker mUserTracker; private UserTracker.Callback mCurrentUserTrackerCallback; private final Handler mHandler; private final ContentObserver mContentObserver; private final SecureSettings mSecureSettings; private final ArrayList<ReduceBrightColorsController.Listener> mListeners = new ArrayList<>(); @Inject public ReduceBrightColorsController(UserTracker userTracker, @Background Handler handler, ColorDisplayManager colorDisplayManager, SecureSettings secureSettings) { mManager = colorDisplayManager; mUserTracker = userTracker; mHandler = handler; mSecureSettings = secureSettings; mContentObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); final String setting = uri == null ? null : uri.getLastPathSegment(); synchronized (mListeners) { if (setting != null && mListeners.size() != 0) { if (setting.equals(Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED)) { dispatchOnActivated(mManager.isReduceBrightColorsActivated()); } } } } }; mCurrentUserTrackerCallback = new UserTracker.Callback() { @Override public void onUserChanged(int newUser, Context userContext) { synchronized (mListeners) { if (mListeners.size() > 0) { mSecureSettings.unregisterContentObserver(mContentObserver); mSecureSettings.registerContentObserverForUser( Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, false, mContentObserver, newUser); } } } }; mUserTracker.addCallback(mCurrentUserTrackerCallback, new HandlerExecutor(handler)); } @Override public void addCallback(@NonNull Listener listener) { synchronized (mListeners) { if (!mListeners.contains(listener)) { mListeners.add(listener); if (mListeners.size() == 1) { mSecureSettings.registerContentObserverForUser( Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, false, mContentObserver, mUserTracker.getUserId()); } } } } @Override public void removeCallback(@androidx.annotation.NonNull Listener listener) { synchronized (mListeners) { if (mListeners.remove(listener) && mListeners.size() == 0) { mSecureSettings.unregisterContentObserver(mContentObserver); } } } /** Returns {@code true} if Reduce Bright Colors is activated */ public boolean isReduceBrightColorsActivated() { return mManager.isReduceBrightColorsActivated(); } boolean isReduceBrightColorsActivated(); /** Sets the activation state of Reduce Bright Colors */ public void setReduceBrightColorsActivated(boolean activated) { mManager.setReduceBrightColorsActivated(activated); } private void dispatchOnActivated(boolean activated) { ArrayList<Listener> copy = new ArrayList<>(mListeners); for (Listener l : copy) { l.onActivated(activated); } } void setReduceBrightColorsActivated(boolean activated); /** * Listener invoked whenever the Reduce Bright Colors settings are changed. */ public interface Listener { interface Listener { /** * Listener invoked when the activated state changes. * Loading