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