Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/battery/doman/interactor/BatterySaverTileDataInteractorTest.kt 0 → 100644 +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.battery.doman.interactor import android.os.UserHandle import android.platform.test.annotations.EnabledOnRavenwood import android.testing.LeakCheck 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.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger import com.android.systemui.qs.tiles.impl.battery.domain.interactor.BatterySaverTileDataInteractor import com.android.systemui.utils.leaks.FakeBatteryController import com.google.common.truth.Truth 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 BatterySaverTileDataInteractorTest : SysuiTestCase() { private val kosmos = Kosmos() private val testScope = kosmos.testScope private val batteryController = FakeBatteryController(LeakCheck()) private val testUser = UserHandle.of(1) private val underTest = BatterySaverTileDataInteractor(testScope.testScheduler, batteryController) @Test fun availability_isTrue() = testScope.runTest { val availability = underTest.availability(testUser).toCollection(mutableListOf()) Truth.assertThat(availability).hasSize(1) Truth.assertThat(availability.last()).isTrue() } @Test fun tileData_matchesBatteryControllerPowerSaving() = testScope.runTest { val data by collectLastValue( underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest)) ) runCurrent() Truth.assertThat(data!!.isPowerSaving).isFalse() batteryController.setPowerSaveMode(true) runCurrent() Truth.assertThat(data!!.isPowerSaving).isTrue() batteryController.setPowerSaveMode(false) runCurrent() Truth.assertThat(data!!.isPowerSaving).isFalse() } @Test fun tileData_matchesBatteryControllerIsPluggedIn() = testScope.runTest { val data by collectLastValue( underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest)) ) runCurrent() Truth.assertThat(data!!.isPluggedIn).isFalse() batteryController.isPluggedIn = true runCurrent() Truth.assertThat(data!!.isPluggedIn).isTrue() batteryController.isPluggedIn = false runCurrent() Truth.assertThat(data!!.isPluggedIn).isFalse() } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/battery/doman/interactor/BatterySaverTileUserActionInteractorTest.kt 0 → 100644 +81 −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.battery.doman.interactor import android.platform.test.annotations.EnabledOnRavenwood import android.provider.Settings import android.testing.LeakCheck import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase 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.battery.domain.interactor.BatterySaverTileUserActionInteractor import com.android.systemui.qs.tiles.impl.battery.domain.model.BatterySaverTileModel import com.android.systemui.utils.leaks.FakeBatteryController import com.google.common.truth.Truth import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @SmallTest @EnabledOnRavenwood @RunWith(AndroidJUnit4::class) class BatterySaverTileUserActionInteractorTest : SysuiTestCase() { private val inputHandler = FakeQSTileIntentUserInputHandler() private val controller = FakeBatteryController(LeakCheck()) private val underTest = BatterySaverTileUserActionInteractor(inputHandler, controller) @Test fun handleClickWhenNotPluggedIn_flipsPowerSaverMode() = runTest { val originalPowerSaveMode = controller.isPowerSave controller.isPluggedIn = false underTest.handleInput( QSTileInputTestKtx.click(BatterySaverTileModel.Standard(false, originalPowerSaveMode)) ) Truth.assertThat(controller.isPowerSave).isNotEqualTo(originalPowerSaveMode) } @Test fun handleClickWhenPluggedIn_doesNotTurnOnPowerSaverMode() = runTest { controller.setPowerSaveMode(false) val originalPowerSaveMode = controller.isPowerSave controller.isPluggedIn = true underTest.handleInput( QSTileInputTestKtx.click( BatterySaverTileModel.Standard(controller.isPluggedIn, originalPowerSaveMode) ) ) Truth.assertThat(controller.isPowerSave).isEqualTo(originalPowerSaveMode) } @Test fun handleLongClick() = runTest { underTest.handleInput( QSTileInputTestKtx.longClick(BatterySaverTileModel.Standard(false, false)) ) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { Truth.assertThat(it.intent.action).isEqualTo(Settings.ACTION_BATTERY_SAVER_SETTINGS) } } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapperTest.kt 0 → 100644 +270 −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.battery.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.tiles.impl.battery.domain.model.BatterySaverTileModel import com.android.systemui.qs.tiles.impl.battery.qsBatterySaverTileConfig import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject 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 BatterySaverTileMapperTest : SysuiTestCase() { private val kosmos = Kosmos() private val batterySaverTileConfig = kosmos.qsBatterySaverTileConfig private lateinit var mapper: BatterySaverTileMapper @Before fun setup() { mapper = BatterySaverTileMapper( context.orCreateTestableResources .apply { addOverride(R.drawable.qs_battery_saver_icon_off, TestStubDrawable()) addOverride(R.drawable.qs_battery_saver_icon_on, TestStubDrawable()) } .resources, context.theme, ) } @Test fun map_standard_notPluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Standard(false, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.INACTIVE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_standard_notPluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Standard(false, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.ACTIVE, "", R.drawable.qs_battery_saver_icon_on, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_standard_pluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Standard(true, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_on, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_standard_pluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Standard(true, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverDisabledNotPluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(false, false, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.INACTIVE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverDisabledNotPluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(false, true, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.ACTIVE, context.getString(R.string.standard_battery_saver_text), R.drawable.qs_battery_saver_icon_on, context.getString(R.string.standard_battery_saver_text), ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverDisabledPluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(true, true, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_on, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverDisabledPluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(true, false, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverEnabledNotPluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(false, false, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.INACTIVE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverEnabledNotPluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(false, true, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.ACTIVE, context.getString(R.string.extreme_battery_saver_text), R.drawable.qs_battery_saver_icon_on, context.getString(R.string.extreme_battery_saver_text), ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverEnabledPluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(true, true, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_on, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverEnabledPluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(true, false, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } private fun createBatterySaverTileState( activationState: QSTileState.ActivationState, secondaryLabel: String, iconRes: Int, stateDescription: CharSequence?, ): QSTileState { val label = context.getString(R.string.battery_detail_switch_title) return QSTileState( { Icon.Loaded(context.getDrawable(iconRes)!!, null) }, label, activationState, secondaryLabel, if (activationState == QSTileState.ActivationState.UNAVAILABLE) setOf(QSTileState.UserAction.LONG_CLICK) else setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK), label, stateDescription, QSTileState.SideViewIcon.None, QSTileState.EnabledState.ENABLED, Switch::class.qualifiedName ) } } packages/SystemUI/res/values/strings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,11 @@ <!-- Battery saver notification dismiss action: Do not turn on battery saver. [CHAR LIMIT=NONE]--> <string name="battery_saver_dismiss_action">No thanks</string> <!-- Secondary label for Battery Saver tile when Battery Saver is enabled. [CHAR LIMIT=20] --> <string name="standard_battery_saver_text">Standard</string> <!-- Secondary label for Battery Saver tile when Extreme Battery Saver is enabled. [CHAR LIMIT=20] --> <string name="extreme_battery_saver_text">Extreme</string> <!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] --> <!-- Name of the button that links to the Wifi settings screen. [CHAR LIMIT=NONE] --> Loading packages/SystemUI/src/com/android/systemui/battery/BatterySaverModule.kt +47 −0 Original line number Diff line number Diff line package com.android.systemui.battery import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.qs.tiles.BatterySaverTile import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory import com.android.systemui.qs.tiles.impl.battery.domain.interactor.BatterySaverTileDataInteractor import com.android.systemui.qs.tiles.impl.battery.domain.interactor.BatterySaverTileUserActionInteractor import com.android.systemui.qs.tiles.impl.battery.domain.model.BatterySaverTileModel import com.android.systemui.qs.tiles.impl.battery.ui.BatterySaverTileMapper 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.res.R import dagger.Binds import dagger.Module import dagger.Provides import dagger.multibindings.IntoMap import dagger.multibindings.StringKey Loading @@ -15,4 +27,39 @@ interface BatterySaverModule { @IntoMap @StringKey(BatterySaverTile.TILE_SPEC) fun bindBatterySaverTile(batterySaverTile: BatterySaverTile): QSTileImpl<*> companion object { private const val BATTERY_SAVER_TILE_SPEC = "battery" @Provides @IntoMap @StringKey(BATTERY_SAVER_TILE_SPEC) fun provideBatterySaverTileConfig(uiEventLogger: QsEventLogger): QSTileConfig = QSTileConfig( tileSpec = TileSpec.create(BATTERY_SAVER_TILE_SPEC), uiConfig = QSTileUIConfig.Resource( iconRes = R.drawable.qs_battery_saver_icon_off, labelRes = R.string.battery_detail_switch_title, ), instanceId = uiEventLogger.getNewInstanceId(), ) /** Inject BatterySaverTile into tileViewModelMap in QSModule */ @Provides @IntoMap @StringKey(BATTERY_SAVER_TILE_SPEC) fun provideBatterySaverTileViewModel( factory: QSTileViewModelFactory.Static<BatterySaverTileModel>, mapper: BatterySaverTileMapper, stateInteractor: BatterySaverTileDataInteractor, userActionInteractor: BatterySaverTileUserActionInteractor ): QSTileViewModel = factory.create( TileSpec.create(BATTERY_SAVER_TILE_SPEC), userActionInteractor, stateInteractor, mapper, ) } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/battery/doman/interactor/BatterySaverTileDataInteractorTest.kt 0 → 100644 +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.battery.doman.interactor import android.os.UserHandle import android.platform.test.annotations.EnabledOnRavenwood import android.testing.LeakCheck 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.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger import com.android.systemui.qs.tiles.impl.battery.domain.interactor.BatterySaverTileDataInteractor import com.android.systemui.utils.leaks.FakeBatteryController import com.google.common.truth.Truth 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 BatterySaverTileDataInteractorTest : SysuiTestCase() { private val kosmos = Kosmos() private val testScope = kosmos.testScope private val batteryController = FakeBatteryController(LeakCheck()) private val testUser = UserHandle.of(1) private val underTest = BatterySaverTileDataInteractor(testScope.testScheduler, batteryController) @Test fun availability_isTrue() = testScope.runTest { val availability = underTest.availability(testUser).toCollection(mutableListOf()) Truth.assertThat(availability).hasSize(1) Truth.assertThat(availability.last()).isTrue() } @Test fun tileData_matchesBatteryControllerPowerSaving() = testScope.runTest { val data by collectLastValue( underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest)) ) runCurrent() Truth.assertThat(data!!.isPowerSaving).isFalse() batteryController.setPowerSaveMode(true) runCurrent() Truth.assertThat(data!!.isPowerSaving).isTrue() batteryController.setPowerSaveMode(false) runCurrent() Truth.assertThat(data!!.isPowerSaving).isFalse() } @Test fun tileData_matchesBatteryControllerIsPluggedIn() = testScope.runTest { val data by collectLastValue( underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest)) ) runCurrent() Truth.assertThat(data!!.isPluggedIn).isFalse() batteryController.isPluggedIn = true runCurrent() Truth.assertThat(data!!.isPluggedIn).isTrue() batteryController.isPluggedIn = false runCurrent() Truth.assertThat(data!!.isPluggedIn).isFalse() } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/battery/doman/interactor/BatterySaverTileUserActionInteractorTest.kt 0 → 100644 +81 −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.battery.doman.interactor import android.platform.test.annotations.EnabledOnRavenwood import android.provider.Settings import android.testing.LeakCheck import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase 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.battery.domain.interactor.BatterySaverTileUserActionInteractor import com.android.systemui.qs.tiles.impl.battery.domain.model.BatterySaverTileModel import com.android.systemui.utils.leaks.FakeBatteryController import com.google.common.truth.Truth import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @SmallTest @EnabledOnRavenwood @RunWith(AndroidJUnit4::class) class BatterySaverTileUserActionInteractorTest : SysuiTestCase() { private val inputHandler = FakeQSTileIntentUserInputHandler() private val controller = FakeBatteryController(LeakCheck()) private val underTest = BatterySaverTileUserActionInteractor(inputHandler, controller) @Test fun handleClickWhenNotPluggedIn_flipsPowerSaverMode() = runTest { val originalPowerSaveMode = controller.isPowerSave controller.isPluggedIn = false underTest.handleInput( QSTileInputTestKtx.click(BatterySaverTileModel.Standard(false, originalPowerSaveMode)) ) Truth.assertThat(controller.isPowerSave).isNotEqualTo(originalPowerSaveMode) } @Test fun handleClickWhenPluggedIn_doesNotTurnOnPowerSaverMode() = runTest { controller.setPowerSaveMode(false) val originalPowerSaveMode = controller.isPowerSave controller.isPluggedIn = true underTest.handleInput( QSTileInputTestKtx.click( BatterySaverTileModel.Standard(controller.isPluggedIn, originalPowerSaveMode) ) ) Truth.assertThat(controller.isPowerSave).isEqualTo(originalPowerSaveMode) } @Test fun handleLongClick() = runTest { underTest.handleInput( QSTileInputTestKtx.longClick(BatterySaverTileModel.Standard(false, false)) ) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { Truth.assertThat(it.intent.action).isEqualTo(Settings.ACTION_BATTERY_SAVER_SETTINGS) } } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapperTest.kt 0 → 100644 +270 −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.battery.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.tiles.impl.battery.domain.model.BatterySaverTileModel import com.android.systemui.qs.tiles.impl.battery.qsBatterySaverTileConfig import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject 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 BatterySaverTileMapperTest : SysuiTestCase() { private val kosmos = Kosmos() private val batterySaverTileConfig = kosmos.qsBatterySaverTileConfig private lateinit var mapper: BatterySaverTileMapper @Before fun setup() { mapper = BatterySaverTileMapper( context.orCreateTestableResources .apply { addOverride(R.drawable.qs_battery_saver_icon_off, TestStubDrawable()) addOverride(R.drawable.qs_battery_saver_icon_on, TestStubDrawable()) } .resources, context.theme, ) } @Test fun map_standard_notPluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Standard(false, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.INACTIVE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_standard_notPluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Standard(false, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.ACTIVE, "", R.drawable.qs_battery_saver_icon_on, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_standard_pluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Standard(true, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_on, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_standard_pluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Standard(true, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverDisabledNotPluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(false, false, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.INACTIVE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverDisabledNotPluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(false, true, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.ACTIVE, context.getString(R.string.standard_battery_saver_text), R.drawable.qs_battery_saver_icon_on, context.getString(R.string.standard_battery_saver_text), ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverDisabledPluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(true, true, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_on, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverDisabledPluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(true, false, false) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverEnabledNotPluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(false, false, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.INACTIVE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverEnabledNotPluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(false, true, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.ACTIVE, context.getString(R.string.extreme_battery_saver_text), R.drawable.qs_battery_saver_icon_on, context.getString(R.string.extreme_battery_saver_text), ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverEnabledPluggedInPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(true, true, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_on, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @Test fun map_extremeSaverEnabledPluggedInNotPowerSaving() { val inputModel = BatterySaverTileModel.Extreme(true, false, true) val outputState = mapper.map(batterySaverTileConfig, inputModel) val expectedState = createBatterySaverTileState( QSTileState.ActivationState.UNAVAILABLE, "", R.drawable.qs_battery_saver_icon_off, null, ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } private fun createBatterySaverTileState( activationState: QSTileState.ActivationState, secondaryLabel: String, iconRes: Int, stateDescription: CharSequence?, ): QSTileState { val label = context.getString(R.string.battery_detail_switch_title) return QSTileState( { Icon.Loaded(context.getDrawable(iconRes)!!, null) }, label, activationState, secondaryLabel, if (activationState == QSTileState.ActivationState.UNAVAILABLE) setOf(QSTileState.UserAction.LONG_CLICK) else setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK), label, stateDescription, QSTileState.SideViewIcon.None, QSTileState.EnabledState.ENABLED, Switch::class.qualifiedName ) } }
packages/SystemUI/res/values/strings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,11 @@ <!-- Battery saver notification dismiss action: Do not turn on battery saver. [CHAR LIMIT=NONE]--> <string name="battery_saver_dismiss_action">No thanks</string> <!-- Secondary label for Battery Saver tile when Battery Saver is enabled. [CHAR LIMIT=20] --> <string name="standard_battery_saver_text">Standard</string> <!-- Secondary label for Battery Saver tile when Extreme Battery Saver is enabled. [CHAR LIMIT=20] --> <string name="extreme_battery_saver_text">Extreme</string> <!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] --> <!-- Name of the button that links to the Wifi settings screen. [CHAR LIMIT=NONE] --> Loading
packages/SystemUI/src/com/android/systemui/battery/BatterySaverModule.kt +47 −0 Original line number Diff line number Diff line package com.android.systemui.battery import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.qs.tiles.BatterySaverTile import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory import com.android.systemui.qs.tiles.impl.battery.domain.interactor.BatterySaverTileDataInteractor import com.android.systemui.qs.tiles.impl.battery.domain.interactor.BatterySaverTileUserActionInteractor import com.android.systemui.qs.tiles.impl.battery.domain.model.BatterySaverTileModel import com.android.systemui.qs.tiles.impl.battery.ui.BatterySaverTileMapper 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.res.R import dagger.Binds import dagger.Module import dagger.Provides import dagger.multibindings.IntoMap import dagger.multibindings.StringKey Loading @@ -15,4 +27,39 @@ interface BatterySaverModule { @IntoMap @StringKey(BatterySaverTile.TILE_SPEC) fun bindBatterySaverTile(batterySaverTile: BatterySaverTile): QSTileImpl<*> companion object { private const val BATTERY_SAVER_TILE_SPEC = "battery" @Provides @IntoMap @StringKey(BATTERY_SAVER_TILE_SPEC) fun provideBatterySaverTileConfig(uiEventLogger: QsEventLogger): QSTileConfig = QSTileConfig( tileSpec = TileSpec.create(BATTERY_SAVER_TILE_SPEC), uiConfig = QSTileUIConfig.Resource( iconRes = R.drawable.qs_battery_saver_icon_off, labelRes = R.string.battery_detail_switch_title, ), instanceId = uiEventLogger.getNewInstanceId(), ) /** Inject BatterySaverTile into tileViewModelMap in QSModule */ @Provides @IntoMap @StringKey(BATTERY_SAVER_TILE_SPEC) fun provideBatterySaverTileViewModel( factory: QSTileViewModelFactory.Static<BatterySaverTileModel>, mapper: BatterySaverTileMapper, stateInteractor: BatterySaverTileDataInteractor, userActionInteractor: BatterySaverTileUserActionInteractor ): QSTileViewModel = factory.create( TileSpec.create(BATTERY_SAVER_TILE_SPEC), userActionInteractor, stateInteractor, mapper, ) } }