blob: 3401441439bf8a6e38b193083cacaeafb6053bc0 [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
19import java.io.FileDescriptor;
20import java.io.PrintWriter;
21import java.util.Arrays;
22
23import android.app.AlertDialog;
24import android.content.BroadcastReceiver;
25import android.content.ContentResolver;
26import android.content.Context;
27import android.content.DialogInterface;
28import android.content.Intent;
29import android.content.IntentFilter;
30import android.net.Uri;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070031import android.os.BatteryManager;
Joe Onorato10523b4d2010-10-25 10:42:46 -070032import android.os.Handler;
33import android.media.AudioManager;
34import android.media.Ringtone;
35import android.media.RingtoneManager;
36import android.provider.Settings;
37import android.util.Slog;
38import android.view.View;
39import android.view.WindowManager;
40import android.widget.TextView;
41
42import com.android.systemui.R;
43import com.android.systemui.SystemUI;
44
45public class PowerUI extends SystemUI {
46 static final String TAG = "PowerUI";
47
48 Handler mHandler = new Handler();
49
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070050 int mBatteryLevel = 100;
51 int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
52 int mPlugType = 0;
53 int mInvalidCharger = 0;
54
55 int mLowBatteryAlertCloseLevel;
56 int[] mLowBatteryReminderLevels = new int[2];
57
58 AlertDialog mInvalidChargerDialog;
Joe Onorato10523b4d2010-10-25 10:42:46 -070059 AlertDialog mLowBatteryDialog;
Joe Onorato10523b4d2010-10-25 10:42:46 -070060 TextView mBatteryLevelTextView;
61
62 public void start() {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070063
64 mLowBatteryAlertCloseLevel = mContext.getResources().getInteger(
65 com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
66 mLowBatteryReminderLevels[0] = mContext.getResources().getInteger(
67 com.android.internal.R.integer.config_lowBatteryWarningLevel);
68 mLowBatteryReminderLevels[1] = mContext.getResources().getInteger(
69 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
70
Joe Onorato10523b4d2010-10-25 10:42:46 -070071 // Register for Intent broadcasts for...
72 IntentFilter filter = new IntentFilter();
73 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
Joe Onorato10523b4d2010-10-25 10:42:46 -070074 filter.addAction(Intent.ACTION_POWER_CONNECTED);
75 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
76 }
77
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070078 /**
79 * Buckets the battery level.
80 *
81 * The code in this function is a little weird because I couldn't comprehend
82 * the bucket going up when the battery level was going down. --joeo
83 *
84 * 1 means that the battery is "ok"
85 * 0 means that the battery is between "ok" and what we should warn about.
86 * less than 0 means that the battery is low
87 */
88 private int findBatteryLevelBucket(int level) {
89 if (level >= mLowBatteryAlertCloseLevel) {
90 return 1;
91 }
92 if (level >= mLowBatteryReminderLevels[0]) {
93 return 0;
94 }
95 final int N = mLowBatteryReminderLevels.length;
96 for (int i=N-1; i>=0; i--) {
97 if (level <= mLowBatteryReminderLevels[i]) {
98 return -1-i;
99 }
100 }
101 throw new RuntimeException("not possible!");
102 }
103
Joe Onorato10523b4d2010-10-25 10:42:46 -0700104 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
105 @Override
106 public void onReceive(Context context, Intent intent) {
107 String action = intent.getAction();
108 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700109 final int oldBatteryLevel = mBatteryLevel;
110 mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100);
111 final int oldBatteryStatus = mBatteryStatus;
112 mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
113 BatteryManager.BATTERY_STATUS_UNKNOWN);
114 final int oldPlugType = mPlugType;
115 mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1);
116 final int oldInvalidCharger = mInvalidCharger;
117 mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0);
118
119 final boolean plugged = mPlugType != 0;
120 final boolean oldPlugged = oldPlugType != 0;
121
122 int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
123 int bucket = findBatteryLevelBucket(mBatteryLevel);
124
125 if (false) {
126 Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel
127 + " .. " + mLowBatteryReminderLevels[0]
128 + " .. " + mLowBatteryReminderLevels[1]);
129 Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel);
130 Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus);
131 Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType);
132 Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);
133 Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket);
134 Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged);
135 }
136
137 if (oldInvalidCharger == 0 && mInvalidCharger != 0) {
138 Slog.d(TAG, "showing invalid charger warning");
139 showInvalidChargerDialog();
140 return;
141 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {
142 Slog.d(TAG, "closing invalid charger warning");
143 dismissInvalidChargerDialog();
144 } else if (mInvalidChargerDialog != null) {
145 // if invalid charger is showing, don't show low battery
146 return;
147 }
148
149 if (!plugged
150 && (bucket < oldBucket || oldPlugged)
151 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
152 && bucket < 0) {
153 Slog.d(TAG, "showing low battery warning: level=" + mBatteryLevel);
154 showLowBatteryWarning();
155 } else if (plugged || (bucket > oldBucket && bucket > 0)) {
156 Slog.d(TAG, "closing low battery warning: level=" + mBatteryLevel);
157 dismissLowBatteryWarning();
158 } else if (mBatteryLevelTextView != null) {
159 showLowBatteryWarning();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700160 }
161 } else {
162 Slog.w(TAG, "unknown intent: " + intent);
163 }
164 }
165 };
166
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700167 void dismissLowBatteryWarning() {
168 if (mLowBatteryDialog != null) {
169 mLowBatteryDialog.dismiss();
170 }
171 }
172
Joe Onorato10523b4d2010-10-25 10:42:46 -0700173 void showLowBatteryWarning() {
174 CharSequence levelText = mContext.getString(
175 R.string.battery_low_percent_format, mBatteryLevel);
176
177 if (mBatteryLevelTextView != null) {
178 mBatteryLevelTextView.setText(levelText);
179 } else {
180 View v = View.inflate(mContext, R.layout.battery_low, null);
181 mBatteryLevelTextView = (TextView)v.findViewById(R.id.level_percent);
182
183 mBatteryLevelTextView.setText(levelText);
184
185 AlertDialog.Builder b = new AlertDialog.Builder(mContext);
186 b.setCancelable(true);
187 b.setTitle(R.string.battery_low_title);
188 b.setView(v);
Adam Powell947f7822011-01-07 22:30:48 -0800189 b.setIconAttribute(android.R.attr.alertDialogIcon);
Joe Onorato10523b4d2010-10-25 10:42:46 -0700190 b.setPositiveButton(android.R.string.ok, null);
191
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700192 final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
193 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
194 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
195 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
196 | Intent.FLAG_ACTIVITY_NO_HISTORY);
197 if (intent.resolveActivity(mContext.getPackageManager()) != null) {
198 b.setNegativeButton(R.string.battery_low_why,
199 new DialogInterface.OnClickListener() {
200 public void onClick(DialogInterface dialog, int which) {
201 mContext.startActivity(intent);
202 if (mLowBatteryDialog != null) {
203 mLowBatteryDialog.dismiss();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700204 }
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700205 }
206 });
207 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700208
209 AlertDialog d = b.create();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700210 d.setOnDismissListener(new DialogInterface.OnDismissListener() {
211 public void onDismiss(DialogInterface dialog) {
212 mLowBatteryDialog = null;
213 mBatteryLevelTextView = null;
214 }
215 });
Joe Onorato10523b4d2010-10-25 10:42:46 -0700216 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
217 d.show();
218 mLowBatteryDialog = d;
219 }
220
221 final ContentResolver cr = mContext.getContentResolver();
222 if (Settings.System.getInt(cr, Settings.System.POWER_SOUNDS_ENABLED, 1) == 1) {
223 final String soundPath = Settings.System.getString(cr,
224 Settings.System.LOW_BATTERY_SOUND);
225 if (soundPath != null) {
226 final Uri soundUri = Uri.parse("file://" + soundPath);
227 if (soundUri != null) {
228 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
229 if (sfx != null) {
Daniel Sandlerd57c8d92011-02-03 01:06:31 -0500230 sfx.setStreamType(AudioManager.STREAM_NOTIFICATION);
Joe Onorato10523b4d2010-10-25 10:42:46 -0700231 sfx.play();
232 }
233 }
234 }
235 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700236 }
237
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700238 void dismissInvalidChargerDialog() {
239 if (mInvalidChargerDialog != null) {
240 mInvalidChargerDialog.dismiss();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700241 }
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700242 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700243
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700244 void showInvalidChargerDialog() {
245 dismissLowBatteryWarning();
246
247 AlertDialog.Builder b = new AlertDialog.Builder(mContext);
248 b.setCancelable(true);
Joe Onoratoa9ad6b82010-10-30 12:13:13 -0700249 b.setMessage(R.string.invalid_charger);
Adam Powell947f7822011-01-07 22:30:48 -0800250 b.setIconAttribute(android.R.attr.alertDialogIcon);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700251 b.setPositiveButton(android.R.string.ok, null);
252
253 AlertDialog d = b.create();
254 d.setOnDismissListener(new DialogInterface.OnDismissListener() {
255 public void onDismiss(DialogInterface dialog) {
256 mInvalidChargerDialog = null;
257 mBatteryLevelTextView = null;
258 }
259 });
260
261 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
262 d.show();
263 mInvalidChargerDialog = d;
264 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700265
266 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700267 pw.print("mLowBatteryAlertCloseLevel=");
268 pw.println(mLowBatteryAlertCloseLevel);
269 pw.print("mLowBatteryReminderLevels=");
270 pw.println(Arrays.toString(mLowBatteryReminderLevels));
271 pw.print("mInvalidChargerDialog=");
272 pw.println(mInvalidChargerDialog == null ? "null" : mInvalidChargerDialog.toString());
273 pw.print("mLowBatteryDialog=");
274 pw.println(mLowBatteryDialog == null ? "null" : mLowBatteryDialog.toString());
275 pw.print("mBatteryLevel=");
276 pw.println(Integer.toString(mBatteryLevel));
277 pw.print("mBatteryStatus=");
278 pw.println(Integer.toString(mBatteryStatus));
279 pw.print("mPlugType=");
280 pw.println(Integer.toString(mPlugType));
281 pw.print("mInvalidCharger=");
282 pw.println(Integer.toString(mInvalidCharger));
283 pw.print("bucket: ");
284 pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
Joe Onorato10523b4d2010-10-25 10:42:46 -0700285 }
286}
287