blob: a549f5122db68e5ec6197c77f9baa1b4c412827d [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) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700142 dismissInvalidChargerDialog();
143 } else if (mInvalidChargerDialog != null) {
144 // if invalid charger is showing, don't show low battery
145 return;
146 }
147
148 if (!plugged
149 && (bucket < oldBucket || oldPlugged)
150 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
151 && bucket < 0) {
Joe Onoratof4a9e7d2011-04-06 13:58:11 -0700152 Slog.i(TAG, "showing low battery warning: level=" + mBatteryLevel);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700153 showLowBatteryWarning();
154 } else if (plugged || (bucket > oldBucket && bucket > 0)) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700155 dismissLowBatteryWarning();
156 } else if (mBatteryLevelTextView != null) {
157 showLowBatteryWarning();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700158 }
159 } else {
160 Slog.w(TAG, "unknown intent: " + intent);
161 }
162 }
163 };
164
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700165 void dismissLowBatteryWarning() {
166 if (mLowBatteryDialog != null) {
Joe Onoratof4a9e7d2011-04-06 13:58:11 -0700167 Slog.i(TAG, "closing low battery warning: level=" + mBatteryLevel);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700168 mLowBatteryDialog.dismiss();
169 }
170 }
171
Joe Onorato10523b4d2010-10-25 10:42:46 -0700172 void showLowBatteryWarning() {
173 CharSequence levelText = mContext.getString(
174 R.string.battery_low_percent_format, mBatteryLevel);
175
176 if (mBatteryLevelTextView != null) {
177 mBatteryLevelTextView.setText(levelText);
178 } else {
179 View v = View.inflate(mContext, R.layout.battery_low, null);
180 mBatteryLevelTextView = (TextView)v.findViewById(R.id.level_percent);
181
182 mBatteryLevelTextView.setText(levelText);
183
184 AlertDialog.Builder b = new AlertDialog.Builder(mContext);
185 b.setCancelable(true);
186 b.setTitle(R.string.battery_low_title);
187 b.setView(v);
Adam Powell947f7822011-01-07 22:30:48 -0800188 b.setIconAttribute(android.R.attr.alertDialogIcon);
Joe Onorato10523b4d2010-10-25 10:42:46 -0700189 b.setPositiveButton(android.R.string.ok, null);
190
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700191 final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
192 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
193 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
194 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
195 | Intent.FLAG_ACTIVITY_NO_HISTORY);
196 if (intent.resolveActivity(mContext.getPackageManager()) != null) {
197 b.setNegativeButton(R.string.battery_low_why,
198 new DialogInterface.OnClickListener() {
199 public void onClick(DialogInterface dialog, int which) {
200 mContext.startActivity(intent);
201 if (mLowBatteryDialog != null) {
202 mLowBatteryDialog.dismiss();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700203 }
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700204 }
205 });
206 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700207
208 AlertDialog d = b.create();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700209 d.setOnDismissListener(new DialogInterface.OnDismissListener() {
210 public void onDismiss(DialogInterface dialog) {
211 mLowBatteryDialog = null;
212 mBatteryLevelTextView = null;
213 }
214 });
Joe Onorato10523b4d2010-10-25 10:42:46 -0700215 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
216 d.show();
217 mLowBatteryDialog = d;
218 }
219
220 final ContentResolver cr = mContext.getContentResolver();
221 if (Settings.System.getInt(cr, Settings.System.POWER_SOUNDS_ENABLED, 1) == 1) {
222 final String soundPath = Settings.System.getString(cr,
223 Settings.System.LOW_BATTERY_SOUND);
224 if (soundPath != null) {
225 final Uri soundUri = Uri.parse("file://" + soundPath);
226 if (soundUri != null) {
227 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
228 if (sfx != null) {
Daniel Sandlerd57c8d92011-02-03 01:06:31 -0500229 sfx.setStreamType(AudioManager.STREAM_NOTIFICATION);
Joe Onorato10523b4d2010-10-25 10:42:46 -0700230 sfx.play();
231 }
232 }
233 }
234 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700235 }
236
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700237 void dismissInvalidChargerDialog() {
238 if (mInvalidChargerDialog != null) {
Joe Onoratof4a9e7d2011-04-06 13:58:11 -0700239 Slog.d(TAG, "closing invalid charger warning");
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700240 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