Merge "Sticky battery saver" into pi-dev

This commit is contained in:
TreeHugger Robot
2018-03-26 21:41:09 +00:00
committed by Android (Google) Code Review
7 changed files with 1060 additions and 154 deletions

View File

@@ -585,6 +585,7 @@ package android.provider {
field public static final java.lang.String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
field public static final java.lang.String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
field public static final java.lang.String LOW_POWER_MODE = "low_power";
field public static final java.lang.String LOW_POWER_MODE_STICKY = "low_power_sticky";
field public static final java.lang.String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
}

View File

@@ -11004,12 +11004,20 @@ public final class Settings {
public static final String SHOW_PROCESSES = "show_processes";
/**
* If 1 low power mode is enabled.
* If 1 low power mode (aka battery saver) is enabled.
* @hide
*/
@TestApi
public static final String LOW_POWER_MODE = "low_power";
/**
* If 1, battery saver ({@link #LOW_POWER_MODE}) will be re-activated after the device
* is unplugged from a charger or rebooted.
* @hide
*/
@TestApi
public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
/**
* Battery level [1-100] at which low power mode automatically turns on.
* If 0, it will not automatically turn on.

View File

@@ -118,61 +118,60 @@ message PowerManagerServiceDumpProto {
// True if the sandman has just been summoned for the first time since entering
// the dreaming or dozing state. Indicates whether a new dream should begin.
optional bool is_sandman_summoned = 23;
// If true, the device is in low power mode.
optional bool is_low_power_mode_enabled = 24;
// True if the battery level is currently considered low.
optional bool is_battery_level_low = 25;
optional bool is_battery_level_low = 24;
// True if we are currently in light device idle mode.
optional bool is_light_device_idle_mode = 26;
optional bool is_light_device_idle_mode = 25;
// True if we are currently in device idle mode.
optional bool is_device_idle_mode = 27;
optional bool is_device_idle_mode = 26;
// Set of app ids that we will always respect the wake locks for.
repeated int32 device_idle_whitelist = 28;
repeated int32 device_idle_whitelist = 27;
// Set of app ids that are temporarily allowed to acquire wakelocks due to
// high-pri message
repeated int32 device_idle_temp_whitelist = 29;
repeated int32 device_idle_temp_whitelist = 28;
// Timestamp of the last time the device was awoken.
optional int64 last_wake_time_ms = 30;
optional int64 last_wake_time_ms = 29;
// Timestamp of the last time the device was put to sleep.
optional int64 last_sleep_time_ms = 31;
optional int64 last_sleep_time_ms = 30;
// Timestamp of the last call to user activity.
optional int64 last_user_activity_time_ms = 32;
optional int64 last_user_activity_time_no_change_lights_ms = 33;
optional int64 last_user_activity_time_ms = 31;
optional int64 last_user_activity_time_no_change_lights_ms = 32;
// Timestamp of last interactive power hint.
optional int64 last_interactive_power_hint_time_ms = 34;
optional int64 last_interactive_power_hint_time_ms = 33;
// Timestamp of the last screen brightness boost.
optional int64 last_screen_brightness_boost_time_ms = 35;
optional int64 last_screen_brightness_boost_time_ms = 34;
// True if screen brightness boost is in progress.
optional bool is_screen_brightness_boost_in_progress = 36;
optional bool is_screen_brightness_boost_in_progress = 35;
// True if the display power state has been fully applied, which means the
// display is actually on or actually off or whatever was requested.
optional bool is_display_ready = 37;
optional bool is_display_ready = 36;
// True if the wake lock suspend blocker has been acquired.
optional bool is_holding_wake_lock_suspend_blocker = 38;
optional bool is_holding_wake_lock_suspend_blocker = 37;
// The suspend blocker used to keep the CPU alive when the display is on, the
// display is getting ready or there is user activity (in which case the
// display must be on).
optional bool is_holding_display_suspend_blocker = 39;
optional bool is_holding_display_suspend_blocker = 38;
// Settings and configuration
optional PowerServiceSettingsAndConfigurationDumpProto settings_and_configuration = 40;
optional PowerServiceSettingsAndConfigurationDumpProto settings_and_configuration = 39;
// Sleep timeout in ms. This can be -1.
optional sint32 sleep_timeout_ms = 41;
optional sint32 sleep_timeout_ms = 40;
// Screen off timeout in ms
optional int32 screen_off_timeout_ms = 42;
optional int32 screen_off_timeout_ms = 41;
// Screen dim duration in ms
optional int32 screen_dim_duration_ms = 43;
optional int32 screen_dim_duration_ms = 42;
// We are currently in the middle of a batch change of uids.
optional bool are_uids_changing = 44;
optional bool are_uids_changing = 43;
// Some uids have actually changed while mUidsChanging was true.
optional bool are_uids_changed = 45;
optional bool are_uids_changed = 44;
// List of UIDs and their states
repeated UidStateProto uid_states = 46;
optional .android.os.LooperProto looper = 47;
repeated UidStateProto uid_states = 45;
optional .android.os.LooperProto looper = 46;
// List of all wake locks acquired by applications.
repeated WakeLockProto wake_locks = 48;
repeated WakeLockProto wake_locks = 47;
// List of all suspend blockers.
repeated SuspendBlockerProto suspend_blockers = 49;
optional WirelessChargerDetectorProto wireless_charger_detector = 50;
repeated SuspendBlockerProto suspend_blockers = 48;
optional WirelessChargerDetectorProto wireless_charger_detector = 49;
optional BatterySaverStateMachineProto battery_saver_state_machine = 50;
}
// A com.android.server.power.PowerManagerService.SuspendBlockerImpl object.
@@ -270,51 +269,80 @@ message PowerServiceSettingsAndConfigurationDumpProto {
optional bool are_dreams_activate_on_dock_setting = 17;
// True if doze should not be started until after the screen off transition.
optional bool is_doze_after_screen_off_config = 18;
// If true, the device is in low power mode.
optional bool is_low_power_mode_setting = 19;
// Current state of whether the settings are allowing auto low power mode.
optional bool is_auto_low_power_mode_configured = 20;
// The user turned off low power mode below the trigger level
optional bool is_auto_low_power_mode_snoozing = 21;
// The minimum screen off timeout, in milliseconds.
optional int32 minimum_screen_off_timeout_config_ms = 22;
optional int32 minimum_screen_off_timeout_config_ms = 19;
// The screen dim duration, in milliseconds.
optional int32 maximum_screen_dim_duration_config_ms = 23;
optional int32 maximum_screen_dim_duration_config_ms = 20;
// The maximum screen dim time expressed as a ratio relative to the screen off timeout.
optional float maximum_screen_dim_ratio_config = 24;
optional float maximum_screen_dim_ratio_config = 21;
// The screen off timeout setting value in milliseconds.
optional int32 screen_off_timeout_setting_ms = 25;
optional int32 screen_off_timeout_setting_ms = 22;
// The sleep timeout setting value in milliseconds. Default value is -1.
optional sint32 sleep_timeout_setting_ms = 26;
optional sint32 sleep_timeout_setting_ms = 23;
// The maximum allowable screen off timeout according to the device administration policy.
optional int32 maximum_screen_off_timeout_from_device_admin_ms = 27;
optional bool is_maximum_screen_off_timeout_from_device_admin_enforced_locked = 28;
optional int32 maximum_screen_off_timeout_from_device_admin_ms = 24;
optional bool is_maximum_screen_off_timeout_from_device_admin_enforced_locked = 25;
// The stay on while plugged in setting.
// A set of battery conditions under which to make the screen stay on.
optional StayOnWhilePluggedInProto stay_on_while_plugged_in = 29;
optional StayOnWhilePluggedInProto stay_on_while_plugged_in = 26;
// The screen brightness mode.
optional .android.providers.settings.SettingsProto.ScreenBrightnessMode screen_brightness_mode_setting = 30;
optional .android.providers.settings.SettingsProto.ScreenBrightnessMode screen_brightness_mode_setting = 27;
// The screen brightness setting override from the window manager
// to allow the current foreground activity to override the brightness.
// Use -1 to disable.
optional sint32 screen_brightness_override_from_window_manager = 31;
optional sint32 screen_brightness_override_from_window_manager = 28;
// The user activity timeout override from the window manager
// to allow the current foreground activity to override the user activity
// timeout. Use -1 to disable.
optional sint64 user_activity_timeout_override_from_window_manager_ms = 32;
optional sint64 user_activity_timeout_override_from_window_manager_ms = 29;
// The window manager has determined the user to be inactive via other means.
// Set this to false to disable.
optional bool is_user_inactive_override_from_window_manager = 33;
optional bool is_user_inactive_override_from_window_manager = 30;
// The screen state to use while dozing.
optional .android.view.DisplayStateEnum doze_screen_state_override_from_dream_manager = 34;
optional .android.view.DisplayStateEnum doze_screen_state_override_from_dream_manager = 31;
// The screen brightness to use while dozing.
optional float dozed_screen_brightness_override_from_dream_manager = 35;
optional float dozed_screen_brightness_override_from_dream_manager = 32;
// Screen brightness settings limits.
optional ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 36;
optional ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 33;
// True if double tap to wake is enabled
optional bool is_double_tap_wake_enabled = 37;
optional bool is_double_tap_wake_enabled = 34;
// True if we are currently in VR Mode.
optional bool is_vr_mode_enabled = 38;
optional bool is_vr_mode_enabled = 35;
// True if Sidekick is controlling the display and we shouldn't change its power mode.
optional bool draw_wake_lock_override_from_sidekick = 39;
optional bool draw_wake_lock_override_from_sidekick = 36;
}
message BatterySaverStateMachineProto {
// Whether battery saver is enabled.
optional bool enabled = 1;
// Whether system has booted.
optional bool boot_completed = 2;
// Whether settings have been loaded already.
optional bool settings_loaded = 3;
// Whether battery status has been set at least once.
optional bool battery_status_set = 4;
// Whether automatic battery saver has been canceled by the user.
optional bool battery_saver_snoozing = 5;
// Whether the device is connected to any power source.
optional bool is_powered = 6;
// Current battery level in %, 0-100.
optional int32 battery_level = 7;
// Whether battery level is low or not.
optional bool is_battery_level_low = 8;
// The value of Global.LOW_POWER_MODE.
optional bool setting_battery_saver_enabled = 9;
// The value of Global.LOW_POWER_MODE_STICKY.
optional bool setting_battery_saver_enabled_sticky = 10;
// The value of Global.LOW_POWER_MODE_TRIGGER_LEVEL.
optional int32 setting_battery_saver_trigger_threshold = 11;
}

View File

@@ -266,6 +266,7 @@ public class SettingsBackupTest {
Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
Settings.Global.LOW_POWER_MODE,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
Settings.Global.LOW_POWER_MODE_STICKY,
Settings.Global.LTE_SERVICE_FORCED,
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,

View File

@@ -64,6 +64,7 @@ import android.os.UserManager;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal;
import android.service.vr.IVrManager;
@@ -97,6 +98,7 @@ import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.batterysaver.BatterySaverController;
import com.android.server.power.batterysaver.BatterySaverStateMachine;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -225,6 +227,7 @@ public final class PowerManagerService extends SystemService
private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private final BatterySaverPolicy mBatterySaverPolicy;
private final BatterySaverController mBatterySaverController;
private final BatterySaverStateMachine mBatterySaverStateMachine;
private LightsManager mLightsManager;
private BatteryManagerInternal mBatteryManagerInternal;
@@ -492,18 +495,6 @@ public final class PowerManagerService extends SystemService
// Time when we last logged a warning about calling userActivity() without permission.
private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
// If true, the device is in low power mode.
private boolean mLowPowerModeEnabled;
// Current state of the low power mode setting.
private boolean mLowPowerModeSetting;
// Current state of whether the settings are allowing auto low power mode.
private boolean mAutoLowPowerModeConfigured;
// The user turned off low power mode below the trigger level
private boolean mAutoLowPowerModeSnoozing;
// True if the battery level is currently considered low.
private boolean mBatteryLevelLow;
@@ -667,6 +658,7 @@ public final class PowerManagerService extends SystemService
mBatterySaverPolicy = new BatterySaverPolicy(mHandler);
mBatterySaverController = new BatterySaverController(mContext,
BackgroundThread.get().getLooper(), mBatterySaverPolicy);
mBatterySaverStateMachine = new BatterySaverStateMachine(mContext, mBatterySaverController);
synchronized (mLock) {
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
@@ -704,6 +696,7 @@ public final class PowerManagerService extends SystemService
mBatterySaverPolicy = batterySaverPolicy;
mBatterySaverController = new BatterySaverController(context,
BackgroundThread.getHandler().getLooper(), batterySaverPolicy);
mBatterySaverStateMachine = new BatterySaverStateMachine(mContext, mBatterySaverController);
}
@Override
@@ -725,6 +718,8 @@ public final class PowerManagerService extends SystemService
final long now = SystemClock.uptimeMillis();
mBootCompleted = true;
mDirty |= DIRTY_BOOT_COMPLETED;
mBatterySaverStateMachine.onBootCompleted();
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
@@ -819,12 +814,6 @@ public final class PowerManagerService extends SystemService
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.THEATER_MODE_ON),
false, mSettingsObserver, UserHandle.USER_ALL);
@@ -953,17 +942,6 @@ public final class PowerManagerService extends SystemService
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE, 0) != 0;
final boolean autoLowPowerModeConfigured = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) != 0;
if (lowPowerModeEnabled != mLowPowerModeSetting
|| autoLowPowerModeConfigured != mAutoLowPowerModeConfigured) {
mLowPowerModeSetting = lowPowerModeEnabled;
mAutoLowPowerModeConfigured = autoLowPowerModeConfigured;
updateLowPowerModeLocked();
}
mDirty |= DIRTY_SETTINGS;
}
@@ -977,29 +955,6 @@ public final class PowerManagerService extends SystemService
}
}
private void updateLowPowerModeLocked() {
if ((mIsPowered || !mBatteryLevelLow && !mBootCompleted) && mLowPowerModeSetting) {
if (DEBUG_SPEW) {
Slog.d(TAG, "updateLowPowerModeLocked: powered or booting with sufficient battery,"
+ " turning setting off");
}
// Turn setting off if powered
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE, 0);
mLowPowerModeSetting = false;
}
final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured
&& !mAutoLowPowerModeSnoozing && mBatteryLevelLow;
final boolean lowPowerModeEnabled = mLowPowerModeSetting || autoLowPowerModeEnabled;
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
postAfterBootCompleted(() ->
mBatterySaverController.enableBatterySaver(mLowPowerModeEnabled));
}
}
private void handleSettingsChangedLocked() {
updateSettingsLocked();
updatePowerStateLocked();
@@ -1751,15 +1706,7 @@ public final class PowerManagerService extends SystemService
}
}
if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {
if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {
if (DEBUG_SPEW) {
Slog.d(TAG, "updateIsPoweredLocked: resetting low power snooze");
}
mAutoLowPowerModeSnoozing = false;
}
updateLowPowerModeLocked();
}
mBatterySaverStateMachine.setBatteryStatus(mIsPowered, mBatteryLevel, mBatteryLevelLow);
}
}
@@ -2733,36 +2680,20 @@ public final class PowerManagerService extends SystemService
}
private boolean isLowPowerModeInternal() {
synchronized (mLock) {
return mLowPowerModeEnabled;
}
return mBatterySaverController.isEnabled();
}
private boolean setLowPowerModeInternal(boolean mode) {
private boolean setLowPowerModeInternal(boolean enabled) {
synchronized (mLock) {
if (DEBUG) Slog.d(TAG, "setLowPowerModeInternal " + mode + " mIsPowered=" + mIsPowered);
if (DEBUG) {
Slog.d(TAG, "setLowPowerModeInternal " + enabled + " mIsPowered=" + mIsPowered);
}
if (mIsPowered) {
return false;
}
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE, mode ? 1 : 0);
mLowPowerModeSetting = mode;
if (mAutoLowPowerModeConfigured && mBatteryLevelLow) {
if (mode && mAutoLowPowerModeSnoozing) {
if (DEBUG_SPEW) {
Slog.d(TAG, "setLowPowerModeInternal: clearing low power mode snooze");
}
mAutoLowPowerModeSnoozing = false;
} else if (!mode && !mAutoLowPowerModeSnoozing) {
if (DEBUG_SPEW) {
Slog.d(TAG, "setLowPowerModeInternal: snoozing low power mode");
}
mAutoLowPowerModeSnoozing = true;
}
}
mBatterySaverStateMachine.setBatterySaverEnabledManually(enabled);
updateLowPowerModeLocked();
return true;
}
}
@@ -2848,7 +2779,8 @@ public final class PowerManagerService extends SystemService
@VisibleForTesting
void updatePowerRequestFromBatterySaverPolicy(DisplayPowerRequest displayPowerRequest) {
PowerSaveState state = mBatterySaverPolicy.
getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS, mLowPowerModeEnabled);
getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS,
mBatterySaverController.isEnabled());
displayPowerRequest.lowPowerMode = state.batterySaverEnabled;
displayPowerRequest.screenLowPowerBrightnessFactor = state.brightnessFactor;
}
@@ -3325,7 +3257,6 @@ public final class PowerManagerService extends SystemService
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
pw.println(" mSandmanScheduled=" + mSandmanScheduled);
pw.println(" mSandmanSummoned=" + mSandmanSummoned);
pw.println(" mLowPowerModeEnabled=" + mLowPowerModeEnabled);
pw.println(" mBatteryLevelLow=" + mBatteryLevelLow);
pw.println(" mLightDeviceIdleMode=" + mLightDeviceIdleMode);
pw.println(" mDeviceIdleMode=" + mDeviceIdleMode);
@@ -3378,9 +3309,6 @@ public final class PowerManagerService extends SystemService
pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
pw.println(" mDozeAfterScreenOff=" + mDozeAfterScreenOff);
pw.println(" mLowPowerModeSetting=" + mLowPowerModeSetting);
pw.println(" mAutoLowPowerModeConfigured=" + mAutoLowPowerModeConfigured);
pw.println(" mAutoLowPowerModeSnoozing=" + mAutoLowPowerModeSnoozing);
pw.println(" mMinimumScreenOffTimeoutConfig=" + mMinimumScreenOffTimeoutConfig);
pw.println(" mMaximumScreenDimDurationConfig=" + mMaximumScreenDimDurationConfig);
pw.println(" mMaximumScreenDimRatioConfig=" + mMaximumScreenDimRatioConfig);
@@ -3456,6 +3384,7 @@ public final class PowerManagerService extends SystemService
pw.println("Display Power: " + mDisplayPowerCallbacks);
mBatterySaverPolicy.dump(pw);
mBatterySaverStateMachine.dump(pw);
pw.println();
final int numProfiles = mProfilePowerState.size();
@@ -3557,7 +3486,6 @@ public final class PowerManagerService extends SystemService
mRequestWaitForNegativeProximity);
proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SCHEDULED, mSandmanScheduled);
proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SUMMONED, mSandmanSummoned);
proto.write(PowerManagerServiceDumpProto.IS_LOW_POWER_MODE_ENABLED, mLowPowerModeEnabled);
proto.write(PowerManagerServiceDumpProto.IS_BATTERY_LEVEL_LOW, mBatteryLevelLow);
proto.write(PowerManagerServiceDumpProto.IS_LIGHT_DEVICE_IDLE_MODE, mLightDeviceIdleMode);
proto.write(PowerManagerServiceDumpProto.IS_DEVICE_IDLE_MODE, mDeviceIdleMode);
@@ -3662,15 +3590,6 @@ public final class PowerManagerService extends SystemService
proto.write(
PowerServiceSettingsAndConfigurationDumpProto.IS_DOZE_AFTER_SCREEN_OFF_CONFIG,
mDozeAfterScreenOff);
proto.write(
PowerServiceSettingsAndConfigurationDumpProto.IS_LOW_POWER_MODE_SETTING,
mLowPowerModeSetting);
proto.write(
PowerServiceSettingsAndConfigurationDumpProto.IS_AUTO_LOW_POWER_MODE_CONFIGURED,
mAutoLowPowerModeConfigured);
proto.write(
PowerServiceSettingsAndConfigurationDumpProto.IS_AUTO_LOW_POWER_MODE_SNOOZING,
mAutoLowPowerModeSnoozing);
proto.write(
PowerServiceSettingsAndConfigurationDumpProto
.MINIMUM_SCREEN_OFF_TIMEOUT_CONFIG_MS,
@@ -3792,6 +3711,9 @@ public final class PowerManagerService extends SystemService
proto.end(uIDToken);
}
mBatterySaverStateMachine.dumpProto(proto,
PowerManagerServiceDumpProto.BATTERY_SAVER_STATE_MACHINE);
mHandler.getLooper().writeToProto(proto, PowerManagerServiceDumpProto.LOOPER);
for (WakeLock wl : mWakeLocks) {
@@ -4432,12 +4354,12 @@ public final class PowerManagerService extends SystemService
}
@Override // Binder call
public boolean setPowerSaveMode(boolean mode) {
public boolean setPowerSaveMode(boolean enabled) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final long ident = Binder.clearCallingIdentity();
try {
return setLowPowerModeInternal(mode);
return setLowPowerModeInternal(enabled);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4752,7 +4674,8 @@ public final class PowerManagerService extends SystemService
@Override
public PowerSaveState getLowPowerState(@ServiceType int serviceType) {
synchronized (mLock) {
return mBatterySaverPolicy.getBatterySaverPolicy(serviceType, mLowPowerModeEnabled);
return mBatterySaverPolicy.getBatterySaverPolicy(serviceType,
mBatterySaverController.isEnabled());
}
}

View File

@@ -0,0 +1,413 @@
/*
* Copyright (C) 2018 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.server.power.batterysaver;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.power.BatterySaverPolicy;
import com.android.server.power.BatterySaverStateMachineProto;
import java.io.PrintWriter;
/**
* Decides when to enable / disable battery saver.
*
* (n.b. This isn't really implemented as a "state machine" though.)
*
* Test:
atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
*/
public class BatterySaverStateMachine {
private static final String TAG = "BatterySaverStateMachine";
private final Object mLock = new Object();
private static final boolean DEBUG = BatterySaverPolicy.DEBUG;
private final Context mContext;
private final BatterySaverController mBatterySaverController;
/** Whether the system has booted. */
@GuardedBy("mLock")
private boolean mBootCompleted;
/** Whether global settings have been loaded already. */
@GuardedBy("mLock")
private boolean mSettingsLoaded;
/** Whether the first battery status has arrived. */
@GuardedBy("mLock")
private boolean mBatteryStatusSet;
/** Whether the device is connected to any power source. */
@GuardedBy("mLock")
private boolean mIsPowered;
/** Current battery level in %, 0-100. (Currently only used in dumpsys.) */
@GuardedBy("mLock")
private int mBatteryLevel;
/** Whether the battery level is considered to be "low" or not.*/
@GuardedBy("mLock")
private boolean mIsBatteryLevelLow;
/** Previously known value of Global.LOW_POWER_MODE. */
@GuardedBy("mLock")
private boolean mSettingBatterySaverEnabled;
/** Previously known value of Global.LOW_POWER_MODE_STICKY. */
@GuardedBy("mLock")
private boolean mSettingBatterySaverEnabledSticky;
/**
* Previously known value of Global.LOW_POWER_MODE_TRIGGER_LEVEL.
* (Currently only used in dumpsys.)
*/
@GuardedBy("mLock")
private int mSettingBatterySaverTriggerThreshold;
/**
* Whether BS has been manually disabled while the battery level is low, in which case we
* shouldn't auto re-enable it until the battery level is not low.
*/
@GuardedBy("mLock")
private boolean mBatterySaverSnoozing;
private final ContentObserver mSettingsObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
synchronized (mLock) {
refreshSettingsLocked();
}
}
};
public BatterySaverStateMachine(
Context context, BatterySaverController batterySaverController) {
mContext = context;
mBatterySaverController = batterySaverController;
}
private boolean isBatterySaverEnabled() {
return mBatterySaverController.isEnabled();
}
private boolean isAutoBatterySaverConfigured() {
return mSettingBatterySaverTriggerThreshold > 0;
}
/**
* {@link com.android.server.power.PowerManagerService} calls it when the system is booted.
*/
public void onBootCompleted() {
if (DEBUG) {
Slog.d(TAG, "onBootCompleted");
}
synchronized (mLock) {
final ContentResolver cr = mContext.getContentResolver();
cr.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE),
false, mSettingsObserver, UserHandle.USER_SYSTEM);
cr.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE_STICKY),
false, mSettingsObserver, UserHandle.USER_SYSTEM);
cr.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
false, mSettingsObserver, UserHandle.USER_SYSTEM);
mBootCompleted = true;
refreshSettingsLocked();
doAutoBatterySaverLocked();
}
}
void refreshSettingsLocked() {
final ContentResolver cr = mContext.getContentResolver();
final boolean lowPowerModeEnabled = getGlobalSetting(
Settings.Global.LOW_POWER_MODE, 0) != 0;
final boolean lowPowerModeEnabledSticky = getGlobalSetting(
Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0;
final int lowPowerModeTriggerLevel = getGlobalSetting(
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
setSettingsLocked(lowPowerModeEnabled, lowPowerModeEnabledSticky,
lowPowerModeTriggerLevel);
}
/**
* {@link com.android.server.power.PowerManagerService} calls it when relevant global settings
* have changed.
*
* Note this will be called before {@link #onBootCompleted} too.
*/
@VisibleForTesting
void setSettingsLocked(boolean batterySaverEnabled, boolean batterySaverEnabledSticky,
int batterySaverTriggerThreshold) {
if (DEBUG) {
Slog.d(TAG, "setSettings: enabled=" + batterySaverEnabled
+ " sticky=" + batterySaverEnabledSticky
+ " threshold=" + batterySaverTriggerThreshold);
}
mSettingsLoaded = true;
final boolean enabledChanged = mSettingBatterySaverEnabled != batterySaverEnabled;
final boolean stickyChanged =
mSettingBatterySaverEnabledSticky != batterySaverEnabledSticky;
final boolean thresholdChanged
= mSettingBatterySaverTriggerThreshold != batterySaverTriggerThreshold;
if (!(enabledChanged || stickyChanged || thresholdChanged)) {
return;
}
mSettingBatterySaverEnabled = batterySaverEnabled;
mSettingBatterySaverEnabledSticky = batterySaverEnabledSticky;
mSettingBatterySaverTriggerThreshold = batterySaverTriggerThreshold;
if (enabledChanged) {
final String reason = batterySaverEnabled
? "Global.low_power changed to 1" : "Global.low_power changed to 0";
enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true,
reason);
}
}
/**
* {@link com.android.server.power.PowerManagerService} calls it when battery state changes.
*
* Note this may be called before {@link #onBootCompleted} too.
*/
public void setBatteryStatus(boolean newPowered, int newLevel, boolean newBatteryLevelLow) {
if (DEBUG) {
Slog.d(TAG, "setBatteryStatus: powered=" + newPowered + " level=" + newLevel
+ " low=" + newBatteryLevelLow);
}
synchronized (mLock) {
mBatteryStatusSet = true;
final boolean poweredChanged = mIsPowered != newPowered;
final boolean levelChanged = mBatteryLevel != newLevel;
final boolean lowChanged = mIsBatteryLevelLow != newBatteryLevelLow;
if (!(poweredChanged || levelChanged || lowChanged)) {
return;
}
mIsPowered = newPowered;
mBatteryLevel = newLevel;
mIsBatteryLevelLow = newBatteryLevelLow;
doAutoBatterySaverLocked();
}
}
/**
* Decide whether to auto-start / stop battery saver.
*/
private void doAutoBatterySaverLocked() {
if (DEBUG) {
Slog.d(TAG, "doAutoBatterySaverLocked: mBootCompleted=" + mBootCompleted
+ " mSettingsLoaded=" + mSettingsLoaded
+ " mBatteryStatusSet=" + mBatteryStatusSet
+ " mIsBatteryLevelLow=" + mIsBatteryLevelLow
+ " mBatterySaverSnoozing=" + mBatterySaverSnoozing
+ " mIsPowered=" + mIsPowered
+ " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky);
}
if (!(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
return; // Not fully initialized yet.
}
if (!mIsBatteryLevelLow) {
updateSnoozingLocked(false, "Battery not low");
}
if (mIsPowered) {
updateSnoozingLocked(false, "Plugged in");
enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, "Plugged in");
} else if (mSettingBatterySaverEnabledSticky) {
// Re-enable BS.
enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true, "Sticky restore");
} else if (mIsBatteryLevelLow) {
if (!mBatterySaverSnoozing && isAutoBatterySaverConfigured()) {
enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false, "Auto ON");
}
} else { // Battery not low
enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, "Auto OFF");
}
}
/**
* {@link com.android.server.power.PowerManagerService} calls it when
* {@link android.os.PowerManager#setPowerSaveMode} is called.
*
* Note this could? be called before {@link #onBootCompleted} too.
*/
public void setBatterySaverEnabledManually(boolean enabled) {
if (DEBUG) {
Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled);
}
synchronized (mLock) {
enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
(enabled ? "Manual ON" : "Manual OFF"));
}
}
/**
* Actually enable / disable battery saver. Write the new state to the global settings
* and propagate it to {@link #mBatterySaverController}.
*/
private void enableBatterySaverLocked(boolean enable, boolean manual, String reason) {
if (DEBUG) {
Slog.d(TAG, "enableBatterySaver: enable=" + enable + " manual=" + manual
+ " reason=" + reason);
}
final boolean wasEnabled = mBatterySaverController.isEnabled();
if (wasEnabled == enable) {
if (DEBUG) {
Slog.d(TAG, "Already " + (enable ? "enabled" : "disabled"));
}
return;
}
if (enable && mIsPowered) {
if (DEBUG) Slog.d(TAG, "Can't enable: isPowered");
return;
}
if (manual) {
if (enable) {
updateSnoozingLocked(false, "Manual snooze OFF");
} else {
// When battery saver is disabled manually (while battery saver is enabled)
// when the battery level is low, we "snooze" BS -- i.e. disable auto battery saver.
// We resume auto-BS once the battery level is not low, or the device is plugged in.
if (isBatterySaverEnabled() && mIsBatteryLevelLow) {
updateSnoozingLocked(true, "Manual snooze");
}
}
}
mSettingBatterySaverEnabled = enable;
putGlobalSetting(Global.LOW_POWER_MODE, enable ? 1 : 0);
if (manual) {
mSettingBatterySaverEnabledSticky = enable;
putGlobalSetting(Global.LOW_POWER_MODE_STICKY, enable ? 1 : 0);
}
mBatterySaverController.enableBatterySaver(enable);
if (DEBUG) {
Slog.d(TAG, "Battery saver: Enabled=" + enable
+ " manual=" + manual
+ " reason=" + reason);
}
}
private void updateSnoozingLocked(boolean snoozing, String reason) {
if (mBatterySaverSnoozing == snoozing) {
return;
}
if (DEBUG) Slog.d(TAG, "Snooze: " + (snoozing ? "start" : "stop") + " reason=" + reason);
mBatterySaverSnoozing = snoozing;
}
@VisibleForTesting
protected void putGlobalSetting(String key, int value) {
Global.putInt(mContext.getContentResolver(), key, value);
}
@VisibleForTesting
protected int getGlobalSetting(String key, int defValue) {
return Global.getInt(mContext.getContentResolver(), key, defValue);
}
public void dump(PrintWriter pw) {
synchronized (mLock) {
pw.println();
pw.println("Battery saver state machine:");
pw.print(" Enabled=");
pw.println(mBatterySaverController.isEnabled());
pw.print(" mBootCompleted=");
pw.println(mBootCompleted);
pw.print(" mSettingsLoaded=");
pw.println(mSettingsLoaded);
pw.print(" mBatteryStatusSet=");
pw.println(mBatteryStatusSet);
pw.print(" mBatterySaverSnoozing=");
pw.println(mBatterySaverSnoozing);
pw.print(" mIsPowered=");
pw.println(mIsPowered);
pw.print(" mBatteryLevel=");
pw.println(mBatteryLevel);
pw.print(" mIsBatteryLevelLow=");
pw.println(mIsBatteryLevelLow);
pw.print(" mSettingBatterySaverEnabled=");
pw.println(mSettingBatterySaverEnabled);
pw.print(" mSettingBatterySaverEnabledSticky=");
pw.println(mSettingBatterySaverEnabledSticky);
pw.print(" mSettingBatterySaverTriggerThreshold=");
pw.println(mSettingBatterySaverTriggerThreshold);
}
}
public void dumpProto(ProtoOutputStream proto, long tag) {
synchronized (mLock) {
final long token = proto.start(tag);
proto.write(BatterySaverStateMachineProto.ENABLED,
mBatterySaverController.isEnabled());
proto.write(BatterySaverStateMachineProto.BOOT_COMPLETED, mBootCompleted);
proto.write(BatterySaverStateMachineProto.SETTINGS_LOADED, mSettingsLoaded);
proto.write(BatterySaverStateMachineProto.BATTERY_STATUS_SET, mBatteryStatusSet);
proto.write(BatterySaverStateMachineProto.BATTERY_SAVER_SNOOZING,
mBatterySaverSnoozing);
proto.write(BatterySaverStateMachineProto.IS_POWERED, mIsPowered);
proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel);
proto.write(BatterySaverStateMachineProto.IS_BATTERY_LEVEL_LOW, mIsBatteryLevelLow);
proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED,
mSettingBatterySaverEnabled);
proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED_STICKY,
mSettingBatterySaverEnabledSticky);
proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_TRIGGER_THRESHOLD,
mSettingBatterySaverTriggerThreshold);
proto.end(token);
}
}
}

View File

@@ -0,0 +1,532 @@
/*
* Copyright (C) 2018 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.server.power.batterysaver;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.provider.Settings.Global;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContext;
import com.google.common.base.Objects;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.HashMap;
/**
atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BatterySaverStateMachineTest {
private MyMockContext mMockContext;
private ContentResolver mMockContextResolver;
private BatterySaverController mMockBatterySaverController;
private Device mDevice;
private TestableBatterySaverStateMachine mTarget;
private class MyMockContext extends MockContext {
@Override
public ContentResolver getContentResolver() {
return mMockContextResolver;
}
}
private DevicePersistedState mPersistedState;
private class DevicePersistedState {
// Current battery level.
public int batteryLevel = 100;
// Whether battery level is currently low or not.
public boolean batteryLow = false;
// Whether the device is plugged in or not.
public boolean powered = false;
// Global settings.
public final HashMap<String, Integer> global = new HashMap<>();
}
/**
* This class simulates a device's volatile status that will be reset by {@link #initDevice()}.
*/
private class Device {
public boolean batterySaverEnabled = false;
public int getLowPowerModeTriggerLevel() {
return mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
}
public void setBatteryLevel(int level) {
mPersistedState.batteryLevel = level;
if (mPersistedState.batteryLevel <= Math.max(15, getLowPowerModeTriggerLevel())) {
mPersistedState.batteryLow = true;
} else if (mPersistedState.batteryLow
&& (mPersistedState.batteryLevel >= (getLowPowerModeTriggerLevel() + 5))) {
mPersistedState.batteryLow = false;
}
pushBatteryStatus();
}
public void setPowered(boolean newPowered) {
mPersistedState.powered = newPowered;
pushBatteryStatus();
}
public void pushBatteryStatus() {
mTarget.setBatteryStatus(mPersistedState.powered, mPersistedState.batteryLevel,
mPersistedState.batteryLow);
}
public void pushGlobalSettings() {
mTarget.setSettingsLocked(
mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE, 0) != 0,
mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_STICKY, 0) != 0,
mDevice.getLowPowerModeTriggerLevel());
}
public void putGlobalSetting(String key, int value) {
mPersistedState.global.put(key, value);
pushGlobalSettings();
}
public int getGlobalSetting(String key, int defValue) {
return mPersistedState.global.getOrDefault(key, defValue);
}
}
/**
* Test target class.
*/
private class TestableBatterySaverStateMachine extends BatterySaverStateMachine {
public TestableBatterySaverStateMachine() {
super(mMockContext, mMockBatterySaverController);
}
@Override
protected void putGlobalSetting(String key, int value) {
if (Objects.equal(mPersistedState.global.get(key), value)) {
return;
}
mDevice.putGlobalSetting(key, value);
}
@Override
protected int getGlobalSetting(String key, int defValue) {
return mDevice.getGlobalSetting(key, defValue);
}
}
@Before
public void setUp() {
mMockContext = new MyMockContext();
mMockContextResolver = mock(ContentResolver.class);
mMockBatterySaverController = mock(BatterySaverController.class);
doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
.when(mMockBatterySaverController).enableBatterySaver(anyBoolean());
when(mMockBatterySaverController.isEnabled())
.thenAnswer((inv) -> mDevice.batterySaverEnabled);
mPersistedState = new DevicePersistedState();
initDevice();
}
private void initDevice() {
mDevice = new Device();
mTarget = new TestableBatterySaverStateMachine();
mDevice.pushBatteryStatus();
mDevice.pushGlobalSettings();
mTarget.onBootCompleted();
}
@Test
public void testNoAutoBatterySaver() {
assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(100, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(90);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(50);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(50, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(16);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(16, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// When LOW_POWER_MODE_TRIGGER_LEVEL is 0, 15% will still trigger low-battery, but
// BS wont be enabled.
mDevice.setBatteryLevel(15);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(15, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setBatteryLevel(10);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(10, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
// Manually enable BS.
mTarget.setBatterySaverEnabledManually(true);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(10, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setBatteryLevel(50);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(50, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// Start charging. It'll disable BS.
mDevice.setPowered(true);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(50, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(60);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(60, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// Unplug.
mDevice.setPowered(false);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(60, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(10);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(10, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setBatteryLevel(80);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(80, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// Reboot the device.
initDevice();
assertEquals(true, mDevice.batterySaverEnabled); // Sticky.
assertEquals(80, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(30);
initDevice();
assertEquals(true, mDevice.batterySaverEnabled); // Still sticky.
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mTarget.setBatterySaverEnabledManually(false);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
initDevice(); // reboot.
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
}
@Test
public void testAutoBatterySaver() {
mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(100, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(90);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(51);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(51, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// Hit the threshold. BS should be enabled.
mDevice.setBatteryLevel(50);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(50, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
// Battery goes up, but until it hits 55%, we still keep BS on.
mDevice.setBatteryLevel(54);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(54, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
// 50% + 5%, now BS will be off.
mDevice.setBatteryLevel(55);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(55, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(40);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(40, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setPowered(true);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(40, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setPowered(false);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(40, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(40, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setBatteryLevel(30);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
// Plug in and out, snooze will reset.
mDevice.setPowered(true);
mDevice.setPowered(false);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setPowered(true);
mDevice.setBatteryLevel(60);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(60, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setPowered(false);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(60, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(50);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(50, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setBatteryLevel(70);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(70, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// Bump ump the threshold.
mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 70);
mDevice.setBatteryLevel(mPersistedState.batteryLevel);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(70, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
// Then down.
mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 60);
mDevice.setBatteryLevel(mPersistedState.batteryLevel);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(70, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// Reboot in low state -> automatically enable BS.
mDevice.setPowered(false);
mDevice.setBatteryLevel(30);
mTarget.setBatterySaverEnabledManually(false);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
initDevice();
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
}
@Test
public void testAutoBatterySaver_withSticky() {
mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
mTarget.setBatterySaverEnabledManually(true);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(100, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(30);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setBatteryLevel(80);
assertEquals(true, mDevice.batterySaverEnabled); // Still enabled.
assertEquals(80, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setPowered(true);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(80, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(30);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setPowered(false);
assertEquals(true, mDevice.batterySaverEnabled); // Restores BS.
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
mDevice.setPowered(true);
mDevice.setBatteryLevel(90);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
initDevice();
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setPowered(false);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mTarget.setBatterySaverEnabledManually(false);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
initDevice();
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
}
@Test
public void testNoAutoBatterySaver_fromAdb() {
assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(100, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
mDevice.setBatteryLevel(90);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// Enable
mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 1);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// Disable
mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 0);
assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// Enable again
mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 1);
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
// Reboot -- setting BS from adb is also sticky.
initDevice();
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
}
}