PowerUI.java revision 3332ba54ae85df14d761447d86d2aa19d448ce11
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 android.content.BroadcastReceiver; 20import android.content.ContentResolver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.database.ContentObserver; 25import android.net.Uri; 26import android.os.BatteryManager; 27import android.os.Handler; 28import android.os.PowerManager; 29import android.os.SystemClock; 30import android.os.UserHandle; 31import android.provider.Settings; 32import android.util.Slog; 33 34import com.android.systemui.SystemUI; 35 36import java.io.FileDescriptor; 37import java.io.PrintWriter; 38import java.util.Arrays; 39 40public class PowerUI extends SystemUI { 41 static final String TAG = "PowerUI"; 42 static final boolean DEBUG = false; 43 44 45 private final Handler mHandler = new Handler(); 46 private final SettingsObserver mObserver = new SettingsObserver(mHandler); 47 private final Receiver mReceiver = new Receiver(); 48 49 private PowerManager mPowerManager; 50 private WarningsUI mWarnings; 51 private int mBatteryLevel = 100; 52 private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; 53 private int mPlugType = 0; 54 private int mInvalidCharger = 0; 55 56 private int mLowBatteryAlertCloseLevel; 57 private final int[] mLowBatteryReminderLevels = new int[2]; 58 59 private long mScreenOffTime = -1; 60 61 public void start() { 62 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 63 mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime(); 64 mWarnings = new PowerNotificationWarnings(mContext); 65 66 ContentObserver obs = new ContentObserver(mHandler) { 67 @Override 68 public void onChange(boolean selfChange) { 69 updateBatteryWarningLevels(); 70 } 71 }; 72 final ContentResolver resolver = mContext.getContentResolver(); 73 resolver.registerContentObserver(Settings.Global.getUriFor( 74 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL), 75 false, obs, UserHandle.USER_ALL); 76 updateBatteryWarningLevels(); 77 mReceiver.init(); 78 mObserver.init(); 79 } 80 81 private void setSaverMode(boolean mode) { 82 mWarnings.showSaverMode(mode); 83 } 84 85 private void setSaverTrigger(int level) { 86 mWarnings.setSaverTrigger(level); 87 } 88 89 void updateBatteryWarningLevels() { 90 int critLevel = mContext.getResources().getInteger( 91 com.android.internal.R.integer.config_criticalBatteryWarningLevel); 92 93 final ContentResolver resolver = mContext.getContentResolver(); 94 int defWarnLevel = mContext.getResources().getInteger( 95 com.android.internal.R.integer.config_lowBatteryWarningLevel); 96 int warnLevel = Settings.Global.getInt(resolver, 97 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel); 98 if (warnLevel == 0) { 99 warnLevel = defWarnLevel; 100 } 101 if (warnLevel < critLevel) { 102 warnLevel = critLevel; 103 } 104 105 mLowBatteryReminderLevels[0] = warnLevel; 106 mLowBatteryReminderLevels[1] = critLevel; 107 mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0] 108 + mContext.getResources().getInteger( 109 com.android.internal.R.integer.config_lowBatteryCloseWarningBump); 110 } 111 112 /** 113 * Buckets the battery level. 114 * 115 * The code in this function is a little weird because I couldn't comprehend 116 * the bucket going up when the battery level was going down. --joeo 117 * 118 * 1 means that the battery is "ok" 119 * 0 means that the battery is between "ok" and what we should warn about. 120 * less than 0 means that the battery is low 121 */ 122 private int findBatteryLevelBucket(int level) { 123 if (level >= mLowBatteryAlertCloseLevel) { 124 return 1; 125 } 126 if (level > mLowBatteryReminderLevels[0]) { 127 return 0; 128 } 129 final int N = mLowBatteryReminderLevels.length; 130 for (int i=N-1; i>=0; i--) { 131 if (level <= mLowBatteryReminderLevels[i]) { 132 return -1-i; 133 } 134 } 135 throw new RuntimeException("not possible!"); 136 } 137 138 private final class Receiver extends BroadcastReceiver { 139 140 public void init() { 141 // Register for Intent broadcasts for... 142 IntentFilter filter = new IntentFilter(); 143 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 144 filter.addAction(Intent.ACTION_SCREEN_OFF); 145 filter.addAction(Intent.ACTION_SCREEN_ON); 146 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 147 mContext.registerReceiver(this, filter, null, mHandler); 148 updateSaverMode(); 149 } 150 151 private void updateSaverMode() { 152 setSaverMode(mPowerManager.isPowerSaveMode()); 153 } 154 155 @Override 156 public void onReceive(Context context, Intent intent) { 157 String action = intent.getAction(); 158 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 159 final int oldBatteryLevel = mBatteryLevel; 160 mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100); 161 final int oldBatteryStatus = mBatteryStatus; 162 mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 163 BatteryManager.BATTERY_STATUS_UNKNOWN); 164 final int oldPlugType = mPlugType; 165 mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1); 166 final int oldInvalidCharger = mInvalidCharger; 167 mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0); 168 169 final boolean plugged = mPlugType != 0; 170 final boolean oldPlugged = oldPlugType != 0; 171 172 int oldBucket = findBatteryLevelBucket(oldBatteryLevel); 173 int bucket = findBatteryLevelBucket(mBatteryLevel); 174 175 if (DEBUG) { 176 Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel 177 + " .. " + mLowBatteryReminderLevels[0] 178 + " .. " + mLowBatteryReminderLevels[1]); 179 Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel); 180 Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus); 181 Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType); 182 Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger); 183 Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket); 184 Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged); 185 } 186 187 mWarnings.update(mBatteryLevel, bucket, mScreenOffTime); 188 if (oldInvalidCharger == 0 && mInvalidCharger != 0) { 189 Slog.d(TAG, "showing invalid charger warning"); 190 mWarnings.showInvalidChargerWarning(); 191 return; 192 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) { 193 mWarnings.dismissInvalidChargerWarning(); 194 } else if (mWarnings.isInvalidChargerWarningShowing()) { 195 // if invalid charger is showing, don't show low battery 196 return; 197 } 198 199 if (!plugged 200 && (bucket < oldBucket || oldPlugged) 201 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN 202 && bucket < 0) { 203 // only play SFX when the dialog comes up or the bucket changes 204 final boolean playSound = bucket != oldBucket || oldPlugged; 205 mWarnings.showLowBatteryWarning(playSound); 206 } else if (plugged || (bucket > oldBucket && bucket > 0)) { 207 mWarnings.dismissLowBatteryWarning(); 208 } else { 209 mWarnings.updateLowBatteryWarning(); 210 } 211 } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 212 mScreenOffTime = SystemClock.elapsedRealtime(); 213 } else if (Intent.ACTION_SCREEN_ON.equals(action)) { 214 mScreenOffTime = -1; 215 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) { 216 updateSaverMode(); 217 } else { 218 Slog.w(TAG, "unknown intent: " + intent); 219 } 220 } 221 }; 222 223 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 224 pw.print("mLowBatteryAlertCloseLevel="); 225 pw.println(mLowBatteryAlertCloseLevel); 226 pw.print("mLowBatteryReminderLevels="); 227 pw.println(Arrays.toString(mLowBatteryReminderLevels)); 228 pw.print("mBatteryLevel="); 229 pw.println(Integer.toString(mBatteryLevel)); 230 pw.print("mBatteryStatus="); 231 pw.println(Integer.toString(mBatteryStatus)); 232 pw.print("mPlugType="); 233 pw.println(Integer.toString(mPlugType)); 234 pw.print("mInvalidCharger="); 235 pw.println(Integer.toString(mInvalidCharger)); 236 pw.print("mScreenOffTime="); 237 pw.print(mScreenOffTime); 238 if (mScreenOffTime >= 0) { 239 pw.print(" ("); 240 pw.print(SystemClock.elapsedRealtime() - mScreenOffTime); 241 pw.print(" ago)"); 242 } 243 pw.println(); 244 pw.print("soundTimeout="); 245 pw.println(Settings.Global.getInt(mContext.getContentResolver(), 246 Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0)); 247 pw.print("bucket: "); 248 pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel))); 249 mWarnings.dump(pw); 250 } 251 252 public interface WarningsUI { 253 void update(int batteryLevel, int bucket, long screenOffTime); 254 void setSaverTrigger(int level); 255 void showSaverMode(boolean mode); 256 void dismissLowBatteryWarning(); 257 void showLowBatteryWarning(boolean playSound); 258 void dismissInvalidChargerWarning(); 259 void showInvalidChargerWarning(); 260 void updateLowBatteryWarning(); 261 boolean isInvalidChargerWarningShowing(); 262 void dump(PrintWriter pw); 263 } 264 265 private final class SettingsObserver extends ContentObserver { 266 private final Uri LOW_POWER_MODE_TRIGGER_LEVEL_URI = 267 Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL); 268 269 public SettingsObserver(Handler handler) { 270 super(handler); 271 } 272 273 public void init() { 274 onChange(true, LOW_POWER_MODE_TRIGGER_LEVEL_URI); 275 final ContentResolver cr = mContext.getContentResolver(); 276 cr.registerContentObserver(LOW_POWER_MODE_TRIGGER_LEVEL_URI, false, this); 277 } 278 279 @Override 280 public void onChange(boolean selfChange, Uri uri) { 281 if (LOW_POWER_MODE_TRIGGER_LEVEL_URI.equals(uri)) { 282 final int level = Settings.Global.getInt(mContext.getContentResolver(), 283 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0); 284 setSaverTrigger(level); 285 } 286 } 287 } 288} 289 290