blob: 522d5338461f3fa2aa1ea67ea16b9c5d62035f16 [file] [log] [blame]
Joe Onorato10523b4d2010-10-25 10:42:46 -07001/*
2 * Copyright (C) 2008 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
17package com.android.systemui.power;
18
Joe Onorato10523b4d2010-10-25 10:42:46 -070019import android.content.BroadcastReceiver;
Dianne Hackborn14272302014-06-10 23:13:02 -070020import android.content.ContentResolver;
Joe Onorato10523b4d2010-10-25 10:42:46 -070021import android.content.Context;
Joe Onorato10523b4d2010-10-25 10:42:46 -070022import android.content.Intent;
23import android.content.IntentFilter;
Dianne Hackborn14272302014-06-10 23:13:02 -070024import android.database.ContentObserver;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070025import android.os.BatteryManager;
Joe Onorato10523b4d2010-10-25 10:42:46 -070026import android.os.Handler;
Daniel Sandlerdea64622013-09-23 16:05:57 -040027import android.os.PowerManager;
28import android.os.SystemClock;
Dianne Hackborn14272302014-06-10 23:13:02 -070029import android.os.UserHandle;
Joe Onorato10523b4d2010-10-25 10:42:46 -070030import android.provider.Settings;
John Spurlock1bb480a2014-08-02 17:12:43 -040031import android.util.Log;
Daniel Sandlerdea64622013-09-23 16:05:57 -040032import android.util.Slog;
Joe Onorato10523b4d2010-10-25 10:42:46 -070033
Joe Onorato10523b4d2010-10-25 10:42:46 -070034import com.android.systemui.SystemUI;
Jorim Jaggi8de4311c2014-08-11 22:36:20 +020035import com.android.systemui.statusbar.phone.PhoneStatusBar;
Joe Onorato10523b4d2010-10-25 10:42:46 -070036
John Spurlockde84f0e2013-06-12 12:41:00 -040037import java.io.FileDescriptor;
38import java.io.PrintWriter;
39import java.util.Arrays;
40
Joe Onorato10523b4d2010-10-25 10:42:46 -070041public class PowerUI extends SystemUI {
42 static final String TAG = "PowerUI";
John Spurlock1bb480a2014-08-02 17:12:43 -040043 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Joe Onorato10523b4d2010-10-25 10:42:46 -070044
John Spurlocked452c52014-03-06 12:02:31 -050045 private final Handler mHandler = new Handler();
John Spurlock3332ba52014-03-10 17:44:07 -040046 private final Receiver mReceiver = new Receiver();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070047
John Spurlock3332ba52014-03-10 17:44:07 -040048 private PowerManager mPowerManager;
49 private WarningsUI mWarnings;
John Spurlocked452c52014-03-06 12:02:31 -050050 private int mBatteryLevel = 100;
51 private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
52 private int mPlugType = 0;
53 private int mInvalidCharger = 0;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070054
John Spurlocked452c52014-03-06 12:02:31 -050055 private int mLowBatteryAlertCloseLevel;
56 private final int[] mLowBatteryReminderLevels = new int[2];
Joe Onorato10523b4d2010-10-25 10:42:46 -070057
Daniel Sandlerdea64622013-09-23 16:05:57 -040058 private long mScreenOffTime = -1;
59
Joe Onorato10523b4d2010-10-25 10:42:46 -070060 public void start() {
John Spurlock3332ba52014-03-10 17:44:07 -040061 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
62 mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
Jorim Jaggi8de4311c2014-08-11 22:36:20 +020063 mWarnings = new PowerNotificationWarnings(mContext, getComponent(PhoneStatusBar.class));
Daniel Sandlerdea64622013-09-23 16:05:57 -040064
Dianne Hackborn14272302014-06-10 23:13:02 -070065 ContentObserver obs = new ContentObserver(mHandler) {
66 @Override
67 public void onChange(boolean selfChange) {
68 updateBatteryWarningLevels();
69 }
70 };
71 final ContentResolver resolver = mContext.getContentResolver();
72 resolver.registerContentObserver(Settings.Global.getUriFor(
73 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
74 false, obs, UserHandle.USER_ALL);
75 updateBatteryWarningLevels();
John Spurlock3332ba52014-03-10 17:44:07 -040076 mReceiver.init();
John Spurlock3332ba52014-03-10 17:44:07 -040077 }
Dianne Hackborn14272302014-06-10 23:13:02 -070078
Dianne Hackborn14272302014-06-10 23:13:02 -070079 void updateBatteryWarningLevels() {
80 int critLevel = mContext.getResources().getInteger(
81 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
82
83 final ContentResolver resolver = mContext.getContentResolver();
84 int defWarnLevel = mContext.getResources().getInteger(
85 com.android.internal.R.integer.config_lowBatteryWarningLevel);
86 int warnLevel = Settings.Global.getInt(resolver,
87 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
88 if (warnLevel == 0) {
89 warnLevel = defWarnLevel;
90 }
91 if (warnLevel < critLevel) {
92 warnLevel = critLevel;
93 }
94
95 mLowBatteryReminderLevels[0] = warnLevel;
96 mLowBatteryReminderLevels[1] = critLevel;
97 mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0]
98 + mContext.getResources().getInteger(
99 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
100 }
101
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700102 /**
103 * Buckets the battery level.
104 *
105 * The code in this function is a little weird because I couldn't comprehend
106 * the bucket going up when the battery level was going down. --joeo
107 *
108 * 1 means that the battery is "ok"
109 * 0 means that the battery is between "ok" and what we should warn about.
110 * less than 0 means that the battery is low
111 */
112 private int findBatteryLevelBucket(int level) {
113 if (level >= mLowBatteryAlertCloseLevel) {
114 return 1;
115 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700116 if (level > mLowBatteryReminderLevels[0]) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700117 return 0;
118 }
119 final int N = mLowBatteryReminderLevels.length;
120 for (int i=N-1; i>=0; i--) {
121 if (level <= mLowBatteryReminderLevels[i]) {
122 return -1-i;
123 }
124 }
125 throw new RuntimeException("not possible!");
126 }
127
John Spurlock3332ba52014-03-10 17:44:07 -0400128 private final class Receiver extends BroadcastReceiver {
129
130 public void init() {
131 // Register for Intent broadcasts for...
132 IntentFilter filter = new IntentFilter();
133 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
134 filter.addAction(Intent.ACTION_SCREEN_OFF);
135 filter.addAction(Intent.ACTION_SCREEN_ON);
John Spurlockecbc5e82014-10-22 09:05:51 -0400136 filter.addAction(Intent.ACTION_USER_SWITCHED);
John Spurlock1bb480a2014-08-02 17:12:43 -0400137 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
John Spurlock3332ba52014-03-10 17:44:07 -0400138 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
139 mContext.registerReceiver(this, filter, null, mHandler);
John Spurlock3332ba52014-03-10 17:44:07 -0400140 }
141
Joe Onorato10523b4d2010-10-25 10:42:46 -0700142 @Override
143 public void onReceive(Context context, Intent intent) {
144 String action = intent.getAction();
145 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700146 final int oldBatteryLevel = mBatteryLevel;
147 mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100);
148 final int oldBatteryStatus = mBatteryStatus;
149 mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
150 BatteryManager.BATTERY_STATUS_UNKNOWN);
151 final int oldPlugType = mPlugType;
152 mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1);
153 final int oldInvalidCharger = mInvalidCharger;
154 mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0);
155
156 final boolean plugged = mPlugType != 0;
157 final boolean oldPlugged = oldPlugType != 0;
158
159 int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
160 int bucket = findBatteryLevelBucket(mBatteryLevel);
161
Daniel Sandler71986622011-07-26 13:06:49 -0400162 if (DEBUG) {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400163 Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700164 + " .. " + mLowBatteryReminderLevels[0]
165 + " .. " + mLowBatteryReminderLevels[1]);
Daniel Sandlerdea64622013-09-23 16:05:57 -0400166 Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel);
167 Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus);
168 Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType);
169 Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);
170 Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket);
171 Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700172 }
173
John Spurlocked452c52014-03-06 12:02:31 -0500174 mWarnings.update(mBatteryLevel, bucket, mScreenOffTime);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700175 if (oldInvalidCharger == 0 && mInvalidCharger != 0) {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400176 Slog.d(TAG, "showing invalid charger warning");
John Spurlocked452c52014-03-06 12:02:31 -0500177 mWarnings.showInvalidChargerWarning();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700178 return;
179 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {
John Spurlocked452c52014-03-06 12:02:31 -0500180 mWarnings.dismissInvalidChargerWarning();
181 } else if (mWarnings.isInvalidChargerWarningShowing()) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700182 // if invalid charger is showing, don't show low battery
183 return;
184 }
185
186 if (!plugged
187 && (bucket < oldBucket || oldPlugged)
188 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
189 && bucket < 0) {
Daniel Sandler71986622011-07-26 13:06:49 -0400190 // only play SFX when the dialog comes up or the bucket changes
John Spurlocked452c52014-03-06 12:02:31 -0500191 final boolean playSound = bucket != oldBucket || oldPlugged;
192 mWarnings.showLowBatteryWarning(playSound);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700193 } else if (plugged || (bucket > oldBucket && bucket > 0)) {
John Spurlocked452c52014-03-06 12:02:31 -0500194 mWarnings.dismissLowBatteryWarning();
195 } else {
196 mWarnings.updateLowBatteryWarning();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700197 }
Daniel Sandlerdea64622013-09-23 16:05:57 -0400198 } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
199 mScreenOffTime = SystemClock.elapsedRealtime();
200 } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
201 mScreenOffTime = -1;
John Spurlockecbc5e82014-10-22 09:05:51 -0400202 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
203 mWarnings.userSwitched();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700204 } else {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400205 Slog.w(TAG, "unknown intent: " + intent);
Joe Onorato10523b4d2010-10-25 10:42:46 -0700206 }
207 }
208 };
209
Joe Onorato10523b4d2010-10-25 10:42:46 -0700210 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700211 pw.print("mLowBatteryAlertCloseLevel=");
212 pw.println(mLowBatteryAlertCloseLevel);
213 pw.print("mLowBatteryReminderLevels=");
214 pw.println(Arrays.toString(mLowBatteryReminderLevels));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700215 pw.print("mBatteryLevel=");
216 pw.println(Integer.toString(mBatteryLevel));
217 pw.print("mBatteryStatus=");
218 pw.println(Integer.toString(mBatteryStatus));
219 pw.print("mPlugType=");
220 pw.println(Integer.toString(mPlugType));
221 pw.print("mInvalidCharger=");
222 pw.println(Integer.toString(mInvalidCharger));
Daniel Sandlerdea64622013-09-23 16:05:57 -0400223 pw.print("mScreenOffTime=");
224 pw.print(mScreenOffTime);
225 if (mScreenOffTime >= 0) {
226 pw.print(" (");
227 pw.print(SystemClock.elapsedRealtime() - mScreenOffTime);
228 pw.print(" ago)");
229 }
230 pw.println();
231 pw.print("soundTimeout=");
232 pw.println(Settings.Global.getInt(mContext.getContentResolver(),
233 Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700234 pw.print("bucket: ");
235 pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
John Spurlocked452c52014-03-06 12:02:31 -0500236 mWarnings.dump(pw);
237 }
238
239 public interface WarningsUI {
240 void update(int batteryLevel, int bucket, long screenOffTime);
241 void dismissLowBatteryWarning();
242 void showLowBatteryWarning(boolean playSound);
243 void dismissInvalidChargerWarning();
244 void showInvalidChargerWarning();
245 void updateLowBatteryWarning();
246 boolean isInvalidChargerWarningShowing();
247 void dump(PrintWriter pw);
John Spurlockecbc5e82014-10-22 09:05:51 -0400248 void userSwitched();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700249 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700250}
251