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