PowerUI.java revision 88400d3a31139c40c4014faf86c243647087ef6c
1/* 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; 31import android.os.BatteryManager; 32import 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 static final boolean DEBUG = false; 49 50 Handler mHandler = new Handler(); 51 52 int mBatteryLevel = 100; 53 int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; 54 int mPlugType = 0; 55 int mInvalidCharger = 0; 56 57 int mLowBatteryAlertCloseLevel; 58 int[] mLowBatteryReminderLevels = new int[2]; 59 60 AlertDialog mInvalidChargerDialog; 61 AlertDialog mLowBatteryDialog; 62 TextView mBatteryLevelTextView; 63 64 public void start() { 65 66 mLowBatteryAlertCloseLevel = mContext.getResources().getInteger( 67 com.android.internal.R.integer.config_lowBatteryCloseWarningLevel); 68 mLowBatteryReminderLevels[0] = mContext.getResources().getInteger( 69 com.android.internal.R.integer.config_lowBatteryWarningLevel); 70 mLowBatteryReminderLevels[1] = mContext.getResources().getInteger( 71 com.android.internal.R.integer.config_criticalBatteryWarningLevel); 72 73 // Register for Intent broadcasts for... 74 IntentFilter filter = new IntentFilter(); 75 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 76 filter.addAction(Intent.ACTION_POWER_CONNECTED); 77 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); 78 } 79 80 /** 81 * Buckets the battery level. 82 * 83 * The code in this function is a little weird because I couldn't comprehend 84 * the bucket going up when the battery level was going down. --joeo 85 * 86 * 1 means that the battery is "ok" 87 * 0 means that the battery is between "ok" and what we should warn about. 88 * less than 0 means that the battery is low 89 */ 90 private int findBatteryLevelBucket(int level) { 91 if (level >= mLowBatteryAlertCloseLevel) { 92 return 1; 93 } 94 if (level >= mLowBatteryReminderLevels[0]) { 95 return 0; 96 } 97 final int N = mLowBatteryReminderLevels.length; 98 for (int i=N-1; i>=0; i--) { 99 if (level <= mLowBatteryReminderLevels[i]) { 100 return -1-i; 101 } 102 } 103 throw new RuntimeException("not possible!"); 104 } 105 106 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 107 @Override 108 public void onReceive(Context context, Intent intent) { 109 String action = intent.getAction(); 110 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 111 final int oldBatteryLevel = mBatteryLevel; 112 mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100); 113 final int oldBatteryStatus = mBatteryStatus; 114 mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 115 BatteryManager.BATTERY_STATUS_UNKNOWN); 116 final int oldPlugType = mPlugType; 117 mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1); 118 final int oldInvalidCharger = mInvalidCharger; 119 mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0); 120 121 final boolean plugged = mPlugType != 0; 122 final boolean oldPlugged = oldPlugType != 0; 123 124 int oldBucket = findBatteryLevelBucket(oldBatteryLevel); 125 int bucket = findBatteryLevelBucket(mBatteryLevel); 126 127 if (DEBUG) { 128 Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel 129 + " .. " + mLowBatteryReminderLevels[0] 130 + " .. " + mLowBatteryReminderLevels[1]); 131 Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel); 132 Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus); 133 Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType); 134 Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger); 135 Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket); 136 Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged); 137 } 138 139 if (oldInvalidCharger == 0 && mInvalidCharger != 0) { 140 Slog.d(TAG, "showing invalid charger warning"); 141 showInvalidChargerDialog(); 142 return; 143 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) { 144 dismissInvalidChargerDialog(); 145 } else if (mInvalidChargerDialog != null) { 146 // if invalid charger is showing, don't show low battery 147 return; 148 } 149 150 if (!plugged 151 && (bucket < oldBucket || oldPlugged) 152 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN 153 && bucket < 0) { 154 showLowBatteryWarning(); 155 156 // only play SFX when the dialog comes up or the bucket changes 157 if (bucket != oldBucket || oldPlugged) { 158 playLowBatterySound(); 159 } 160 } else if (plugged || (bucket > oldBucket && bucket > 0)) { 161 dismissLowBatteryWarning(); 162 } else if (mBatteryLevelTextView != null) { 163 showLowBatteryWarning(); 164 } 165 } else { 166 Slog.w(TAG, "unknown intent: " + intent); 167 } 168 } 169 }; 170 171 void dismissLowBatteryWarning() { 172 if (mLowBatteryDialog != null) { 173 Slog.i(TAG, "closing low battery warning: level=" + mBatteryLevel); 174 mLowBatteryDialog.dismiss(); 175 } 176 } 177 178 void showLowBatteryWarning() { 179 Slog.i(TAG, 180 ((mBatteryLevelTextView == null) ? "showing" : "updating") 181 + " low battery warning: level=" + mBatteryLevel 182 + " [" + findBatteryLevelBucket(mBatteryLevel) + "]"); 183 184 CharSequence levelText = mContext.getString( 185 R.string.battery_low_percent_format, mBatteryLevel); 186 187 if (mBatteryLevelTextView != null) { 188 mBatteryLevelTextView.setText(levelText); 189 } else { 190 View v = View.inflate(mContext, R.layout.battery_low, null); 191 mBatteryLevelTextView = (TextView)v.findViewById(R.id.level_percent); 192 193 mBatteryLevelTextView.setText(levelText); 194 195 AlertDialog.Builder b = new AlertDialog.Builder(mContext); 196 b.setCancelable(true); 197 b.setTitle(R.string.battery_low_title); 198 b.setView(v); 199 b.setIconAttribute(android.R.attr.alertDialogIcon); 200 b.setPositiveButton(android.R.string.ok, null); 201 202 final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY); 203 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 204 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK 205 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 206 | Intent.FLAG_ACTIVITY_NO_HISTORY); 207 if (intent.resolveActivity(mContext.getPackageManager()) != null) { 208 b.setNegativeButton(R.string.battery_low_why, 209 new DialogInterface.OnClickListener() { 210 @Override 211 public void onClick(DialogInterface dialog, int which) { 212 mContext.startActivity(intent); 213 dismissLowBatteryWarning(); 214 } 215 }); 216 } 217 218 AlertDialog d = b.create(); 219 d.setOnDismissListener(new DialogInterface.OnDismissListener() { 220 @Override 221 public void onDismiss(DialogInterface dialog) { 222 mLowBatteryDialog = null; 223 mBatteryLevelTextView = null; 224 } 225 }); 226 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 227 d.getWindow().getAttributes().privateFlags |= 228 WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 229 d.show(); 230 mLowBatteryDialog = d; 231 } 232 } 233 234 void playLowBatterySound() { 235 if (DEBUG) { 236 Slog.i(TAG, "playing low battery sound. WOMP-WOMP!"); 237 } 238 239 final ContentResolver cr = mContext.getContentResolver(); 240 if (Settings.System.getInt(cr, Settings.System.POWER_SOUNDS_ENABLED, 1) == 1) { 241 final String soundPath = Settings.System.getString(cr, 242 Settings.System.LOW_BATTERY_SOUND); 243 if (soundPath != null) { 244 final Uri soundUri = Uri.parse("file://" + soundPath); 245 if (soundUri != null) { 246 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); 247 if (sfx != null) { 248 sfx.setStreamType(AudioManager.STREAM_SYSTEM); 249 sfx.play(); 250 } 251 } 252 } 253 } 254 } 255 256 void dismissInvalidChargerDialog() { 257 if (mInvalidChargerDialog != null) { 258 mInvalidChargerDialog.dismiss(); 259 } 260 } 261 262 void showInvalidChargerDialog() { 263 Slog.d(TAG, "showing invalid charger dialog"); 264 265 dismissLowBatteryWarning(); 266 267 AlertDialog.Builder b = new AlertDialog.Builder(mContext); 268 b.setCancelable(true); 269 b.setMessage(R.string.invalid_charger); 270 b.setIconAttribute(android.R.attr.alertDialogIcon); 271 b.setPositiveButton(android.R.string.ok, null); 272 273 AlertDialog d = b.create(); 274 d.setOnDismissListener(new DialogInterface.OnDismissListener() { 275 public void onDismiss(DialogInterface dialog) { 276 mInvalidChargerDialog = null; 277 mBatteryLevelTextView = null; 278 } 279 }); 280 281 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 282 d.show(); 283 mInvalidChargerDialog = d; 284 } 285 286 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 287 pw.print("mLowBatteryAlertCloseLevel="); 288 pw.println(mLowBatteryAlertCloseLevel); 289 pw.print("mLowBatteryReminderLevels="); 290 pw.println(Arrays.toString(mLowBatteryReminderLevels)); 291 pw.print("mInvalidChargerDialog="); 292 pw.println(mInvalidChargerDialog == null ? "null" : mInvalidChargerDialog.toString()); 293 pw.print("mLowBatteryDialog="); 294 pw.println(mLowBatteryDialog == null ? "null" : mLowBatteryDialog.toString()); 295 pw.print("mBatteryLevel="); 296 pw.println(Integer.toString(mBatteryLevel)); 297 pw.print("mBatteryStatus="); 298 pw.println(Integer.toString(mBatteryStatus)); 299 pw.print("mPlugType="); 300 pw.println(Integer.toString(mPlugType)); 301 pw.print("mInvalidCharger="); 302 pw.println(Integer.toString(mInvalidCharger)); 303 pw.print("bucket: "); 304 pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel))); 305 } 306} 307 308