Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | package com.android.server.power.batterysaver; |
| 17 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 18 | import static com.android.server.power.batterysaver.BatterySaverController.reasonToString; |
| 19 | |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 20 | import android.annotation.NonNull; |
| 21 | import android.annotation.StringRes; |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 22 | import android.app.Notification; |
| 23 | import android.app.NotificationChannel; |
| 24 | import android.app.NotificationManager; |
| 25 | import android.app.PendingIntent; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 26 | import android.content.ContentResolver; |
| 27 | import android.content.Context; |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 28 | import android.content.Intent; |
| 29 | import android.content.res.Resources; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 30 | import android.database.ContentObserver; |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 31 | import android.os.BatterySaverPolicyConfig; |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 32 | import android.os.Handler; |
Salvador Martinez | 812ea75 | 2018-10-19 13:03:20 -0700 | [diff] [blame] | 33 | import android.os.PowerManager; |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 34 | import android.os.SystemClock; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 35 | import android.os.UserHandle; |
| 36 | import android.provider.Settings; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 37 | import android.util.Slog; |
| 38 | import android.util.proto.ProtoOutputStream; |
| 39 | |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 40 | import com.android.internal.R; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 41 | import com.android.internal.annotations.GuardedBy; |
| 42 | import com.android.internal.annotations.VisibleForTesting; |
Makoto Onuki | 6e5eb1d | 2018-03-30 16:15:35 -0700 | [diff] [blame] | 43 | import com.android.internal.os.BackgroundThread; |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 44 | import com.android.server.EventLogTags; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 45 | import com.android.server.power.BatterySaverStateMachineProto; |
| 46 | |
| 47 | import java.io.PrintWriter; |
Kweku Adams | 3c95ee1 | 2019-03-21 13:06:53 -0700 | [diff] [blame] | 48 | import java.text.NumberFormat; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 49 | |
| 50 | /** |
| 51 | * Decides when to enable / disable battery saver. |
| 52 | * |
Makoto Onuki | bd7a625 | 2018-05-10 13:41:39 -0700 | [diff] [blame] | 53 | * IMPORTANT: This class shares the power manager lock, which is very low in the lock hierarchy. |
| 54 | * Do not call out with the lock held. (Settings provider is okay.) |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 55 | * |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 56 | * Test: atest com.android.server.power.batterysaver.BatterySaverStateMachineTest |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 57 | * |
| 58 | * Current state machine. This can be visualized using Graphviz: |
| 59 | <pre> |
| 60 | |
| 61 | digraph { |
| 62 | STATE_OFF |
| 63 | STATE_MANUAL_ON [label="STATE_MANUAL_ON\nTurned on manually by the user"] |
| 64 | STATE_AUTOMATIC_ON [label="STATE_AUTOMATIC_ON\nTurned on automatically by the system"] |
| 65 | STATE_OFF_AUTOMATIC_SNOOZED [ |
| 66 | label="STATE_OFF_AUTOMATIC_SNOOZED\nTurned off manually by the user." |
| 67 | + " The system should not turn it back on automatically." |
| 68 | ] |
| 69 | STATE_PENDING_STICKY_ON [ |
| 70 | label="STATE_PENDING_STICKY_ON\n" |
| 71 | + " Turned on manually by the user and then plugged in. Will turn back on after unplug." |
| 72 | ] |
| 73 | |
| 74 | STATE_OFF -> STATE_MANUAL_ON [label="manual"] |
| 75 | STATE_OFF -> STATE_AUTOMATIC_ON [label="Auto on AND charge <= auto threshold"] |
| 76 | |
| 77 | STATE_MANUAL_ON -> STATE_OFF [label="manual\nOR\nPlugged & sticky disabled"] |
| 78 | STATE_MANUAL_ON -> STATE_PENDING_STICKY_ON [label="Plugged & sticky enabled"] |
| 79 | |
| 80 | STATE_PENDING_STICKY_ON -> STATE_MANUAL_ON [label="Unplugged & sticky enabled"] |
| 81 | STATE_PENDING_STICKY_ON -> STATE_OFF [ |
| 82 | label="Sticky disabled\nOR\nSticky auto off enabled AND charge >= sticky auto off threshold" |
| 83 | ] |
| 84 | |
| 85 | STATE_AUTOMATIC_ON -> STATE_OFF [label="Plugged"] |
| 86 | STATE_AUTOMATIC_ON -> STATE_OFF_AUTOMATIC_SNOOZED [label="Manual"] |
| 87 | |
| 88 | STATE_OFF_AUTOMATIC_SNOOZED -> STATE_OFF [label="Plug\nOR\nCharge > auto threshold"] |
| 89 | STATE_OFF_AUTOMATIC_SNOOZED -> STATE_MANUAL_ON [label="manual"] |
| 90 | |
| 91 | </pre> |
| 92 | } |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 93 | */ |
| 94 | public class BatterySaverStateMachine { |
| 95 | private static final String TAG = "BatterySaverStateMachine"; |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 96 | private static final String DYNAMIC_MODE_NOTIF_CHANNEL_ID = "dynamic_mode_notification"; |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 97 | private static final String BATTERY_SAVER_NOTIF_CHANNEL_ID = "battery_saver_channel"; |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 98 | private static final int DYNAMIC_MODE_NOTIFICATION_ID = 1992; |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 99 | private static final int STICKY_AUTO_DISABLED_NOTIFICATION_ID = 1993; |
Makoto Onuki | bd7a625 | 2018-05-10 13:41:39 -0700 | [diff] [blame] | 100 | private final Object mLock; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 101 | |
| 102 | private static final boolean DEBUG = BatterySaverPolicy.DEBUG; |
| 103 | |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 104 | private static final long ADAPTIVE_CHANGE_TIMEOUT_MS = 24 * 60 * 60 * 1000L; |
| 105 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 106 | /** Turn off adaptive battery saver if the device has charged above this level. */ |
| 107 | private static final int ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL = 80; |
| 108 | |
| 109 | private static final int STATE_OFF = BatterySaverStateMachineProto.STATE_OFF; |
| 110 | |
| 111 | /** Turned on manually by the user. */ |
| 112 | private static final int STATE_MANUAL_ON = BatterySaverStateMachineProto.STATE_MANUAL_ON; |
| 113 | |
| 114 | /** Turned on automatically by the system. */ |
| 115 | private static final int STATE_AUTOMATIC_ON = BatterySaverStateMachineProto.STATE_AUTOMATIC_ON; |
| 116 | |
| 117 | /** Turned off manually by the user. The system should not turn it back on automatically. */ |
| 118 | private static final int STATE_OFF_AUTOMATIC_SNOOZED = |
| 119 | BatterySaverStateMachineProto.STATE_OFF_AUTOMATIC_SNOOZED; |
| 120 | |
| 121 | /** Turned on manually by the user and then plugged in. Will turn back on after unplug. */ |
| 122 | private static final int STATE_PENDING_STICKY_ON = |
| 123 | BatterySaverStateMachineProto.STATE_PENDING_STICKY_ON; |
| 124 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 125 | private final Context mContext; |
| 126 | private final BatterySaverController mBatterySaverController; |
| 127 | |
| 128 | /** Whether the system has booted. */ |
| 129 | @GuardedBy("mLock") |
| 130 | private boolean mBootCompleted; |
| 131 | |
| 132 | /** Whether global settings have been loaded already. */ |
| 133 | @GuardedBy("mLock") |
| 134 | private boolean mSettingsLoaded; |
| 135 | |
| 136 | /** Whether the first battery status has arrived. */ |
| 137 | @GuardedBy("mLock") |
| 138 | private boolean mBatteryStatusSet; |
| 139 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 140 | @GuardedBy("mLock") |
| 141 | private int mState; |
| 142 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 143 | /** Whether the device is connected to any power source. */ |
| 144 | @GuardedBy("mLock") |
| 145 | private boolean mIsPowered; |
| 146 | |
| 147 | /** Current battery level in %, 0-100. (Currently only used in dumpsys.) */ |
| 148 | @GuardedBy("mLock") |
| 149 | private int mBatteryLevel; |
| 150 | |
Michael Kwan | e322502 | 2018-06-26 18:03:38 -0700 | [diff] [blame] | 151 | /** Whether the battery level is considered to be "low" or not. */ |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 152 | @GuardedBy("mLock") |
| 153 | private boolean mIsBatteryLevelLow; |
| 154 | |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 155 | /** Previously known value of Settings.Global.LOW_POWER_MODE. */ |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 156 | @GuardedBy("mLock") |
| 157 | private boolean mSettingBatterySaverEnabled; |
| 158 | |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 159 | /** Previously known value of Settings.Global.LOW_POWER_MODE_STICKY. */ |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 160 | @GuardedBy("mLock") |
| 161 | private boolean mSettingBatterySaverEnabledSticky; |
| 162 | |
Michael Kwan | e322502 | 2018-06-26 18:03:38 -0700 | [diff] [blame] | 163 | /** Config flag to track if battery saver's sticky behaviour is disabled. */ |
| 164 | private final boolean mBatterySaverStickyBehaviourDisabled; |
| 165 | |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 166 | /** |
| 167 | * Whether or not to end sticky battery saver upon reaching a level specified by |
| 168 | * {@link #mSettingBatterySaverStickyAutoDisableThreshold}. |
| 169 | */ |
| 170 | @GuardedBy("mLock") |
| 171 | private boolean mSettingBatterySaverStickyAutoDisableEnabled; |
| 172 | |
| 173 | /** |
| 174 | * The battery level at which to end sticky battery saver. Only useful if |
| 175 | * {@link #mSettingBatterySaverStickyAutoDisableEnabled} is {@code true}. |
| 176 | */ |
| 177 | @GuardedBy("mLock") |
| 178 | private int mSettingBatterySaverStickyAutoDisableThreshold; |
| 179 | |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 180 | /** Config flag to track default disable threshold for Dynamic Power Savings enabled battery |
| 181 | * saver. */ |
| 182 | @GuardedBy("mLock") |
| 183 | private final int mDynamicPowerSavingsDefaultDisableThreshold; |
| 184 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 185 | /** |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 186 | * Previously known value of Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL. |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 187 | * (Currently only used in dumpsys.) |
| 188 | */ |
| 189 | @GuardedBy("mLock") |
| 190 | private int mSettingBatterySaverTriggerThreshold; |
| 191 | |
Salvador Martinez | b85a9f8 | 2019-03-20 16:21:27 -0700 | [diff] [blame] | 192 | /** Previously known value of Settings.Global.AUTOMATIC_POWER_SAVE_MODE. */ |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 193 | @GuardedBy("mLock") |
| 194 | private int mSettingAutomaticBatterySaver; |
| 195 | |
| 196 | /** When to disable battery saver again if it was enabled due to an external suggestion. |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 197 | * Corresponds to Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD. |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 198 | */ |
| 199 | @GuardedBy("mLock") |
| 200 | private int mDynamicPowerSavingsDisableThreshold; |
| 201 | |
| 202 | /** |
| 203 | * Whether we've received a suggestion that battery saver should be on from an external app. |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 204 | * Updates when Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED changes. |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 205 | */ |
| 206 | @GuardedBy("mLock") |
| 207 | private boolean mDynamicPowerSavingsBatterySaver; |
| 208 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 209 | /** |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 210 | * Last reason passed to {@link #enableBatterySaverLocked}. |
| 211 | */ |
| 212 | @GuardedBy("mLock") |
| 213 | private int mLastChangedIntReason; |
| 214 | |
| 215 | /** |
| 216 | * Last reason passed to {@link #enableBatterySaverLocked}. |
| 217 | */ |
| 218 | @GuardedBy("mLock") |
| 219 | private String mLastChangedStrReason; |
| 220 | |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 221 | /** |
| 222 | * The last time adaptive battery saver was changed by an external service, using elapsed |
| 223 | * realtime as the timebase. |
| 224 | */ |
| 225 | @GuardedBy("mLock") |
| 226 | private long mLastAdaptiveBatterySaverChangedExternallyElapsed; |
| 227 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 228 | private final ContentObserver mSettingsObserver = new ContentObserver(null) { |
| 229 | @Override |
| 230 | public void onChange(boolean selfChange) { |
| 231 | synchronized (mLock) { |
| 232 | refreshSettingsLocked(); |
| 233 | } |
| 234 | } |
| 235 | }; |
| 236 | |
Makoto Onuki | bd7a625 | 2018-05-10 13:41:39 -0700 | [diff] [blame] | 237 | public BatterySaverStateMachine(Object lock, |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 238 | Context context, BatterySaverController batterySaverController) { |
Makoto Onuki | bd7a625 | 2018-05-10 13:41:39 -0700 | [diff] [blame] | 239 | mLock = lock; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 240 | mContext = context; |
| 241 | mBatterySaverController = batterySaverController; |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 242 | mState = STATE_OFF; |
Michael Kwan | e322502 | 2018-06-26 18:03:38 -0700 | [diff] [blame] | 243 | |
| 244 | mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean( |
| 245 | com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled); |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 246 | mDynamicPowerSavingsDefaultDisableThreshold = mContext.getResources().getInteger( |
| 247 | com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 248 | } |
| 249 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 250 | /** @return true if the automatic percentage based mode should be used */ |
| 251 | private boolean isAutomaticModeActiveLocked() { |
Salvador Martinez | b85a9f8 | 2019-03-20 16:21:27 -0700 | [diff] [blame] | 252 | return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 253 | && mSettingBatterySaverTriggerThreshold > 0; |
| 254 | } |
| 255 | |
| 256 | /** |
| 257 | * The returned value won't necessarily make sense if {@link #isAutomaticModeActiveLocked()} |
| 258 | * returns {@code false}. |
| 259 | * |
| 260 | * @return true if the battery level is below automatic's threshold. |
| 261 | */ |
| 262 | private boolean isInAutomaticLowZoneLocked() { |
| 263 | return mIsBatteryLevelLow; |
| 264 | } |
| 265 | |
| 266 | /** @return true if the dynamic mode should be used */ |
| 267 | private boolean isDynamicModeActiveLocked() { |
Salvador Martinez | b85a9f8 | 2019-03-20 16:21:27 -0700 | [diff] [blame] | 268 | return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 269 | && mDynamicPowerSavingsBatterySaver; |
| 270 | } |
| 271 | |
| 272 | /** |
| 273 | * The returned value won't necessarily make sense if {@link #isDynamicModeActiveLocked()} |
| 274 | * returns {@code false}. |
| 275 | * |
| 276 | * @return true if the battery level is below dynamic's threshold. |
| 277 | */ |
| 278 | private boolean isInDynamicLowZoneLocked() { |
| 279 | return mBatteryLevel <= mDynamicPowerSavingsDisableThreshold; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 280 | } |
| 281 | |
| 282 | /** |
| 283 | * {@link com.android.server.power.PowerManagerService} calls it when the system is booted. |
| 284 | */ |
| 285 | public void onBootCompleted() { |
| 286 | if (DEBUG) { |
| 287 | Slog.d(TAG, "onBootCompleted"); |
| 288 | } |
Makoto Onuki | 1d146e4 | 2018-06-04 13:54:25 -0700 | [diff] [blame] | 289 | // Just booted. We don't want LOW_POWER_MODE to be persisted, so just always clear it. |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 290 | putGlobalSetting(Settings.Global.LOW_POWER_MODE, 0); |
Makoto Onuki | 1d146e4 | 2018-06-04 13:54:25 -0700 | [diff] [blame] | 291 | |
| 292 | // This is called with the power manager lock held. Don't do anything that may call to |
| 293 | // upper services. (e.g. don't call into AM directly) |
| 294 | // So use a BG thread. |
Makoto Onuki | 6e5eb1d | 2018-03-30 16:15:35 -0700 | [diff] [blame] | 295 | runOnBgThread(() -> { |
Makoto Onuki | 1d146e4 | 2018-06-04 13:54:25 -0700 | [diff] [blame] | 296 | |
Makoto Onuki | bd7a625 | 2018-05-10 13:41:39 -0700 | [diff] [blame] | 297 | final ContentResolver cr = mContext.getContentResolver(); |
| 298 | cr.registerContentObserver(Settings.Global.getUriFor( |
| 299 | Settings.Global.LOW_POWER_MODE), |
| 300 | false, mSettingsObserver, UserHandle.USER_SYSTEM); |
| 301 | cr.registerContentObserver(Settings.Global.getUriFor( |
| 302 | Settings.Global.LOW_POWER_MODE_STICKY), |
| 303 | false, mSettingsObserver, UserHandle.USER_SYSTEM); |
| 304 | cr.registerContentObserver(Settings.Global.getUriFor( |
| 305 | Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL), |
| 306 | false, mSettingsObserver, UserHandle.USER_SYSTEM); |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 307 | cr.registerContentObserver(Settings.Global.getUriFor( |
Salvador Martinez | b85a9f8 | 2019-03-20 16:21:27 -0700 | [diff] [blame] | 308 | Settings.Global.AUTOMATIC_POWER_SAVE_MODE), |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 309 | false, mSettingsObserver, UserHandle.USER_SYSTEM); |
| 310 | cr.registerContentObserver(Settings.Global.getUriFor( |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 311 | Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED), |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 312 | false, mSettingsObserver, UserHandle.USER_SYSTEM); |
| 313 | cr.registerContentObserver(Settings.Global.getUriFor( |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 314 | Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD), |
| 315 | false, mSettingsObserver, UserHandle.USER_SYSTEM); |
| 316 | cr.registerContentObserver(Settings.Global.getUriFor( |
| 317 | Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED), |
| 318 | false, mSettingsObserver, UserHandle.USER_SYSTEM); |
| 319 | cr.registerContentObserver(Settings.Global.getUriFor( |
| 320 | Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL), |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 321 | false, mSettingsObserver, UserHandle.USER_SYSTEM); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 322 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 323 | |
Makoto Onuki | bd7a625 | 2018-05-10 13:41:39 -0700 | [diff] [blame] | 324 | synchronized (mLock) { |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 325 | final boolean lowPowerModeEnabledSticky = getGlobalSetting( |
| 326 | Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0; |
| 327 | |
| 328 | if (lowPowerModeEnabledSticky) { |
| 329 | mState = STATE_PENDING_STICKY_ON; |
| 330 | } |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 331 | |
Makoto Onuki | 6e5eb1d | 2018-03-30 16:15:35 -0700 | [diff] [blame] | 332 | mBootCompleted = true; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 333 | |
Makoto Onuki | 6e5eb1d | 2018-03-30 16:15:35 -0700 | [diff] [blame] | 334 | refreshSettingsLocked(); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 335 | |
Makoto Onuki | 6e5eb1d | 2018-03-30 16:15:35 -0700 | [diff] [blame] | 336 | doAutoBatterySaverLocked(); |
| 337 | } |
| 338 | }); |
| 339 | } |
| 340 | |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 341 | /** |
| 342 | * Run a {@link Runnable} on a background handler. |
| 343 | */ |
Makoto Onuki | 6e5eb1d | 2018-03-30 16:15:35 -0700 | [diff] [blame] | 344 | @VisibleForTesting |
| 345 | void runOnBgThread(Runnable r) { |
| 346 | BackgroundThread.getHandler().post(r); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 347 | } |
| 348 | |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 349 | /** |
Kweku Adams | 7fb72a4 | 2019-01-08 16:08:49 -0800 | [diff] [blame] | 350 | * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable} is |
| 351 | * already registered, it'll be first removed before being re-posted. |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 352 | */ |
| 353 | @VisibleForTesting |
| 354 | void runOnBgThreadLazy(Runnable r, int delayMillis) { |
| 355 | final Handler h = BackgroundThread.getHandler(); |
| 356 | h.removeCallbacks(r); |
| 357 | h.postDelayed(r, delayMillis); |
| 358 | } |
| 359 | |
Andreas Gampe | edef60e | 2018-07-20 12:55:37 -0700 | [diff] [blame] | 360 | @GuardedBy("mLock") |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 361 | private void refreshSettingsLocked() { |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 362 | final boolean lowPowerModeEnabled = getGlobalSetting( |
| 363 | Settings.Global.LOW_POWER_MODE, 0) != 0; |
| 364 | final boolean lowPowerModeEnabledSticky = getGlobalSetting( |
| 365 | Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0; |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 366 | final boolean dynamicPowerSavingsBatterySaver = getGlobalSetting( |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 367 | Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0) != 0; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 368 | final int lowPowerModeTriggerLevel = getGlobalSetting( |
| 369 | Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0); |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 370 | final int automaticBatterySaverMode = getGlobalSetting( |
Salvador Martinez | b85a9f8 | 2019-03-20 16:21:27 -0700 | [diff] [blame] | 371 | Settings.Global.AUTOMATIC_POWER_SAVE_MODE, |
| 372 | PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE); |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 373 | final int dynamicPowerSavingsDisableThreshold = getGlobalSetting( |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 374 | Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 375 | mDynamicPowerSavingsDefaultDisableThreshold); |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 376 | final boolean isStickyAutoDisableEnabled = getGlobalSetting( |
Kweku Adams | 6065cbb | 2019-02-25 18:33:22 -0800 | [diff] [blame] | 377 | Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1) != 0; |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 378 | final int stickyAutoDisableThreshold = getGlobalSetting( |
| 379 | Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 380 | |
| 381 | setSettingsLocked(lowPowerModeEnabled, lowPowerModeEnabledSticky, |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 382 | lowPowerModeTriggerLevel, |
| 383 | isStickyAutoDisableEnabled, stickyAutoDisableThreshold, |
| 384 | automaticBatterySaverMode, |
| 385 | dynamicPowerSavingsBatterySaver, dynamicPowerSavingsDisableThreshold); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 386 | } |
| 387 | |
| 388 | /** |
| 389 | * {@link com.android.server.power.PowerManagerService} calls it when relevant global settings |
| 390 | * have changed. |
| 391 | * |
| 392 | * Note this will be called before {@link #onBootCompleted} too. |
| 393 | */ |
Andreas Gampe | edef60e | 2018-07-20 12:55:37 -0700 | [diff] [blame] | 394 | @GuardedBy("mLock") |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 395 | @VisibleForTesting |
| 396 | void setSettingsLocked(boolean batterySaverEnabled, boolean batterySaverEnabledSticky, |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 397 | int batterySaverTriggerThreshold, |
| 398 | boolean isStickyAutoDisableEnabled, int stickyAutoDisableThreshold, |
| 399 | int automaticBatterySaver, |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 400 | boolean dynamicPowerSavingsBatterySaver, int dynamicPowerSavingsDisableThreshold) { |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 401 | if (DEBUG) { |
| 402 | Slog.d(TAG, "setSettings: enabled=" + batterySaverEnabled |
| 403 | + " sticky=" + batterySaverEnabledSticky |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 404 | + " threshold=" + batterySaverTriggerThreshold |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 405 | + " stickyAutoDisableEnabled=" + isStickyAutoDisableEnabled |
| 406 | + " stickyAutoDisableThreshold=" + stickyAutoDisableThreshold |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 407 | + " automaticBatterySaver=" + automaticBatterySaver |
| 408 | + " dynamicPowerSavingsBatterySaver=" + dynamicPowerSavingsBatterySaver |
| 409 | + " dynamicPowerSavingsDisableThreshold=" |
| 410 | + dynamicPowerSavingsDisableThreshold); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 411 | } |
| 412 | |
| 413 | mSettingsLoaded = true; |
| 414 | |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 415 | // Set sensible limits. |
| 416 | stickyAutoDisableThreshold = Math.max(stickyAutoDisableThreshold, |
| 417 | batterySaverTriggerThreshold); |
| 418 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 419 | final boolean enabledChanged = mSettingBatterySaverEnabled != batterySaverEnabled; |
| 420 | final boolean stickyChanged = |
| 421 | mSettingBatterySaverEnabledSticky != batterySaverEnabledSticky; |
| 422 | final boolean thresholdChanged |
| 423 | = mSettingBatterySaverTriggerThreshold != batterySaverTriggerThreshold; |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 424 | final boolean stickyAutoDisableEnabledChanged = |
| 425 | mSettingBatterySaverStickyAutoDisableEnabled != isStickyAutoDisableEnabled; |
| 426 | final boolean stickyAutoDisableThresholdChanged = |
| 427 | mSettingBatterySaverStickyAutoDisableThreshold != stickyAutoDisableThreshold; |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 428 | final boolean automaticModeChanged = mSettingAutomaticBatterySaver != automaticBatterySaver; |
| 429 | final boolean dynamicPowerSavingsThresholdChanged = |
| 430 | mDynamicPowerSavingsDisableThreshold != dynamicPowerSavingsDisableThreshold; |
| 431 | final boolean dynamicPowerSavingsBatterySaverChanged = |
| 432 | mDynamicPowerSavingsBatterySaver != dynamicPowerSavingsBatterySaver; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 433 | |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 434 | if (!(enabledChanged || stickyChanged || thresholdChanged || automaticModeChanged |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 435 | || stickyAutoDisableEnabledChanged || stickyAutoDisableThresholdChanged |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 436 | || dynamicPowerSavingsThresholdChanged || dynamicPowerSavingsBatterySaverChanged)) { |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 437 | return; |
| 438 | } |
| 439 | |
| 440 | mSettingBatterySaverEnabled = batterySaverEnabled; |
| 441 | mSettingBatterySaverEnabledSticky = batterySaverEnabledSticky; |
| 442 | mSettingBatterySaverTriggerThreshold = batterySaverTriggerThreshold; |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 443 | mSettingBatterySaverStickyAutoDisableEnabled = isStickyAutoDisableEnabled; |
| 444 | mSettingBatterySaverStickyAutoDisableThreshold = stickyAutoDisableThreshold; |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 445 | mSettingAutomaticBatterySaver = automaticBatterySaver; |
| 446 | mDynamicPowerSavingsDisableThreshold = dynamicPowerSavingsDisableThreshold; |
| 447 | mDynamicPowerSavingsBatterySaver = dynamicPowerSavingsBatterySaver; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 448 | |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 449 | if (thresholdChanged) { |
| 450 | // To avoid spamming the event log, we throttle logging here. |
| 451 | runOnBgThreadLazy(mThresholdChangeLogger, 2000); |
| 452 | } |
| 453 | |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 454 | if (!mSettingBatterySaverStickyAutoDisableEnabled) { |
| 455 | hideStickyDisabledNotification(); |
| 456 | } |
| 457 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 458 | if (enabledChanged) { |
| 459 | final String reason = batterySaverEnabled |
| 460 | ? "Global.low_power changed to 1" : "Global.low_power changed to 0"; |
| 461 | enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true, |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 462 | BatterySaverController.REASON_SETTING_CHANGED, reason); |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 463 | } else { |
| 464 | doAutoBatterySaverLocked(); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 465 | } |
| 466 | } |
| 467 | |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 468 | private final Runnable mThresholdChangeLogger = () -> { |
| 469 | EventLogTags.writeBatterySaverSetting(mSettingBatterySaverTriggerThreshold); |
| 470 | }; |
| 471 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 472 | /** |
| 473 | * {@link com.android.server.power.PowerManagerService} calls it when battery state changes. |
| 474 | * |
| 475 | * Note this may be called before {@link #onBootCompleted} too. |
| 476 | */ |
| 477 | public void setBatteryStatus(boolean newPowered, int newLevel, boolean newBatteryLevelLow) { |
| 478 | if (DEBUG) { |
| 479 | Slog.d(TAG, "setBatteryStatus: powered=" + newPowered + " level=" + newLevel |
| 480 | + " low=" + newBatteryLevelLow); |
| 481 | } |
| 482 | synchronized (mLock) { |
| 483 | mBatteryStatusSet = true; |
| 484 | |
| 485 | final boolean poweredChanged = mIsPowered != newPowered; |
| 486 | final boolean levelChanged = mBatteryLevel != newLevel; |
| 487 | final boolean lowChanged = mIsBatteryLevelLow != newBatteryLevelLow; |
| 488 | |
| 489 | if (!(poweredChanged || levelChanged || lowChanged)) { |
| 490 | return; |
| 491 | } |
| 492 | |
| 493 | mIsPowered = newPowered; |
| 494 | mBatteryLevel = newLevel; |
| 495 | mIsBatteryLevelLow = newBatteryLevelLow; |
| 496 | |
| 497 | doAutoBatterySaverLocked(); |
| 498 | } |
| 499 | } |
| 500 | |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 501 | /** |
| 502 | * Enable or disable the current adaptive battery saver policy. This may not change what's in |
| 503 | * effect if full battery saver is also enabled. |
| 504 | */ |
| 505 | public boolean setAdaptiveBatterySaverEnabled(boolean enabled) { |
| 506 | if (DEBUG) { |
| 507 | Slog.d(TAG, "setAdaptiveBatterySaverEnabled: enabled=" + enabled); |
| 508 | } |
| 509 | synchronized (mLock) { |
| 510 | mLastAdaptiveBatterySaverChangedExternallyElapsed = SystemClock.elapsedRealtime(); |
| 511 | return mBatterySaverController.setAdaptivePolicyEnabledLocked( |
| 512 | enabled, BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED); |
| 513 | } |
| 514 | } |
| 515 | |
| 516 | /** |
| 517 | * Change the adaptive battery saver policy. |
| 518 | */ |
| 519 | public boolean setAdaptiveBatterySaverPolicy(BatterySaverPolicyConfig config) { |
| 520 | if (DEBUG) { |
| 521 | Slog.d(TAG, "setAdaptiveBatterySaverPolicy: config=" + config); |
| 522 | } |
| 523 | |
| 524 | synchronized (mLock) { |
| 525 | mLastAdaptiveBatterySaverChangedExternallyElapsed = SystemClock.elapsedRealtime(); |
| 526 | return mBatterySaverController.setAdaptivePolicyLocked(config, |
| 527 | BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED); |
| 528 | } |
| 529 | } |
| 530 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 531 | /** |
| 532 | * Decide whether to auto-start / stop battery saver. |
| 533 | */ |
Andreas Gampe | edef60e | 2018-07-20 12:55:37 -0700 | [diff] [blame] | 534 | @GuardedBy("mLock") |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 535 | private void doAutoBatterySaverLocked() { |
| 536 | if (DEBUG) { |
| 537 | Slog.d(TAG, "doAutoBatterySaverLocked: mBootCompleted=" + mBootCompleted |
| 538 | + " mSettingsLoaded=" + mSettingsLoaded |
| 539 | + " mBatteryStatusSet=" + mBatteryStatusSet |
Kweku Adams | 5bcc89f | 2019-05-15 11:23:19 -0700 | [diff] [blame] | 540 | + " mState=" + mState |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 541 | + " mIsBatteryLevelLow=" + mIsBatteryLevelLow |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 542 | + " mIsPowered=" + mIsPowered |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 543 | + " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 544 | + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky |
| 545 | + " mSettingBatterySaverStickyAutoDisableEnabled=" |
| 546 | + mSettingBatterySaverStickyAutoDisableEnabled); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 547 | } |
| 548 | if (!(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) { |
| 549 | return; // Not fully initialized yet. |
| 550 | } |
Salvador Martinez | 812ea75 | 2018-10-19 13:03:20 -0700 | [diff] [blame] | 551 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 552 | updateStateLocked(false, false); |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 553 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 554 | // Adaptive control. |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 555 | if (SystemClock.elapsedRealtime() - mLastAdaptiveBatterySaverChangedExternallyElapsed |
| 556 | > ADAPTIVE_CHANGE_TIMEOUT_MS) { |
| 557 | mBatterySaverController.setAdaptivePolicyEnabledLocked( |
| 558 | false, BatterySaverController.REASON_TIMEOUT); |
| 559 | mBatterySaverController.resetAdaptivePolicyLocked( |
| 560 | BatterySaverController.REASON_TIMEOUT); |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 561 | } else if (mIsPowered && mBatteryLevel >= ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL) { |
| 562 | mBatterySaverController.setAdaptivePolicyEnabledLocked(false, |
| 563 | BatterySaverController.REASON_PLUGGED_IN); |
| 564 | } |
| 565 | } |
| 566 | |
| 567 | /** |
| 568 | * Update the state machine based on the current settings and battery/charge status. |
| 569 | * |
| 570 | * @param manual Whether the change was made by the user. |
| 571 | * @param enable Whether the user wants to turn battery saver on or off. Is only used if {@param |
| 572 | * manual} is true. |
| 573 | */ |
| 574 | @GuardedBy("mLock") |
| 575 | private void updateStateLocked(boolean manual, boolean enable) { |
| 576 | if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) { |
| 577 | return; // Not fully initialized yet. |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 578 | } |
| 579 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 580 | switch (mState) { |
| 581 | case STATE_OFF: { |
| 582 | if (!mIsPowered) { |
| 583 | if (manual) { |
| 584 | if (!enable) { |
| 585 | Slog.e(TAG, "Tried to disable BS when it's already OFF"); |
| 586 | return; |
| 587 | } |
| 588 | enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, |
| 589 | BatterySaverController.REASON_MANUAL_ON); |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 590 | hideStickyDisabledNotification(); |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 591 | mState = STATE_MANUAL_ON; |
| 592 | } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) { |
| 593 | enableBatterySaverLocked(/*enable*/ true, /*manual*/ false, |
| 594 | BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON); |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 595 | hideStickyDisabledNotification(); |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 596 | mState = STATE_AUTOMATIC_ON; |
| 597 | } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) { |
| 598 | enableBatterySaverLocked(/*enable*/ true, /*manual*/ false, |
| 599 | BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON); |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 600 | hideStickyDisabledNotification(); |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 601 | mState = STATE_AUTOMATIC_ON; |
| 602 | } |
| 603 | } |
| 604 | break; |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 605 | } |
| 606 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 607 | case STATE_MANUAL_ON: { |
| 608 | if (manual) { |
| 609 | if (enable) { |
| 610 | Slog.e(TAG, "Tried to enable BS when it's already MANUAL_ON"); |
| 611 | return; |
| 612 | } |
| 613 | enableBatterySaverLocked(/*enable*/ false, /*manual*/ true, |
| 614 | BatterySaverController.REASON_MANUAL_OFF); |
| 615 | mState = STATE_OFF; |
| 616 | } else if (mIsPowered) { |
| 617 | enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, |
| 618 | BatterySaverController.REASON_PLUGGED_IN); |
| 619 | if (mSettingBatterySaverEnabledSticky |
| 620 | && !mBatterySaverStickyBehaviourDisabled) { |
| 621 | mState = STATE_PENDING_STICKY_ON; |
| 622 | } else { |
| 623 | mState = STATE_OFF; |
| 624 | } |
| 625 | } |
| 626 | break; |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 627 | } |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 628 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 629 | case STATE_AUTOMATIC_ON: { |
| 630 | if (mIsPowered) { |
| 631 | enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, |
| 632 | BatterySaverController.REASON_PLUGGED_IN); |
| 633 | mState = STATE_OFF; |
| 634 | } else if (manual) { |
| 635 | if (enable) { |
| 636 | Slog.e(TAG, "Tried to enable BS when it's already AUTO_ON"); |
| 637 | return; |
| 638 | } |
| 639 | enableBatterySaverLocked(/*enable*/ false, /*manual*/ true, |
| 640 | BatterySaverController.REASON_MANUAL_OFF); |
| 641 | // When battery saver is disabled manually (while battery saver is enabled) |
| 642 | // when the battery level is low, we "snooze" BS -- i.e. disable auto battery |
| 643 | // saver. |
| 644 | // We resume auto-BS once the battery level is not low, or the device is |
| 645 | // plugged in. |
| 646 | mState = STATE_OFF_AUTOMATIC_SNOOZED; |
| 647 | } else if (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) { |
| 648 | enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, |
| 649 | BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF); |
| 650 | mState = STATE_OFF; |
| 651 | } else if (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) { |
| 652 | enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, |
| 653 | BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF); |
| 654 | mState = STATE_OFF; |
| 655 | } else if (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked()) { |
| 656 | enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, |
| 657 | BatterySaverController.REASON_SETTING_CHANGED); |
| 658 | mState = STATE_OFF; |
| 659 | } |
| 660 | break; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 661 | } |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 662 | |
| 663 | case STATE_OFF_AUTOMATIC_SNOOZED: { |
| 664 | if (manual) { |
| 665 | if (!enable) { |
| 666 | Slog.e(TAG, "Tried to disable BS when it's already AUTO_SNOOZED"); |
| 667 | return; |
| 668 | } |
| 669 | enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, |
| 670 | BatterySaverController.REASON_MANUAL_ON); |
| 671 | mState = STATE_MANUAL_ON; |
| 672 | } else if (mIsPowered // Plugging in resets snooze. |
| 673 | || (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) |
| 674 | || (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) |
| 675 | || (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked())) { |
| 676 | mState = STATE_OFF; |
| 677 | } |
| 678 | break; |
Salvador Martinez | 04b9833 | 2018-10-02 11:28:39 -0700 | [diff] [blame] | 679 | } |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 680 | |
| 681 | case STATE_PENDING_STICKY_ON: { |
| 682 | if (manual) { |
| 683 | // This shouldn't be possible. We'll only be in this state when the device is |
| 684 | // plugged in, so the user shouldn't be able to manually change state. |
| 685 | Slog.e(TAG, "Tried to manually change BS state from PENDING_STICKY_ON"); |
| 686 | return; |
| 687 | } |
| 688 | final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled |
| 689 | && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold; |
| 690 | final boolean isStickyDisabled = |
| 691 | mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky; |
| 692 | if (isStickyDisabled || shouldTurnOffSticky) { |
Kweku Adams | 5bcc89f | 2019-05-15 11:23:19 -0700 | [diff] [blame] | 693 | mState = STATE_OFF; |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 694 | setStickyActive(false); |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 695 | triggerStickyDisabledNotification(); |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 696 | } else if (!mIsPowered) { |
| 697 | // Re-enable BS. |
| 698 | enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, |
| 699 | BatterySaverController.REASON_STICKY_RESTORE); |
| 700 | mState = STATE_MANUAL_ON; |
| 701 | } |
| 702 | break; |
| 703 | } |
| 704 | |
| 705 | default: |
| 706 | Slog.wtf(TAG, "Unknown state: " + mState); |
| 707 | break; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 708 | } |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 709 | } |
| 710 | |
| 711 | @VisibleForTesting |
| 712 | int getState() { |
| 713 | synchronized (mLock) { |
| 714 | return mState; |
| 715 | } |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 716 | } |
| 717 | |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 718 | /** |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 719 | * {@link com.android.server.power.PowerManagerService} calls it when |
Salvador Martinez | c8c4c5d | 2019-03-11 11:11:37 -0700 | [diff] [blame] | 720 | * {@link android.os.PowerManager#setPowerSaveModeEnabled} is called. |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 721 | * |
| 722 | * Note this could? be called before {@link #onBootCompleted} too. |
| 723 | */ |
| 724 | public void setBatterySaverEnabledManually(boolean enabled) { |
| 725 | if (DEBUG) { |
| 726 | Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled); |
| 727 | } |
| 728 | synchronized (mLock) { |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 729 | updateStateLocked(true, enabled); |
| 730 | // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true and |
| 731 | // enabled is false |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 732 | } |
| 733 | } |
| 734 | |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 735 | @GuardedBy("mLock") |
| 736 | private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason) { |
| 737 | enableBatterySaverLocked(enable, manual, intReason, reasonToString(intReason)); |
| 738 | } |
| 739 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 740 | /** |
| 741 | * Actually enable / disable battery saver. Write the new state to the global settings |
| 742 | * and propagate it to {@link #mBatterySaverController}. |
| 743 | */ |
Andreas Gampe | edef60e | 2018-07-20 12:55:37 -0700 | [diff] [blame] | 744 | @GuardedBy("mLock") |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 745 | private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason, |
| 746 | String strReason) { |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 747 | if (DEBUG) { |
| 748 | Slog.d(TAG, "enableBatterySaver: enable=" + enable + " manual=" + manual |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 749 | + " reason=" + strReason + "(" + intReason + ")"); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 750 | } |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 751 | final boolean wasEnabled = mBatterySaverController.isFullEnabled(); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 752 | |
| 753 | if (wasEnabled == enable) { |
| 754 | if (DEBUG) { |
| 755 | Slog.d(TAG, "Already " + (enable ? "enabled" : "disabled")); |
| 756 | } |
| 757 | return; |
| 758 | } |
| 759 | if (enable && mIsPowered) { |
| 760 | if (DEBUG) Slog.d(TAG, "Can't enable: isPowered"); |
| 761 | return; |
| 762 | } |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 763 | mLastChangedIntReason = intReason; |
| 764 | mLastChangedStrReason = strReason; |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 765 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 766 | mSettingBatterySaverEnabled = enable; |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 767 | putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 768 | |
| 769 | if (manual) { |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 770 | setStickyActive(!mBatterySaverStickyBehaviourDisabled && enable); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 771 | } |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 772 | mBatterySaverController.enableBatterySaver(enable, intReason); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 773 | |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 774 | // Handle triggering the notification to show/hide when appropriate |
| 775 | if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON) { |
Kweku Adams | 79a0faf | 2019-12-10 16:32:55 -0800 | [diff] [blame] | 776 | triggerDynamicModeNotification(); |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 777 | } else if (!enable) { |
Kweku Adams | 79a0faf | 2019-12-10 16:32:55 -0800 | [diff] [blame] | 778 | hideDynamicModeNotification(); |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 779 | } |
| 780 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 781 | if (DEBUG) { |
| 782 | Slog.d(TAG, "Battery saver: Enabled=" + enable |
| 783 | + " manual=" + manual |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 784 | + " reason=" + strReason + "(" + intReason + ")"); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 785 | } |
| 786 | } |
| 787 | |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 788 | @VisibleForTesting |
| 789 | void triggerDynamicModeNotification() { |
Kweku Adams | 79a0faf | 2019-12-10 16:32:55 -0800 | [diff] [blame] | 790 | // The current lock is the PowerManager lock, which sits very low in the service lock |
| 791 | // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock. |
| 792 | runOnBgThread(() -> { |
| 793 | NotificationManager manager = mContext.getSystemService(NotificationManager.class); |
| 794 | ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID, |
| 795 | R.string.dynamic_mode_notification_channel_name); |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 796 | |
Kweku Adams | 79a0faf | 2019-12-10 16:32:55 -0800 | [diff] [blame] | 797 | manager.notifyAsUser(TAG, DYNAMIC_MODE_NOTIFICATION_ID, |
| 798 | buildNotification(DYNAMIC_MODE_NOTIF_CHANNEL_ID, |
| 799 | mContext.getResources().getString( |
| 800 | R.string.dynamic_mode_notification_title), |
| 801 | R.string.dynamic_mode_notification_summary, |
| 802 | Intent.ACTION_POWER_USAGE_SUMMARY), |
| 803 | UserHandle.ALL); |
| 804 | }); |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 805 | } |
| 806 | |
Kweku Adams | 5bcc89f | 2019-05-15 11:23:19 -0700 | [diff] [blame] | 807 | @VisibleForTesting |
| 808 | void triggerStickyDisabledNotification() { |
Kweku Adams | 79a0faf | 2019-12-10 16:32:55 -0800 | [diff] [blame] | 809 | // The current lock is the PowerManager lock, which sits very low in the service lock |
| 810 | // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock. |
| 811 | runOnBgThread(() -> { |
| 812 | NotificationManager manager = mContext.getSystemService(NotificationManager.class); |
| 813 | ensureNotificationChannelExists(manager, BATTERY_SAVER_NOTIF_CHANNEL_ID, |
| 814 | R.string.battery_saver_notification_channel_name); |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 815 | |
Kweku Adams | 79a0faf | 2019-12-10 16:32:55 -0800 | [diff] [blame] | 816 | final String percentage = NumberFormat.getPercentInstance() |
| 817 | .format((double) mBatteryLevel / 100.0); |
| 818 | manager.notifyAsUser(TAG, STICKY_AUTO_DISABLED_NOTIFICATION_ID, |
| 819 | buildNotification(BATTERY_SAVER_NOTIF_CHANNEL_ID, |
| 820 | mContext.getResources().getString( |
| 821 | R.string.battery_saver_charged_notification_title, percentage), |
| 822 | R.string.battery_saver_off_notification_summary, |
| 823 | Settings.ACTION_BATTERY_SAVER_SETTINGS), |
| 824 | UserHandle.ALL); |
| 825 | }); |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 826 | } |
| 827 | |
| 828 | private void ensureNotificationChannelExists(NotificationManager manager, |
| 829 | @NonNull String channelId, @StringRes int nameId) { |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 830 | NotificationChannel channel = new NotificationChannel( |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 831 | channelId, mContext.getText(nameId), NotificationManager.IMPORTANCE_DEFAULT); |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 832 | channel.setSound(null, null); |
Kweku Adams | 400e044 | 2019-05-23 18:41:23 -0700 | [diff] [blame] | 833 | channel.setBlockableSystem(true); |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 834 | manager.createNotificationChannel(channel); |
| 835 | } |
| 836 | |
Kweku Adams | 3c95ee1 | 2019-03-21 13:06:53 -0700 | [diff] [blame] | 837 | private Notification buildNotification(@NonNull String channelId, @NonNull String title, |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 838 | @StringRes int summaryId, @NonNull String intentAction) { |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 839 | Resources res = mContext.getResources(); |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 840 | Intent intent = new Intent(intentAction); |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 841 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); |
| 842 | PendingIntent batterySaverIntent = PendingIntent.getActivity( |
| 843 | mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT); |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 844 | final String summary = res.getString(summaryId); |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 845 | |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 846 | return new Notification.Builder(mContext, channelId) |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 847 | .setSmallIcon(R.drawable.ic_battery) |
Kweku Adams | 3c95ee1 | 2019-03-21 13:06:53 -0700 | [diff] [blame] | 848 | .setContentTitle(title) |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 849 | .setContentText(summary) |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 850 | .setContentIntent(batterySaverIntent) |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 851 | .setStyle(new Notification.BigTextStyle().bigText(summary)) |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 852 | .setOnlyAlertOnce(true) |
Kweku Adams | 3c95ee1 | 2019-03-21 13:06:53 -0700 | [diff] [blame] | 853 | .setAutoCancel(true) |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 854 | .build(); |
| 855 | } |
| 856 | |
| 857 | private void hideDynamicModeNotification() { |
Kweku Adams | 476ca77 | 2019-03-06 16:10:25 -0800 | [diff] [blame] | 858 | hideNotification(DYNAMIC_MODE_NOTIFICATION_ID); |
| 859 | } |
| 860 | |
| 861 | private void hideStickyDisabledNotification() { |
| 862 | hideNotification(STICKY_AUTO_DISABLED_NOTIFICATION_ID); |
| 863 | } |
| 864 | |
| 865 | private void hideNotification(int notificationId) { |
Kweku Adams | 79a0faf | 2019-12-10 16:32:55 -0800 | [diff] [blame] | 866 | // The current lock is the PowerManager lock, which sits very low in the service lock |
| 867 | // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock. |
| 868 | runOnBgThread(() -> { |
| 869 | NotificationManager manager = mContext.getSystemService(NotificationManager.class); |
| 870 | manager.cancelAsUser(TAG, notificationId, UserHandle.ALL); |
| 871 | }); |
Salvador Martinez | 3a3f822 | 2018-12-14 15:29:30 -0800 | [diff] [blame] | 872 | } |
| 873 | |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 874 | private void setStickyActive(boolean active) { |
| 875 | mSettingBatterySaverEnabledSticky = active; |
| 876 | putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY, |
| 877 | mSettingBatterySaverEnabledSticky ? 1 : 0); |
| 878 | } |
| 879 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 880 | @VisibleForTesting |
| 881 | protected void putGlobalSetting(String key, int value) { |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 882 | Settings.Global.putInt(mContext.getContentResolver(), key, value); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 883 | } |
| 884 | |
| 885 | @VisibleForTesting |
| 886 | protected int getGlobalSetting(String key, int defValue) { |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 887 | return Settings.Global.getInt(mContext.getContentResolver(), key, defValue); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 888 | } |
| 889 | |
| 890 | public void dump(PrintWriter pw) { |
| 891 | synchronized (mLock) { |
| 892 | pw.println(); |
| 893 | pw.println("Battery saver state machine:"); |
| 894 | |
| 895 | pw.print(" Enabled="); |
| 896 | pw.println(mBatterySaverController.isEnabled()); |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 897 | pw.print(" full="); |
| 898 | pw.println(mBatterySaverController.isFullEnabled()); |
| 899 | pw.print(" adaptive="); |
| 900 | pw.print(mBatterySaverController.isAdaptiveEnabled()); |
| 901 | if (mBatterySaverController.isAdaptiveEnabled()) { |
| 902 | pw.print(" (advertise="); |
| 903 | pw.print( |
| 904 | mBatterySaverController.getBatterySaverPolicy().shouldAdvertiseIsEnabled()); |
| 905 | pw.print(")"); |
| 906 | } |
| 907 | pw.println(); |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 908 | pw.print(" mState="); |
| 909 | pw.println(mState); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 910 | |
Makoto Onuki | 0f8617a | 2018-04-30 10:26:21 -0700 | [diff] [blame] | 911 | pw.print(" mLastChangedIntReason="); |
| 912 | pw.println(mLastChangedIntReason); |
| 913 | pw.print(" mLastChangedStrReason="); |
| 914 | pw.println(mLastChangedStrReason); |
| 915 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 916 | pw.print(" mBootCompleted="); |
| 917 | pw.println(mBootCompleted); |
| 918 | pw.print(" mSettingsLoaded="); |
| 919 | pw.println(mSettingsLoaded); |
| 920 | pw.print(" mBatteryStatusSet="); |
| 921 | pw.println(mBatteryStatusSet); |
| 922 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 923 | pw.print(" mIsPowered="); |
| 924 | pw.println(mIsPowered); |
| 925 | pw.print(" mBatteryLevel="); |
| 926 | pw.println(mBatteryLevel); |
| 927 | pw.print(" mIsBatteryLevelLow="); |
| 928 | pw.println(mIsBatteryLevelLow); |
| 929 | |
| 930 | pw.print(" mSettingBatterySaverEnabled="); |
| 931 | pw.println(mSettingBatterySaverEnabled); |
| 932 | pw.print(" mSettingBatterySaverEnabledSticky="); |
| 933 | pw.println(mSettingBatterySaverEnabledSticky); |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 934 | pw.print(" mSettingBatterySaverStickyAutoDisableEnabled="); |
| 935 | pw.println(mSettingBatterySaverStickyAutoDisableEnabled); |
| 936 | pw.print(" mSettingBatterySaverStickyAutoDisableThreshold="); |
| 937 | pw.println(mSettingBatterySaverStickyAutoDisableThreshold); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 938 | pw.print(" mSettingBatterySaverTriggerThreshold="); |
| 939 | pw.println(mSettingBatterySaverTriggerThreshold); |
Michael Kwan | e322502 | 2018-06-26 18:03:38 -0700 | [diff] [blame] | 940 | pw.print(" mBatterySaverStickyBehaviourDisabled="); |
| 941 | pw.println(mBatterySaverStickyBehaviourDisabled); |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 942 | |
| 943 | pw.print(" mLastAdaptiveBatterySaverChangedExternallyElapsed="); |
| 944 | pw.println(mLastAdaptiveBatterySaverChangedExternallyElapsed); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 945 | } |
| 946 | } |
| 947 | |
| 948 | public void dumpProto(ProtoOutputStream proto, long tag) { |
| 949 | synchronized (mLock) { |
| 950 | final long token = proto.start(tag); |
| 951 | |
| 952 | proto.write(BatterySaverStateMachineProto.ENABLED, |
| 953 | mBatterySaverController.isEnabled()); |
Kweku Adams | f57f99e | 2019-03-07 15:38:21 -0800 | [diff] [blame] | 954 | proto.write(BatterySaverStateMachineProto.STATE, mState); |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 955 | proto.write(BatterySaverStateMachineProto.IS_FULL_ENABLED, |
| 956 | mBatterySaverController.isFullEnabled()); |
| 957 | proto.write(BatterySaverStateMachineProto.IS_ADAPTIVE_ENABLED, |
| 958 | mBatterySaverController.isAdaptiveEnabled()); |
| 959 | proto.write(BatterySaverStateMachineProto.SHOULD_ADVERTISE_IS_ENABLED, |
| 960 | mBatterySaverController.getBatterySaverPolicy().shouldAdvertiseIsEnabled()); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 961 | |
| 962 | proto.write(BatterySaverStateMachineProto.BOOT_COMPLETED, mBootCompleted); |
| 963 | proto.write(BatterySaverStateMachineProto.SETTINGS_LOADED, mSettingsLoaded); |
| 964 | proto.write(BatterySaverStateMachineProto.BATTERY_STATUS_SET, mBatteryStatusSet); |
| 965 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 966 | |
| 967 | proto.write(BatterySaverStateMachineProto.IS_POWERED, mIsPowered); |
| 968 | proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel); |
| 969 | proto.write(BatterySaverStateMachineProto.IS_BATTERY_LEVEL_LOW, mIsBatteryLevelLow); |
| 970 | |
| 971 | proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED, |
| 972 | mSettingBatterySaverEnabled); |
| 973 | proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED_STICKY, |
| 974 | mSettingBatterySaverEnabledSticky); |
| 975 | proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_TRIGGER_THRESHOLD, |
| 976 | mSettingBatterySaverTriggerThreshold); |
Kweku Adams | b243a99 | 2019-01-18 11:18:16 -0800 | [diff] [blame] | 977 | proto.write( |
| 978 | BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_STICKY_AUTO_DISABLE_ENABLED, |
| 979 | mSettingBatterySaverStickyAutoDisableEnabled); |
| 980 | proto.write( |
| 981 | BatterySaverStateMachineProto |
| 982 | .SETTING_BATTERY_SAVER_STICKY_AUTO_DISABLE_THRESHOLD, |
| 983 | mSettingBatterySaverStickyAutoDisableThreshold); |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 984 | |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 985 | proto.write( |
| 986 | BatterySaverStateMachineProto |
| 987 | .LAST_ADAPTIVE_BATTERY_SAVER_CHANGED_EXTERNALLY_ELAPSED, |
| 988 | mLastAdaptiveBatterySaverChangedExternallyElapsed); |
| 989 | |
Makoto Onuki | a3cd7b9 | 2018-03-19 14:47:05 -0700 | [diff] [blame] | 990 | proto.end(token); |
| 991 | } |
| 992 | } |
| 993 | } |