PowerUI.java revision e797b82c767a68cddbe90555426116a669a2f7d9
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 Handler mHandler = new Handler(); 49 50 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; 59 AlertDialog mLowBatteryDialog; 60 TextView mBatteryLevelTextView; 61 62 public void start() { 63 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 71 // Register for Intent broadcasts for... 72 IntentFilter filter = new IntentFilter(); 73 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 74 filter.addAction(Intent.ACTION_POWER_CONNECTED); 75 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); 76 } 77 78 /** 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 104 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)) { 109 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(); 160 } 161 } else { 162 Slog.w(TAG, "unknown intent: " + intent); 163 } 164 } 165 }; 166 167 void dismissLowBatteryWarning() { 168 if (mLowBatteryDialog != null) { 169 mLowBatteryDialog.dismiss(); 170 } 171 } 172 173 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); 189 b.setIconAttribute(android.R.attr.alertDialogIcon); 190 b.setPositiveButton(android.R.string.ok, null); 191 192 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(); 204 } 205 } 206 }); 207 } 208 209 AlertDialog d = b.create(); 210 d.setOnDismissListener(new DialogInterface.OnDismissListener() { 211 public void onDismiss(DialogInterface dialog) { 212 mLowBatteryDialog = null; 213 mBatteryLevelTextView = null; 214 } 215 }); 216 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) { 230 sfx.setStreamType(AudioManager.STREAM_SYSTEM); 231 sfx.play(); 232 } 233 } 234 } 235 } 236 } 237 238 void dismissInvalidChargerDialog() { 239 if (mInvalidChargerDialog != null) { 240 mInvalidChargerDialog.dismiss(); 241 } 242 } 243 244 void showInvalidChargerDialog() { 245 dismissLowBatteryWarning(); 246 247 AlertDialog.Builder b = new AlertDialog.Builder(mContext); 248 b.setCancelable(true); 249 b.setMessage(R.string.invalid_charger); 250 b.setIconAttribute(android.R.attr.alertDialogIcon); 251 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 } 265 266 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 267 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))); 285 } 286} 287 288