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

Commit c0c95926 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Migrate Use Battery Saver" into main

parents 1c576674 23367e38
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.settingslib.fuelgauge.BatterySaverUtils;
import com.android.settingslib.widget.MainSwitchPreference;

/** Controller to update the battery saver button */
// LINT.IfChange
public class BatterySaverButtonPreferenceController extends TogglePreferenceController
        implements LifecycleObserver, OnStart, OnStop, BatterySaverReceiver.BatterySaverListener {
    private static final long SWITCH_ANIMATION_DURATION = 350L;
@@ -129,3 +130,4 @@ public class BatterySaverButtonPreferenceController extends TogglePreferenceCont
        }
    }
}
// LINT.ThenChange(BatterySaverPreference.kt)
+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.settings.fuelgauge.batterysaver

import android.content.Context
import android.os.Handler
import android.os.Looper
import android.os.PowerManager
import com.android.settings.R
import com.android.settings.fuelgauge.BatterySaverReceiver
import com.android.settings.fuelgauge.BatterySaverReceiver.BatterySaverListener
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.NoOpKeyedObservable
import com.android.settingslib.fuelgauge.BatterySaverLogging.SAVER_ENABLED_SETTINGS
import com.android.settingslib.fuelgauge.BatterySaverUtils
import com.android.settingslib.fuelgauge.BatteryStatus
import com.android.settingslib.fuelgauge.BatteryUtils
import com.android.settingslib.metadata.MainSwitchPreference
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider

// LINT.IfChange
class BatterySaverPreference :
    MainSwitchPreference(KEY, R.string.battery_saver_master_switch_title),
    PreferenceLifecycleProvider {

    private var batterySaverReceiver: BatterySaverReceiver? = null
    private val handler by lazy { Handler(Looper.getMainLooper()) }

    override fun storage(context: Context) = BatterySaverStore(context)

    override fun isEnabled(context: Context) =
        !BatteryStatus(BatteryUtils.getBatteryIntent(context)).isPluggedIn

    override fun onStart(context: PreferenceLifecycleContext) {
        BatterySaverReceiver(context).apply {
            batterySaverReceiver = this
            setBatterySaverListener(
                object : BatterySaverListener {
                    override fun onPowerSaveModeChanged() {
                        handler.postDelayed(
                            { context.notifyPreferenceChange(this@BatterySaverPreference) },
                            SWITCH_ANIMATION_DURATION,
                        )
                    }

                    override fun onBatteryChanged(pluggedIn: Boolean) =
                        context.notifyPreferenceChange(this@BatterySaverPreference)
                }
            )
            setListening(true)
        }
    }

    override fun onStop(context: PreferenceLifecycleContext) {
        batterySaverReceiver?.setListening(false)
        batterySaverReceiver = null
        handler.removeCallbacksAndMessages(null /* token */)
    }

    @Suppress("UNCHECKED_CAST")
    class BatterySaverStore(private val context: Context) :
        NoOpKeyedObservable<String>(), KeyValueStore {
        override fun contains(key: String) = key == KEY

        override fun <T : Any> getValue(key: String, valueType: Class<T>) =
            context.isPowerSaveMode() as T

        override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
            BatterySaverUtils.setPowerSaveMode(
                context,
                value as Boolean,
                /* needFirstTimeWarning= */ false,
                SAVER_ENABLED_SETTINGS,
            )
        }

        private fun Context.isPowerSaveMode() =
            getSystemService(PowerManager::class.java)?.isPowerSaveMode == true
    }

    companion object {
        private const val KEY = "battery_saver"
        private const val SWITCH_ANIMATION_DURATION: Long = 350L
    }
}
// LINT.ThenChange(BatterySaverButtonPreferenceController.java)
+3 −1
Original line number Diff line number Diff line
@@ -39,7 +39,9 @@ class BatterySaverScreen : PreferenceScreenCreator {

    override fun hasCompleteHierarchy() = false

    override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
    override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {
        +BatterySaverPreference()
    }

    companion object {
        const val KEY = "battery_saver_screen"
+2 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;

// LINT.IfChange
@RunWith(RobolectricTestRunner.class)
public class BatterySaverButtonPreferenceControllerTest {

@@ -120,3 +121,4 @@ public class BatterySaverButtonPreferenceControllerTest {
        assertThat(mController.isPublicSlice()).isTrue();
    }
}
// LINT.ThenChange(BatterySaverPreferenceTest.kt)
+107 −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.settings.fuelgauge.batterysaver

import android.content.BroadcastReceiver
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager.EXTRA_PLUGGED
import android.os.PowerManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.preference.createAndBindWidget
import com.android.settingslib.widget.MainSwitchPreference
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub
import org.mockito.kotlin.verify

// LINT.IfChange
@RunWith(AndroidJUnit4::class)
class BatterySaverPreferenceTest {
    private val powerManager = mock<PowerManager>()

    private val context: Context =
        object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
            override fun getSystemService(name: String): Any? =
                when {
                    name == getSystemServiceName(PowerManager::class.java) -> powerManager
                    else -> super.getSystemService(name)
                }

            override fun registerReceiver(receiver: BroadcastReceiver?, filter: IntentFilter?) =
                Intent().putExtra(EXTRA_PLUGGED, 0)
        }

    private val contextPlugIn: Context =
        object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
            override fun registerReceiver(receiver: BroadcastReceiver?, filter: IntentFilter?) =
                Intent().putExtra(EXTRA_PLUGGED, 1)
        }

    private val batterySaverPreference = BatterySaverPreference()

    @Test
    fun lowPowerOn_preferenceIsChecked() {
        powerManager.stub { on { isPowerSaveMode } doReturn true }

        assertThat(getMainSwitchPreference().isChecked).isTrue()
    }

    @Test
    fun lowPowerOff_preferenceIsUnChecked() {
        powerManager.stub { on { isPowerSaveMode } doReturn false }

        assertThat(getMainSwitchPreference().isChecked).isFalse()
    }

    @Test
    fun storeSetOn_setPowerSaveMode() {
        batterySaverPreference
            .storage(context)
            .setValue(batterySaverPreference.key, Boolean::class.javaObjectType, true)

        verify(powerManager).setPowerSaveModeEnabled(true)
    }

    @Test
    fun storeSetOff_unsetPowerSaveMode() {
        batterySaverPreference
            .storage(context)
            .setValue(batterySaverPreference.key, Boolean::class.javaObjectType, false)

        verify(powerManager).setPowerSaveModeEnabled(false)
    }

    @Test
    fun isUnPlugIn_preferenceEnabled() {
        assertThat(getMainSwitchPreference().isEnabled).isTrue()
    }

    @Test
    fun isPlugIn_preferenceDisabled() {
        assertThat(getMainSwitchPreference(contextPlugIn).isEnabled).isFalse()
    }

    private fun getMainSwitchPreference(ctx: Context = context) =
        batterySaverPreference.createAndBindWidget<MainSwitchPreference>(ctx)
}
// LINT.ThenChange(BatterySaverButtonPreferenceControllerTest.java)
Loading