PowerUI.java revision ecbc5e828abaf2b10dd7a746ecff9bcfae2b0f7f
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.os.BatteryManager; 26import android.os.Handler; 27import android.os.PowerManager; 28import android.os.SystemClock; 29import android.os.UserHandle; 30import android.provider.Settings; 31import android.util.Log; 32import android.util.Slog; 33 34import com.android.systemui.SystemUI; 35import com.android.systemui.statusbar.phone.PhoneStatusBar; 36 37import java.io.FileDescriptor; 38import java.io.PrintWriter; 39import java.util.Arrays; 40 41public class PowerUI extends SystemUI { 42 static final String TAG = "PowerUI"; 43 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 44 45 private final Handler mHandler = new Handler(); 46 private final Receiver mReceiver = new Receiver(); 47 48 private PowerManager mPowerManager; 49 private WarningsUI mWarnings; 50 private int mBatteryLevel = 100; 51 private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; 52 private int mPlugType = 0; 53 private int mInvalidCharger = 0; 54 55 private int mLowBatteryAlertCloseLevel; 56 private final int[] mLowBatteryReminderLevels = new int[2]; 57 58 private long mScreenOffTime = -1; 59 60 public void start() { 61 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 62 mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime(); 63 mWarnings = new PowerNotificationWarnings(mContext, getComponent(PhoneStatusBar.class)); 64 65 ContentObserver obs = new ContentObserver(mHandler) { 66 @Override 67 public void onChange(boolean selfChange) { 68 updateBatteryWarningLevels(); 69 } 70 }; 71 final ContentResolver resolver = mContext.getContentResolver(); 72 resolver.registerContentObserver(Settings.Global.getUriFor( 73 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL), 74 false, obs, UserHandle.USER_ALL); 75 updateBatteryWarningLevels(); 76 mReceiver.init(); 77 } 78 79 private void setSaverMode(boolean mode) { 80 mWarnings.showSaverMode(mode); 81 } 82 83 void updateBatteryWarningLevels() { 84 int critLevel = mContext.getResources().getInteger( 85 com.android.internal.R.integer.config_criticalBatteryWarningLevel); 86 87 final ContentResolver resolver = mContext.getContentResolver(); 88 int defWarnLevel = mContext.getResources().getInteger( 89 com.android.internal.R.integer.config_lowBatteryWarningLevel); 90 int warnLevel = Settings.Global.getInt(resolver, 91 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel); 92 if (warnLevel == 0) { 93 warnLevel = defWarnLevel; 94 } 95 if (warnLevel < critLevel) { 96 warnLevel = critLevel; 97 } 98 99 mLowBatteryReminderLevels[0] = warnLevel; 100 mLowBatteryReminderLevels[1] = critLevel; 101 mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0] 102 + mContext.getResources().getInteger( 103 com.android.internal.R.integer.config_lowBatteryCloseWarningBump); 104 } 105 106 /** 107 * Buckets the battery level. 108 * 109 * The code in this function is a little weird because I couldn't comprehend 110 * the bucket going up when the battery level was going down. --joeo 111 * 112 * 1 means that the battery is "ok" 113 * 0 means that the battery is between "ok" and what we should warn about. 114 * less than 0 means that the battery is low 115 */ 116 private int findBatteryLevelBucket(int level) { 117 if (level >= mLowBatteryAlertCloseLevel) { 118 return 1; 119 } 120 if (level > mLowBatteryReminderLevels[0]) { 121 return 0; 122 } 123 final int N = mLowBatteryReminderLevels.length; 124 for (int i=N-1; i>=0; i--) { 125 if (level <= mLowBatteryReminderLevels[i]) { 126 return -1-i; 127 } 128 } 129 throw new RuntimeException("not possible!"); 130 } 131 132 private final class Receiver extends BroadcastReceiver { 133 134 public void init() { 135 // Register for Intent broadcasts for... 136 IntentFilter filter = new IntentFilter(); 137 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 138 filter.addAction(Intent.ACTION_SCREEN_OFF); 139 filter.addAction(Intent.ACTION_SCREEN_ON); 140 filter.addAction(Intent.ACTION_USER_SWITCHED); 141 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING); 142 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 143 mContext.registerReceiver(this, filter, null, mHandler); 144 updateSaverMode(); 145 } 146 147 private void updateSaverMode() { 148 setSaverMode(mPowerManager.isPowerSaveMode()); 149 } 150 151 @Override 152 public void onReceive(Context context, Intent intent) { 153 String action = intent.getAction(); 154 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 155 final int oldBatteryLevel = mBatteryLevel; 156 mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100); 157 final int oldBatteryStatus = mBatteryStatus; 158 mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 159 BatteryManager.BATTERY_STATUS_UNKNOWN); 160 final int oldPlugType = mPlugType; 161 mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1); 162 final int oldInvalidCharger = mInvalidCharger; 163 mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0); 164 165 final boolean plugged = mPlugType != 0; 166 final boolean oldPlugged = oldPlugType != 0; 167 168 int oldBucket = findBatteryLevelBucket(oldBatteryLevel); 169 int bucket = findBatteryLevelBucket(mBatteryLevel); 170 171 if (DEBUG) { 172 Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel 173 + " .. " + mLowBatteryReminderLevels[0] 174 + " .. " + mLowBatteryReminderLevels[1]); 175 Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel); 176 Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus); 177 Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType); 178 Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger); 179 Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket); 180 Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged); 181 } 182 183 mWarnings.update(mBatteryLevel, bucket, mScreenOffTime); 184 if (oldInvalidCharger == 0 && mInvalidCharger != 0) { 185 Slog.d(TAG, "showing invalid charger warning"); 186 mWarnings.showInvalidChargerWarning(); 187 return; 188 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) { 189 mWarnings.dismissInvalidChargerWarning(); 190 } else if (mWarnings.isInvalidChargerWarningShowing()) { 191 // if invalid charger is showing, don't show low battery 192 return; 193 } 194 195 if (!plugged 196 && (bucket < oldBucket || oldPlugged) 197 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN 198 && bucket < 0) { 199 // only play SFX when the dialog comes up or the bucket changes 200 final boolean playSound = bucket != oldBucket || oldPlugged; 201 mWarnings.showLowBatteryWarning(playSound); 202 } else if (plugged || (bucket > oldBucket && bucket > 0)) { 203 mWarnings.dismissLowBatteryWarning(); 204 } else { 205 mWarnings.updateLowBatteryWarning(); 206 } 207 } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 208 mScreenOffTime = SystemClock.elapsedRealtime(); 209 } else if (Intent.ACTION_SCREEN_ON.equals(action)) { 210 mScreenOffTime = -1; 211 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { 212 mWarnings.userSwitched(); 213 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) { 214 updateSaverMode(); 215 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) { 216 setSaverMode(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false)); 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 showSaverMode(boolean mode); 255 void dismissLowBatteryWarning(); 256 void showLowBatteryWarning(boolean playSound); 257 void dismissInvalidChargerWarning(); 258 void showInvalidChargerWarning(); 259 void updateLowBatteryWarning(); 260 boolean isInvalidChargerWarningShowing(); 261 void dump(PrintWriter pw); 262 void userSwitched(); 263 } 264} 265 266