1dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler/*
2dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler * Copyright (C) 2013 The Android Open Source Project
3dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler *
4dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler * Licensed under the Apache License, Version 2.0 (the "License");
5dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler * you may not use this file except in compliance with the License.
6dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler * You may obtain a copy of the License at
7dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler *
8dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler *      http://www.apache.org/licenses/LICENSE-2.0
9dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler *
10dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler * Unless required by applicable law or agreed to in writing, software
11dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler * distributed under the License is distributed on an "AS IS" BASIS,
12dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler * See the License for the specific language governing permissions and
14dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler * limitations under the License.
15dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler */
16dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
17dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerpackage com.android.systemui;
18dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
19dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.content.BroadcastReceiver;
20dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.content.Context;
21dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.content.Intent;
22dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.content.IntentFilter;
23dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.content.res.Resources;
24dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.content.res.TypedArray;
25dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.graphics.Canvas;
26dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.graphics.Paint;
27fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlockimport android.graphics.Path;
28fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlockimport android.graphics.PorterDuff;
29fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlockimport android.graphics.PorterDuffXfermode;
30dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.graphics.Rect;
31dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.graphics.RectF;
32dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.graphics.Typeface;
33dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.os.BatteryManager;
343c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlockimport android.os.Bundle;
35dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.provider.Settings;
36dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.util.AttributeSet;
37dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandlerimport android.view.View;
38dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
393c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlockpublic class BatteryMeterView extends View implements DemoMode {
40dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public static final String TAG = BatteryMeterView.class.getSimpleName();
41dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
42dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
43dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public static final boolean ENABLE_PERCENT = true;
44dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public static final boolean SINGLE_DIGIT_PERCENT = false;
45dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public static final boolean SHOW_100_PERCENT = false;
46dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
47dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public static final int FULL = 96;
48dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public static final int EMPTY = 4;
49dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
50cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock    public static final float SUBPIXEL = 0.4f;  // inset rects for softer edges
51cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock
52dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    int[] mColors;
53dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
54dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    boolean mShowPercent = true;
55fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock    Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
56dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    int mButtonHeight;
57dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    private float mTextHeight, mWarningTextHeight;
58dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
59dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    private int mHeight;
60dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    private int mWidth;
61dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    private String mWarningString;
62e189f662df446effc77560a64136652b16d9d54bJohn Spurlock    private final int mChargeColor;
63fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock    private final float[] mBoltPoints;
64fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock    private final Path mBoltPath = new Path();
65fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock
66fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock    private final RectF mFrame = new RectF();
67fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock    private final RectF mButtonFrame = new RectF();
68fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock    private final RectF mClipFrame = new RectF();
69d8595fd8feca567d48c4e271070a75c576a7dfbfJohn Spurlock    private final RectF mBoltFrame = new RectF();
70dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
71dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    private class BatteryTracker extends BroadcastReceiver {
7205021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler        public static final int UNKNOWN_LEVEL = -1;
7305021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler
74dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        // current battery status
7505021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler        int level = UNKNOWN_LEVEL;
76dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        String percentStr;
77dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        int plugType;
78dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        boolean plugged;
79dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        int health;
80dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        int status;
81dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        String technology;
82dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        int voltage;
83dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        int temperature;
84dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        boolean testmode = false;
85dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
86dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        @Override
87dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        public void onReceive(Context context, Intent intent) {
88dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            final String action = intent.getAction();
89dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
90dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                if (testmode && ! intent.getBooleanExtra("testmode", false)) return;
91dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
92dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                level = (int)(100f
93dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
94dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
95dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
96dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
97dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                plugged = plugType != 0;
98dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH,
99dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        BatteryManager.BATTERY_HEALTH_UNKNOWN);
100dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
101dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        BatteryManager.BATTERY_STATUS_UNKNOWN);
102dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
103dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);
104dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
105dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
106dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                setContentDescription(
107dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        context.getString(R.string.accessibility_battery_level, level));
108dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                postInvalidate();
109dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            } else if (action.equals(ACTION_LEVEL_TEST)) {
110dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                testmode = true;
111dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                post(new Runnable() {
112dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    int curLevel = 0;
113dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    int incr = 1;
114dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    int saveLevel = level;
115dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    int savePlugged = plugType;
116dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
117dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    @Override
118dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    public void run() {
119dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        if (curLevel < 0) {
120dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                            testmode = false;
121dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                            dummy.putExtra("level", saveLevel);
122dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                            dummy.putExtra("plugged", savePlugged);
123dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                            dummy.putExtra("testmode", false);
124dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        } else {
125dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                            dummy.putExtra("level", curLevel);
126dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                            dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC : 0);
127dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                            dummy.putExtra("testmode", true);
128dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        }
129dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        getContext().sendBroadcast(dummy);
130dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
131dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        if (!testmode) return;
132dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
133dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        curLevel += incr;
134dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        if (curLevel == 100) {
135dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                            incr *= -1;
136dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        }
137dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                        postDelayed(this, 200);
138dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    }
139dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                });
140dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            }
141dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        }
142dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    }
143dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
144dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    BatteryTracker mTracker = new BatteryTracker();
145dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
146dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    @Override
147dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public void onAttachedToWindow() {
148dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        super.onAttachedToWindow();
149dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
150dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        IntentFilter filter = new IntentFilter();
151dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
152dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        filter.addAction(ACTION_LEVEL_TEST);
15305021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler        final Intent sticky = getContext().registerReceiver(mTracker, filter);
15405021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler        if (sticky != null) {
15505021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler            // preload the battery level
15605021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler            mTracker.onReceive(getContext(), sticky);
15705021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler        }
158dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    }
159dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
160dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    @Override
161dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public void onDetachedFromWindow() {
162dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        super.onDetachedFromWindow();
163dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
164dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        getContext().unregisterReceiver(mTracker);
165dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    }
166dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
167dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public BatteryMeterView(Context context) {
168dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        this(context, null, 0);
169dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    }
170dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
171dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public BatteryMeterView(Context context, AttributeSet attrs) {
172dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        this(context, attrs, 0);
173dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    }
174dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
175dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
176dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        super(context, attrs, defStyle);
177dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
178dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        final Resources res = context.getResources();
179dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
180dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
181dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
182dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        final int N = levels.length();
183dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mColors = new int[2*N];
184dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        for (int i=0; i<N; i++) {
185dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            mColors[2*i] = levels.getInt(i, 0);
186dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            mColors[2*i+1] = colors.getColor(i, 0);
187dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        }
188fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        levels.recycle();
189fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        colors.recycle();
190dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
191dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                context.getContentResolver(), "status_bar_show_battery_percent", 0);
192dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
193dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
194dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
195dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
196dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mFramePaint.setColor(res.getColor(R.color.batterymeter_frame_color));
197cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mFramePaint.setDither(true);
198cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mFramePaint.setStrokeWidth(0);
199cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
200cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mFramePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
201cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock
202dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
203cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mBatteryPaint.setDither(true);
204cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mBatteryPaint.setStrokeWidth(0);
205cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
206dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
207dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
208dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mTextPaint.setColor(0xFFFFFFFF);
209dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        Typeface font = Typeface.create("sans-serif-condensed", Typeface.NORMAL);
210dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mTextPaint.setTypeface(font);
211dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mTextPaint.setTextAlign(Paint.Align.CENTER);
212dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
213dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
214dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mWarningTextPaint.setColor(mColors[1]);
215dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        font = Typeface.create("sans-serif", Typeface.BOLD);
216dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mWarningTextPaint.setTypeface(font);
217dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
218dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
219e189f662df446effc77560a64136652b16d9d54bJohn Spurlock        mChargeColor = getResources().getColor(R.color.batterymeter_charge_color);
220fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock
221fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        mBoltPaint = new Paint();
222fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        mBoltPaint.setAntiAlias(true);
223cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mBoltPaint.setColor(res.getColor(R.color.batterymeter_bolt_color));
224fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        mBoltPoints = loadBoltPoints(res);
225cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
226fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock    }
227fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock
228fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock    private static float[] loadBoltPoints(Resources res) {
229fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
230fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        int maxX = 0, maxY = 0;
231fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        for (int i = 0; i < pts.length; i += 2) {
232fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock            maxX = Math.max(maxX, pts[i]);
233fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock            maxY = Math.max(maxY, pts[i + 1]);
234fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        }
235fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        final float[] ptsF = new float[pts.length];
236fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        for (int i = 0; i < pts.length; i += 2) {
237fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock            ptsF[i] = (float)pts[i] / maxX;
238fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock            ptsF[i + 1] = (float)pts[i + 1] / maxY;
239fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        }
240fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        return ptsF;
241dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    }
242dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
243dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    @Override
244dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
245dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mHeight = h;
246dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mWidth = w;
247dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mWarningTextPaint.setTextSize(h * 0.75f);
248dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
249dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    }
250dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
251dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    private int getColorForLevel(int percent) {
252dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        int thresh, color = 0;
253dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        for (int i=0; i<mColors.length; i+=2) {
254dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            thresh = mColors[i];
255dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            color = mColors[i+1];
256dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            if (percent <= thresh) return color;
257dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        }
258dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        return color;
259dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    }
260dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
261dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    @Override
262dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    public void draw(Canvas c) {
2633c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock        BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
2643c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock        final int level = tracker.level;
26505021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler
26605021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler        if (level == BatteryTracker.UNKNOWN_LEVEL) return;
26705021e5e47132799efc3f8312fbca7cb20e6fc71Daniel Sandler
268dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        float drawFrac = (float) level / 100f;
269dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        final int pt = getPaddingTop();
270dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        final int pl = getPaddingLeft();
271dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        final int pr = getPaddingRight();
272dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        final int pb = getPaddingBottom();
273dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        int height = mHeight - pt - pb;
274dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        int width = mWidth - pl - pr;
275dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
276dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mButtonHeight = (int) (height * 0.12f);
277dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
278fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        mFrame.set(0, 0, width, height);
279fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        mFrame.offset(pl, pt);
280dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
281fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        mButtonFrame.set(
282fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                mFrame.left + width * 0.25f,
283fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                mFrame.top,
284fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                mFrame.right - width * 0.25f,
285cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock                mFrame.top + mButtonHeight + 5 /*cover frame border of intersecting area*/);
286cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock
287cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mButtonFrame.top += SUBPIXEL;
288cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mButtonFrame.left += SUBPIXEL;
289cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mButtonFrame.right -= SUBPIXEL;
290dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
291fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        mFrame.top += mButtonHeight;
292cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mFrame.left += SUBPIXEL;
293cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mFrame.top += SUBPIXEL;
294cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mFrame.right -= SUBPIXEL;
295cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        mFrame.bottom -= SUBPIXEL;
296dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
297dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        // first, draw the battery shape
298fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        c.drawRect(mFrame, mFramePaint);
299dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
300dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        // fill 'er up
301cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock        final int color = tracker.plugged ? mChargeColor : getColorForLevel(level);
302dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        mBatteryPaint.setColor(color);
303dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
304dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        if (level >= FULL) {
305dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            drawFrac = 1f;
306dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        } else if (level <= EMPTY) {
307dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            drawFrac = 0f;
308dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        }
309dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
310fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        c.drawRect(mButtonFrame, drawFrac == 1f ? mBatteryPaint : mFramePaint);
311dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
312fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        mClipFrame.set(mFrame);
313fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        mClipFrame.top += (mFrame.height() * (1f - drawFrac));
314dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
315dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        c.save(Canvas.CLIP_SAVE_FLAG);
316fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        c.clipRect(mClipFrame);
317fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock        c.drawRect(mFrame, mBatteryPaint);
318dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        c.restore();
319dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
320d19877f8a3557702d87bc9ed8c4be947e947b8b7John Spurlock        if (tracker.plugged) {
321fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock            // draw the bolt
322d8595fd8feca567d48c4e271070a75c576a7dfbfJohn Spurlock            final float bl = mFrame.left + mFrame.width() / 4.5f;
323d8595fd8feca567d48c4e271070a75c576a7dfbfJohn Spurlock            final float bt = mFrame.top + mFrame.height() / 6f;
324d8595fd8feca567d48c4e271070a75c576a7dfbfJohn Spurlock            final float br = mFrame.right - mFrame.width() / 7f;
325d8595fd8feca567d48c4e271070a75c576a7dfbfJohn Spurlock            final float bb = mFrame.bottom - mFrame.height() / 10f;
326fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock            if (mBoltFrame.left != bl || mBoltFrame.top != bt
327fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                    || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
328fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                mBoltFrame.set(bl, bt, br, bb);
329fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                mBoltPath.reset();
330fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                mBoltPath.moveTo(
331fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
332fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
333fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                for (int i = 2; i < mBoltPoints.length; i += 2) {
334fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                    mBoltPath.lineTo(
335fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                            mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
336fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                            mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
337fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                }
338fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                mBoltPath.lineTo(
339fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
340fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
341fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock            }
342fceb7edddeda6962212377cb88391d9affe5967aJohn Spurlock            c.drawPath(mBoltPath, mBoltPaint);
343d19877f8a3557702d87bc9ed8c4be947e947b8b7John Spurlock        } else if (level <= EMPTY) {
344d19877f8a3557702d87bc9ed8c4be947e947b8b7John Spurlock            final float x = mWidth * 0.5f;
345d19877f8a3557702d87bc9ed8c4be947e947b8b7John Spurlock            final float y = (mHeight + mWarningTextHeight) * 0.48f;
346d19877f8a3557702d87bc9ed8c4be947e947b8b7John Spurlock            c.drawText(mWarningString, x, y, mWarningTextPaint);
3473c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock        } else if (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
348dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            mTextPaint.setTextSize(height *
349dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    (SINGLE_DIGIT_PERCENT ? 0.75f
3503c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock                            : (tracker.level == 100 ? 0.38f : 0.5f)));
351dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            mTextHeight = -mTextPaint.getFontMetrics().ascent;
352dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler
353cfab99005360819294c65280d8b695ab50c1f0b3John Spurlock            final String str = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
354dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            final float x = mWidth * 0.5f;
355dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            final float y = (mHeight + mTextHeight) * 0.47f;
356dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler            c.drawText(str,
357dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    x,
358dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    y,
359dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler                    mTextPaint);
360dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler        }
361dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler    }
3623c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock
3633c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock    private boolean mDemoMode;
3643c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock    private BatteryTracker mDemoTracker = new BatteryTracker();
3653c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock
3663c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock    @Override
3673c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock    public void dispatchDemoCommand(String command, Bundle args) {
3683c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
3693c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock            mDemoMode = true;
3703c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock            mDemoTracker.level = mTracker.level;
3713c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock            mDemoTracker.plugged = mTracker.plugged;
3723c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
3733c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock            mDemoMode = false;
3743c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock            postInvalidate();
3753c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock        } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
3763c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock           String level = args.getString("level");
3773c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock           String plugged = args.getString("plugged");
3783c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock           if (level != null) {
3793c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock               mDemoTracker.level = Math.min(Math.max(Integer.parseInt(level), 0), 100);
3803c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock           }
3813c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock           if (plugged != null) {
3823c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock               mDemoTracker.plugged = Boolean.parseBoolean(plugged);
3833c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock           }
3843c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock           postInvalidate();
3853c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock        }
3863c87566c115e1fce3fdc09a6fe40488bcdc04cdeJohn Spurlock    }
387dfaf3bdeeb21c8421074c70d82642612bcdd8e98Daniel Sandler}
388