1abe1974a11364b577e94966ca87047d7889c8edfJason Monk/*
2abe1974a11364b577e94966ca87047d7889c8edfJason Monk * Copyright (C) 2015 The Android Open Source Project
3abe1974a11364b577e94966ca87047d7889c8edfJason Monk *
4abe1974a11364b577e94966ca87047d7889c8edfJason Monk * Licensed under the Apache License, Version 2.0 (the "License");
5abe1974a11364b577e94966ca87047d7889c8edfJason Monk * you may not use this file except in compliance with the License.
6abe1974a11364b577e94966ca87047d7889c8edfJason Monk * You may obtain a copy of the License at
7abe1974a11364b577e94966ca87047d7889c8edfJason Monk *
8abe1974a11364b577e94966ca87047d7889c8edfJason Monk *      http://www.apache.org/licenses/LICENSE-2.0
9abe1974a11364b577e94966ca87047d7889c8edfJason Monk *
10abe1974a11364b577e94966ca87047d7889c8edfJason Monk * Unless required by applicable law or agreed to in writing, software
11abe1974a11364b577e94966ca87047d7889c8edfJason Monk * distributed under the License is distributed on an "AS IS" BASIS,
12abe1974a11364b577e94966ca87047d7889c8edfJason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13abe1974a11364b577e94966ca87047d7889c8edfJason Monk * See the License for the specific language governing permissions and
14abe1974a11364b577e94966ca87047d7889c8edfJason Monk * limitations under the License.
15abe1974a11364b577e94966ca87047d7889c8edfJason Monk */
16abe1974a11364b577e94966ca87047d7889c8edfJason Monk
17abe1974a11364b577e94966ca87047d7889c8edfJason Monkpackage com.android.systemui;
18abe1974a11364b577e94966ca87047d7889c8edfJason Monk
19abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.animation.ArgbEvaluator;
20abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.annotation.Nullable;
21abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.content.Context;
22abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.content.res.Resources;
23abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.content.res.TypedArray;
24abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.database.ContentObserver;
25c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport android.graphics.Canvas;
26c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport android.graphics.Color;
27c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport android.graphics.ColorFilter;
28c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport android.graphics.Paint;
29c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport android.graphics.Path;
30c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport android.graphics.RectF;
31c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport android.graphics.Typeface;
32abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.graphics.drawable.Drawable;
33abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.net.Uri;
34abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.os.Bundle;
35abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.os.Handler;
36abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport android.provider.Settings;
37c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson
38abe1974a11364b577e94966ca87047d7889c8edfJason Monkimport com.android.systemui.statusbar.policy.BatteryController;
39abe1974a11364b577e94966ca87047d7889c8edfJason Monk
4098d7c7a84d007d3de0c3394d8a93253a313eda27Jason Monkpublic class BatteryMeterDrawable extends Drawable implements
41abe1974a11364b577e94966ca87047d7889c8edfJason Monk        BatteryController.BatteryStateChangeCallback {
42abe1974a11364b577e94966ca87047d7889c8edfJason Monk
43abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private static final float ASPECT_RATIO = 9.5f / 14.5f;
44abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public static final String TAG = BatteryMeterDrawable.class.getSimpleName();
45abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
46abe1974a11364b577e94966ca87047d7889c8edfJason Monk
47abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private static final boolean SINGLE_DIGIT_PERCENT = false;
48abe1974a11364b577e94966ca87047d7889c8edfJason Monk
49abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private static final int FULL = 96;
50abe1974a11364b577e94966ca87047d7889c8edfJason Monk
51abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private static final float BOLT_LEVEL_THRESHOLD = 0.3f;  // opaque bolt below this fraction
52abe1974a11364b577e94966ca87047d7889c8edfJason Monk
53abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final int[] mColors;
54eae7c318864bcfd814c8be697315f829952ccc69Jason Monk    private final int mIntrinsicWidth;
55eae7c318864bcfd814c8be697315f829952ccc69Jason Monk    private final int mIntrinsicHeight;
56abe1974a11364b577e94966ca87047d7889c8edfJason Monk
57abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private boolean mShowPercent;
58abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private float mButtonHeightFraction;
59abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private float mSubpixelSmoothingLeft;
60abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private float mSubpixelSmoothingRight;
61c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk    private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint,
62c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            mPlusPaint;
63abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private float mTextHeight, mWarningTextHeight;
64abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int mIconTint = Color.WHITE;
6586905582411c5c77a3e7641589cf206c6e5770f5Jorim Jaggi    private float mOldDarkIntensity = 0f;
66abe1974a11364b577e94966ca87047d7889c8edfJason Monk
67abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int mHeight;
68abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int mWidth;
69abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private String mWarningString;
70abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final int mCriticalLevel;
71abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int mChargeColor;
72abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final float[] mBoltPoints;
73abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final Path mBoltPath = new Path();
74c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk    private final float[] mPlusPoints;
75c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk    private final Path mPlusPath = new Path();
76abe1974a11364b577e94966ca87047d7889c8edfJason Monk
77abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final RectF mFrame = new RectF();
78abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final RectF mButtonFrame = new RectF();
79abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final RectF mBoltFrame = new RectF();
80c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk    private final RectF mPlusFrame = new RectF();
81abe1974a11364b577e94966ca87047d7889c8edfJason Monk
82abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final Path mShapePath = new Path();
83abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final Path mClipPath = new Path();
84abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final Path mTextPath = new Path();
85abe1974a11364b577e94966ca87047d7889c8edfJason Monk
86abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private BatteryController mBatteryController;
87abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private boolean mPowerSaveEnabled;
88abe1974a11364b577e94966ca87047d7889c8edfJason Monk
89abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int mDarkModeBackgroundColor;
90abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int mDarkModeFillColor;
91abe1974a11364b577e94966ca87047d7889c8edfJason Monk
92abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int mLightModeBackgroundColor;
93abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int mLightModeFillColor;
94abe1974a11364b577e94966ca87047d7889c8edfJason Monk
95abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final SettingObserver mSettingObserver = new SettingObserver();
96abe1974a11364b577e94966ca87047d7889c8edfJason Monk
97abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final Context mContext;
98abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final Handler mHandler;
99abe1974a11364b577e94966ca87047d7889c8edfJason Monk
100abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int mLevel = -1;
101abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private boolean mPluggedIn;
102abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private boolean mListening;
103abe1974a11364b577e94966ca87047d7889c8edfJason Monk
104abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public BatteryMeterDrawable(Context context, Handler handler, int frameColor) {
105abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mContext = context;
106abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mHandler = handler;
107abe1974a11364b577e94966ca87047d7889c8edfJason Monk        final Resources res = context.getResources();
108abe1974a11364b577e94966ca87047d7889c8edfJason Monk        TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
109abe1974a11364b577e94966ca87047d7889c8edfJason Monk        TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
110abe1974a11364b577e94966ca87047d7889c8edfJason Monk
111abe1974a11364b577e94966ca87047d7889c8edfJason Monk        final int N = levels.length();
112abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mColors = new int[2*N];
113abe1974a11364b577e94966ca87047d7889c8edfJason Monk        for (int i=0; i<N; i++) {
114abe1974a11364b577e94966ca87047d7889c8edfJason Monk            mColors[2*i] = levels.getInt(i, 0);
115abe1974a11364b577e94966ca87047d7889c8edfJason Monk            mColors[2*i+1] = colors.getColor(i, 0);
116abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
117abe1974a11364b577e94966ca87047d7889c8edfJason Monk        levels.recycle();
118abe1974a11364b577e94966ca87047d7889c8edfJason Monk        colors.recycle();
119abe1974a11364b577e94966ca87047d7889c8edfJason Monk        updateShowPercent();
120abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
121abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mCriticalLevel = mContext.getResources().getInteger(
122abe1974a11364b577e94966ca87047d7889c8edfJason Monk                com.android.internal.R.integer.config_criticalBatteryWarningLevel);
123abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mButtonHeightFraction = context.getResources().getFraction(
124abe1974a11364b577e94966ca87047d7889c8edfJason Monk                R.fraction.battery_button_height_fraction, 1, 1);
125abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mSubpixelSmoothingLeft = context.getResources().getFraction(
126abe1974a11364b577e94966ca87047d7889c8edfJason Monk                R.fraction.battery_subpixel_smoothing_left, 1, 1);
127abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mSubpixelSmoothingRight = context.getResources().getFraction(
128abe1974a11364b577e94966ca87047d7889c8edfJason Monk                R.fraction.battery_subpixel_smoothing_right, 1, 1);
129abe1974a11364b577e94966ca87047d7889c8edfJason Monk
130abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
131abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFramePaint.setColor(frameColor);
132abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFramePaint.setDither(true);
133abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFramePaint.setStrokeWidth(0);
134abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
135abe1974a11364b577e94966ca87047d7889c8edfJason Monk
136abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
137abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBatteryPaint.setDither(true);
138abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBatteryPaint.setStrokeWidth(0);
139abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
140abe1974a11364b577e94966ca87047d7889c8edfJason Monk
141abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
142abe1974a11364b577e94966ca87047d7889c8edfJason Monk        Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
143abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mTextPaint.setTypeface(font);
144abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mTextPaint.setTextAlign(Paint.Align.CENTER);
145abe1974a11364b577e94966ca87047d7889c8edfJason Monk
146abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
147abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mWarningTextPaint.setColor(mColors[1]);
148abe1974a11364b577e94966ca87047d7889c8edfJason Monk        font = Typeface.create("sans-serif", Typeface.BOLD);
149abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mWarningTextPaint.setTypeface(font);
150abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
151abe1974a11364b577e94966ca87047d7889c8edfJason Monk
152abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mChargeColor = context.getColor(R.color.batterymeter_charge_color);
153abe1974a11364b577e94966ca87047d7889c8edfJason Monk
154abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
155abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
156abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBoltPoints = loadBoltPoints(res);
157abe1974a11364b577e94966ca87047d7889c8edfJason Monk
158c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        mPlusPaint = new Paint(mBoltPaint);
159c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        mPlusPoints = loadPlusPoints(res);
160c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk
161abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mDarkModeBackgroundColor =
162abe1974a11364b577e94966ca87047d7889c8edfJason Monk                context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
163abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
164abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mLightModeBackgroundColor =
165abe1974a11364b577e94966ca87047d7889c8edfJason Monk                context.getColor(R.color.light_mode_icon_color_dual_tone_background);
166abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
167eae7c318864bcfd814c8be697315f829952ccc69Jason Monk
168eae7c318864bcfd814c8be697315f829952ccc69Jason Monk        mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
169eae7c318864bcfd814c8be697315f829952ccc69Jason Monk        mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
170eae7c318864bcfd814c8be697315f829952ccc69Jason Monk    }
171eae7c318864bcfd814c8be697315f829952ccc69Jason Monk
172eae7c318864bcfd814c8be697315f829952ccc69Jason Monk    @Override
173eae7c318864bcfd814c8be697315f829952ccc69Jason Monk    public int getIntrinsicHeight() {
174eae7c318864bcfd814c8be697315f829952ccc69Jason Monk        return mIntrinsicHeight;
175eae7c318864bcfd814c8be697315f829952ccc69Jason Monk    }
176eae7c318864bcfd814c8be697315f829952ccc69Jason Monk
177eae7c318864bcfd814c8be697315f829952ccc69Jason Monk    @Override
178eae7c318864bcfd814c8be697315f829952ccc69Jason Monk    public int getIntrinsicWidth() {
179eae7c318864bcfd814c8be697315f829952ccc69Jason Monk        return mIntrinsicWidth;
180abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
181abe1974a11364b577e94966ca87047d7889c8edfJason Monk
182abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public void startListening() {
183abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mListening = true;
184abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mContext.getContentResolver().registerContentObserver(
185abe1974a11364b577e94966ca87047d7889c8edfJason Monk                Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
1865c404c8dc6c2a603030e840216fc3c6984009cd3Jason Monk        updateShowPercent();
187abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBatteryController.addStateChangedCallback(this);
188abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
189abe1974a11364b577e94966ca87047d7889c8edfJason Monk
190abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public void stopListening() {
191abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mListening = false;
192abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
193abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBatteryController.removeStateChangedCallback(this);
194abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
195abe1974a11364b577e94966ca87047d7889c8edfJason Monk
1965c404c8dc6c2a603030e840216fc3c6984009cd3Jason Monk    public void disableShowPercent() {
1975c404c8dc6c2a603030e840216fc3c6984009cd3Jason Monk        mShowPercent = false;
1985c404c8dc6c2a603030e840216fc3c6984009cd3Jason Monk        postInvalidate();
1995c404c8dc6c2a603030e840216fc3c6984009cd3Jason Monk    }
2005c404c8dc6c2a603030e840216fc3c6984009cd3Jason Monk
201abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private void postInvalidate() {
202abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mHandler.post(new Runnable() {
203abe1974a11364b577e94966ca87047d7889c8edfJason Monk            @Override
204abe1974a11364b577e94966ca87047d7889c8edfJason Monk            public void run() {
205abe1974a11364b577e94966ca87047d7889c8edfJason Monk                invalidateSelf();
206abe1974a11364b577e94966ca87047d7889c8edfJason Monk            }
207abe1974a11364b577e94966ca87047d7889c8edfJason Monk        });
208abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
209abe1974a11364b577e94966ca87047d7889c8edfJason Monk
210abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public void setBatteryController(BatteryController batteryController) {
211abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBatteryController = batteryController;
212abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mPowerSaveEnabled = mBatteryController.isPowerSave();
213abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
214abe1974a11364b577e94966ca87047d7889c8edfJason Monk
215abe1974a11364b577e94966ca87047d7889c8edfJason Monk    @Override
216abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
217abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mLevel = level;
218abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mPluggedIn = pluggedIn;
219abe1974a11364b577e94966ca87047d7889c8edfJason Monk
220abe1974a11364b577e94966ca87047d7889c8edfJason Monk        postInvalidate();
221abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
222abe1974a11364b577e94966ca87047d7889c8edfJason Monk
223abe1974a11364b577e94966ca87047d7889c8edfJason Monk    @Override
224c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk    public void onPowerSaveChanged(boolean isPowerSave) {
225c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        mPowerSaveEnabled = isPowerSave;
226abe1974a11364b577e94966ca87047d7889c8edfJason Monk        invalidateSelf();
227abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
228abe1974a11364b577e94966ca87047d7889c8edfJason Monk
229abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private static float[] loadBoltPoints(Resources res) {
230abe1974a11364b577e94966ca87047d7889c8edfJason Monk        final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
231abe1974a11364b577e94966ca87047d7889c8edfJason Monk        int maxX = 0, maxY = 0;
232abe1974a11364b577e94966ca87047d7889c8edfJason Monk        for (int i = 0; i < pts.length; i += 2) {
233abe1974a11364b577e94966ca87047d7889c8edfJason Monk            maxX = Math.max(maxX, pts[i]);
234abe1974a11364b577e94966ca87047d7889c8edfJason Monk            maxY = Math.max(maxY, pts[i + 1]);
235abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
236abe1974a11364b577e94966ca87047d7889c8edfJason Monk        final float[] ptsF = new float[pts.length];
237abe1974a11364b577e94966ca87047d7889c8edfJason Monk        for (int i = 0; i < pts.length; i += 2) {
238abe1974a11364b577e94966ca87047d7889c8edfJason Monk            ptsF[i] = (float)pts[i] / maxX;
239abe1974a11364b577e94966ca87047d7889c8edfJason Monk            ptsF[i + 1] = (float)pts[i + 1] / maxY;
240abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
241abe1974a11364b577e94966ca87047d7889c8edfJason Monk        return ptsF;
242abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
243abe1974a11364b577e94966ca87047d7889c8edfJason Monk
244c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk    private static float[] loadPlusPoints(Resources res) {
245c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        final int[] pts = res.getIntArray(R.array.batterymeter_plus_points);
246c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        int maxX = 0, maxY = 0;
247c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        for (int i = 0; i < pts.length; i += 2) {
248c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            maxX = Math.max(maxX, pts[i]);
249c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            maxY = Math.max(maxY, pts[i + 1]);
250c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        }
251c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        final float[] ptsF = new float[pts.length];
252c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        for (int i = 0; i < pts.length; i += 2) {
253c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            ptsF[i] = (float)pts[i] / maxX;
254c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            ptsF[i + 1] = (float)pts[i + 1] / maxY;
255c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        }
256c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        return ptsF;
257c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk    }
258c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk
259abe1974a11364b577e94966ca87047d7889c8edfJason Monk    @Override
260abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public void setBounds(int left, int top, int right, int bottom) {
261abe1974a11364b577e94966ca87047d7889c8edfJason Monk        super.setBounds(left, top, right, bottom);
262abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mHeight = bottom - top;
263abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mWidth = right - left;
264abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mWarningTextPaint.setTextSize(mHeight * 0.75f);
265abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
266abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
267abe1974a11364b577e94966ca87047d7889c8edfJason Monk
268abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private void updateShowPercent() {
269abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShowPercent = 0 != Settings.System.getInt(mContext.getContentResolver(),
270abe1974a11364b577e94966ca87047d7889c8edfJason Monk                SHOW_PERCENT_SETTING, 0);
271abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
272abe1974a11364b577e94966ca87047d7889c8edfJason Monk
273abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int getColorForLevel(int percent) {
274abe1974a11364b577e94966ca87047d7889c8edfJason Monk
275abe1974a11364b577e94966ca87047d7889c8edfJason Monk        // If we are in power save mode, always use the normal color.
276abe1974a11364b577e94966ca87047d7889c8edfJason Monk        if (mPowerSaveEnabled) {
277abe1974a11364b577e94966ca87047d7889c8edfJason Monk            return mColors[mColors.length-1];
278abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
279abe1974a11364b577e94966ca87047d7889c8edfJason Monk        int thresh, color = 0;
280abe1974a11364b577e94966ca87047d7889c8edfJason Monk        for (int i=0; i<mColors.length; i+=2) {
281abe1974a11364b577e94966ca87047d7889c8edfJason Monk            thresh = mColors[i];
282abe1974a11364b577e94966ca87047d7889c8edfJason Monk            color = mColors[i+1];
283abe1974a11364b577e94966ca87047d7889c8edfJason Monk            if (percent <= thresh) {
284abe1974a11364b577e94966ca87047d7889c8edfJason Monk
285abe1974a11364b577e94966ca87047d7889c8edfJason Monk                // Respect tinting for "normal" level
286abe1974a11364b577e94966ca87047d7889c8edfJason Monk                if (i == mColors.length-2) {
287abe1974a11364b577e94966ca87047d7889c8edfJason Monk                    return mIconTint;
288abe1974a11364b577e94966ca87047d7889c8edfJason Monk                } else {
289abe1974a11364b577e94966ca87047d7889c8edfJason Monk                    return color;
290abe1974a11364b577e94966ca87047d7889c8edfJason Monk                }
291abe1974a11364b577e94966ca87047d7889c8edfJason Monk            }
292abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
293abe1974a11364b577e94966ca87047d7889c8edfJason Monk        return color;
294abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
295abe1974a11364b577e94966ca87047d7889c8edfJason Monk
296abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public void setDarkIntensity(float darkIntensity) {
29786905582411c5c77a3e7641589cf206c6e5770f5Jorim Jaggi        if (darkIntensity == mOldDarkIntensity) {
29886905582411c5c77a3e7641589cf206c6e5770f5Jorim Jaggi            return;
29986905582411c5c77a3e7641589cf206c6e5770f5Jorim Jaggi        }
300abe1974a11364b577e94966ca87047d7889c8edfJason Monk        int backgroundColor = getBackgroundColor(darkIntensity);
301abe1974a11364b577e94966ca87047d7889c8edfJason Monk        int fillColor = getFillColor(darkIntensity);
302abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mIconTint = fillColor;
303abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFramePaint.setColor(backgroundColor);
304abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBoltPaint.setColor(fillColor);
305abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mChargeColor = fillColor;
306abe1974a11364b577e94966ca87047d7889c8edfJason Monk        invalidateSelf();
30786905582411c5c77a3e7641589cf206c6e5770f5Jorim Jaggi        mOldDarkIntensity = darkIntensity;
308abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
309abe1974a11364b577e94966ca87047d7889c8edfJason Monk
310abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int getBackgroundColor(float darkIntensity) {
311abe1974a11364b577e94966ca87047d7889c8edfJason Monk        return getColorForDarkIntensity(
312abe1974a11364b577e94966ca87047d7889c8edfJason Monk                darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
313abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
314abe1974a11364b577e94966ca87047d7889c8edfJason Monk
315abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int getFillColor(float darkIntensity) {
316abe1974a11364b577e94966ca87047d7889c8edfJason Monk        return getColorForDarkIntensity(
317abe1974a11364b577e94966ca87047d7889c8edfJason Monk                darkIntensity, mLightModeFillColor, mDarkModeFillColor);
318abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
319abe1974a11364b577e94966ca87047d7889c8edfJason Monk
320abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
321abe1974a11364b577e94966ca87047d7889c8edfJason Monk        return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
322abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
323abe1974a11364b577e94966ca87047d7889c8edfJason Monk
324abe1974a11364b577e94966ca87047d7889c8edfJason Monk    @Override
325abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public void draw(Canvas c) {
326abe1974a11364b577e94966ca87047d7889c8edfJason Monk        final int level = mLevel;
327abe1974a11364b577e94966ca87047d7889c8edfJason Monk
328abe1974a11364b577e94966ca87047d7889c8edfJason Monk        if (level == -1) return;
329abe1974a11364b577e94966ca87047d7889c8edfJason Monk
330abe1974a11364b577e94966ca87047d7889c8edfJason Monk        float drawFrac = (float) level / 100f;
331abe1974a11364b577e94966ca87047d7889c8edfJason Monk        final int height = mHeight;
332abe1974a11364b577e94966ca87047d7889c8edfJason Monk        final int width = (int) (ASPECT_RATIO * mHeight);
333abe1974a11364b577e94966ca87047d7889c8edfJason Monk        int px = (mWidth - width) / 2;
334abe1974a11364b577e94966ca87047d7889c8edfJason Monk
335abe1974a11364b577e94966ca87047d7889c8edfJason Monk        final int buttonHeight = (int) (height * mButtonHeightFraction);
336abe1974a11364b577e94966ca87047d7889c8edfJason Monk
337abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFrame.set(0, 0, width, height);
338abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFrame.offset(px, 0);
339abe1974a11364b577e94966ca87047d7889c8edfJason Monk
340abe1974a11364b577e94966ca87047d7889c8edfJason Monk        // button-frame: area above the battery body
341abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mButtonFrame.set(
342abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mFrame.left + Math.round(width * 0.25f),
343abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mFrame.top,
344abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mFrame.right - Math.round(width * 0.25f),
345abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mFrame.top + buttonHeight);
346abe1974a11364b577e94966ca87047d7889c8edfJason Monk
347abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mButtonFrame.top += mSubpixelSmoothingLeft;
348abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mButtonFrame.left += mSubpixelSmoothingLeft;
349abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mButtonFrame.right -= mSubpixelSmoothingRight;
350abe1974a11364b577e94966ca87047d7889c8edfJason Monk
351abe1974a11364b577e94966ca87047d7889c8edfJason Monk        // frame: battery body area
352abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFrame.top += buttonHeight;
353abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFrame.left += mSubpixelSmoothingLeft;
354abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFrame.top += mSubpixelSmoothingLeft;
355abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFrame.right -= mSubpixelSmoothingRight;
356abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFrame.bottom -= mSubpixelSmoothingRight;
357abe1974a11364b577e94966ca87047d7889c8edfJason Monk
358abe1974a11364b577e94966ca87047d7889c8edfJason Monk        // set the battery charging color
359abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mBatteryPaint.setColor(mPluggedIn ? mChargeColor : getColorForLevel(level));
360abe1974a11364b577e94966ca87047d7889c8edfJason Monk
361abe1974a11364b577e94966ca87047d7889c8edfJason Monk        if (level >= FULL) {
362abe1974a11364b577e94966ca87047d7889c8edfJason Monk            drawFrac = 1f;
363abe1974a11364b577e94966ca87047d7889c8edfJason Monk        } else if (level <= mCriticalLevel) {
364abe1974a11364b577e94966ca87047d7889c8edfJason Monk            drawFrac = 0f;
365abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
366abe1974a11364b577e94966ca87047d7889c8edfJason Monk
367abe1974a11364b577e94966ca87047d7889c8edfJason Monk        final float levelTop = drawFrac == 1f ? mButtonFrame.top
368abe1974a11364b577e94966ca87047d7889c8edfJason Monk                : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
369abe1974a11364b577e94966ca87047d7889c8edfJason Monk
370abe1974a11364b577e94966ca87047d7889c8edfJason Monk        // define the battery shape
371abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.reset();
372abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
373abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
374abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.lineTo(mButtonFrame.right, mFrame.top);
375abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.lineTo(mFrame.right, mFrame.top);
376abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.lineTo(mFrame.right, mFrame.bottom);
377abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.lineTo(mFrame.left, mFrame.bottom);
378abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.lineTo(mFrame.left, mFrame.top);
379abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.lineTo(mButtonFrame.left, mFrame.top);
380abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
381abe1974a11364b577e94966ca87047d7889c8edfJason Monk
382abe1974a11364b577e94966ca87047d7889c8edfJason Monk        if (mPluggedIn) {
383abe1974a11364b577e94966ca87047d7889c8edfJason Monk            // define the bolt shape
384c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            final float bl = mFrame.left + mFrame.width() / 4f;
385abe1974a11364b577e94966ca87047d7889c8edfJason Monk            final float bt = mFrame.top + mFrame.height() / 6f;
386c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            final float br = mFrame.right - mFrame.width() / 4f;
387abe1974a11364b577e94966ca87047d7889c8edfJason Monk            final float bb = mFrame.bottom - mFrame.height() / 10f;
388abe1974a11364b577e94966ca87047d7889c8edfJason Monk            if (mBoltFrame.left != bl || mBoltFrame.top != bt
389abe1974a11364b577e94966ca87047d7889c8edfJason Monk                    || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
390abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mBoltFrame.set(bl, bt, br, bb);
391abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mBoltPath.reset();
392abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mBoltPath.moveTo(
393abe1974a11364b577e94966ca87047d7889c8edfJason Monk                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
394abe1974a11364b577e94966ca87047d7889c8edfJason Monk                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
395abe1974a11364b577e94966ca87047d7889c8edfJason Monk                for (int i = 2; i < mBoltPoints.length; i += 2) {
396abe1974a11364b577e94966ca87047d7889c8edfJason Monk                    mBoltPath.lineTo(
397abe1974a11364b577e94966ca87047d7889c8edfJason Monk                            mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
398abe1974a11364b577e94966ca87047d7889c8edfJason Monk                            mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
399abe1974a11364b577e94966ca87047d7889c8edfJason Monk                }
400abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mBoltPath.lineTo(
401abe1974a11364b577e94966ca87047d7889c8edfJason Monk                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
402abe1974a11364b577e94966ca87047d7889c8edfJason Monk                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
403abe1974a11364b577e94966ca87047d7889c8edfJason Monk            }
404abe1974a11364b577e94966ca87047d7889c8edfJason Monk
405abe1974a11364b577e94966ca87047d7889c8edfJason Monk            float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
406abe1974a11364b577e94966ca87047d7889c8edfJason Monk            boltPct = Math.min(Math.max(boltPct, 0), 1);
407abe1974a11364b577e94966ca87047d7889c8edfJason Monk            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
408abe1974a11364b577e94966ca87047d7889c8edfJason Monk                // draw the bolt if opaque
409abe1974a11364b577e94966ca87047d7889c8edfJason Monk                c.drawPath(mBoltPath, mBoltPaint);
410abe1974a11364b577e94966ca87047d7889c8edfJason Monk            } else {
411abe1974a11364b577e94966ca87047d7889c8edfJason Monk                // otherwise cut the bolt out of the overall shape
412abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
413abe1974a11364b577e94966ca87047d7889c8edfJason Monk            }
414c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        } else if (mPowerSaveEnabled) {
415c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            // define the plus shape
416c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            final float pw = mFrame.width() * 2 / 3;
417c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            final float pl = mFrame.left + (mFrame.width() - pw) / 2;
418c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            final float pt = mFrame.top + (mFrame.height() - pw) / 2;
419c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            final float pr = mFrame.right - (mFrame.width() - pw) / 2;
420c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
421c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            if (mPlusFrame.left != pl || mPlusFrame.top != pt
422c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                    || mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
423c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                mPlusFrame.set(pl, pt, pr, pb);
424c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                mPlusPath.reset();
425c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                mPlusPath.moveTo(
426c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
427c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
428c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                for (int i = 2; i < mPlusPoints.length; i += 2) {
429c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                    mPlusPath.lineTo(
430c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                            mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
431c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                            mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
432c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                }
433c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                mPlusPath.lineTo(
434c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
435c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
436c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            }
437c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk
438c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
439c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            boltPct = Math.min(Math.max(boltPct, 0), 1);
440c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
441c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                // draw the bolt if opaque
442c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                c.drawPath(mPlusPath, mPlusPaint);
443c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            } else {
444c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                // otherwise cut the bolt out of the overall shape
445c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk                mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
446c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            }
447abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
448abe1974a11364b577e94966ca87047d7889c8edfJason Monk
449abe1974a11364b577e94966ca87047d7889c8edfJason Monk        // compute percentage text
450abe1974a11364b577e94966ca87047d7889c8edfJason Monk        boolean pctOpaque = false;
451abe1974a11364b577e94966ca87047d7889c8edfJason Monk        float pctX = 0, pctY = 0;
452abe1974a11364b577e94966ca87047d7889c8edfJason Monk        String pctText = null;
45349573e9c89a279397288d5139deadb5ec27c9821Jason Monk        if (!mPluggedIn && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
454abe1974a11364b577e94966ca87047d7889c8edfJason Monk            mTextPaint.setColor(getColorForLevel(level));
455abe1974a11364b577e94966ca87047d7889c8edfJason Monk            mTextPaint.setTextSize(height *
456abe1974a11364b577e94966ca87047d7889c8edfJason Monk                    (SINGLE_DIGIT_PERCENT ? 0.75f
457abe1974a11364b577e94966ca87047d7889c8edfJason Monk                            : (mLevel == 100 ? 0.38f : 0.5f)));
458abe1974a11364b577e94966ca87047d7889c8edfJason Monk            mTextHeight = -mTextPaint.getFontMetrics().ascent;
459abe1974a11364b577e94966ca87047d7889c8edfJason Monk            pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
460abe1974a11364b577e94966ca87047d7889c8edfJason Monk            pctX = mWidth * 0.5f;
461abe1974a11364b577e94966ca87047d7889c8edfJason Monk            pctY = (mHeight + mTextHeight) * 0.47f;
462abe1974a11364b577e94966ca87047d7889c8edfJason Monk            pctOpaque = levelTop > pctY;
463abe1974a11364b577e94966ca87047d7889c8edfJason Monk            if (!pctOpaque) {
464abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mTextPath.reset();
465abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
466abe1974a11364b577e94966ca87047d7889c8edfJason Monk                // cut the percentage text out of the overall shape
467abe1974a11364b577e94966ca87047d7889c8edfJason Monk                mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
468abe1974a11364b577e94966ca87047d7889c8edfJason Monk            }
469abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
470abe1974a11364b577e94966ca87047d7889c8edfJason Monk
471abe1974a11364b577e94966ca87047d7889c8edfJason Monk        // draw the battery shape background
472abe1974a11364b577e94966ca87047d7889c8edfJason Monk        c.drawPath(mShapePath, mFramePaint);
473abe1974a11364b577e94966ca87047d7889c8edfJason Monk
474abe1974a11364b577e94966ca87047d7889c8edfJason Monk        // draw the battery shape, clipped to charging level
475abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mFrame.top = levelTop;
476abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mClipPath.reset();
477abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mClipPath.addRect(mFrame,  Path.Direction.CCW);
478abe1974a11364b577e94966ca87047d7889c8edfJason Monk        mShapePath.op(mClipPath, Path.Op.INTERSECT);
479abe1974a11364b577e94966ca87047d7889c8edfJason Monk        c.drawPath(mShapePath, mBatteryPaint);
480abe1974a11364b577e94966ca87047d7889c8edfJason Monk
48149573e9c89a279397288d5139deadb5ec27c9821Jason Monk        if (!mPluggedIn && !mPowerSaveEnabled) {
482abe1974a11364b577e94966ca87047d7889c8edfJason Monk            if (level <= mCriticalLevel) {
483abe1974a11364b577e94966ca87047d7889c8edfJason Monk                // draw the warning text
484abe1974a11364b577e94966ca87047d7889c8edfJason Monk                final float x = mWidth * 0.5f;
485abe1974a11364b577e94966ca87047d7889c8edfJason Monk                final float y = (mHeight + mWarningTextHeight) * 0.48f;
486abe1974a11364b577e94966ca87047d7889c8edfJason Monk                c.drawText(mWarningString, x, y, mWarningTextPaint);
487abe1974a11364b577e94966ca87047d7889c8edfJason Monk            } else if (pctOpaque) {
488abe1974a11364b577e94966ca87047d7889c8edfJason Monk                // draw the percentage text
489abe1974a11364b577e94966ca87047d7889c8edfJason Monk                c.drawText(pctText, pctX, pctY, mTextPaint);
490abe1974a11364b577e94966ca87047d7889c8edfJason Monk            }
491abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
492abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
493abe1974a11364b577e94966ca87047d7889c8edfJason Monk
494abe1974a11364b577e94966ca87047d7889c8edfJason Monk    // Some stuff required by Drawable.
495abe1974a11364b577e94966ca87047d7889c8edfJason Monk    @Override
496abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public void setAlpha(int alpha) {
497abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
498abe1974a11364b577e94966ca87047d7889c8edfJason Monk
499abe1974a11364b577e94966ca87047d7889c8edfJason Monk    @Override
500abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public void setColorFilter(@Nullable ColorFilter colorFilter) {
501abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
502abe1974a11364b577e94966ca87047d7889c8edfJason Monk
503abe1974a11364b577e94966ca87047d7889c8edfJason Monk    @Override
504abe1974a11364b577e94966ca87047d7889c8edfJason Monk    public int getOpacity() {
505abe1974a11364b577e94966ca87047d7889c8edfJason Monk        return 0;
506abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
507abe1974a11364b577e94966ca87047d7889c8edfJason Monk
508abe1974a11364b577e94966ca87047d7889c8edfJason Monk    private final class SettingObserver extends ContentObserver {
509abe1974a11364b577e94966ca87047d7889c8edfJason Monk        public SettingObserver() {
510abe1974a11364b577e94966ca87047d7889c8edfJason Monk            super(new Handler());
511abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
512abe1974a11364b577e94966ca87047d7889c8edfJason Monk
513abe1974a11364b577e94966ca87047d7889c8edfJason Monk        @Override
514abe1974a11364b577e94966ca87047d7889c8edfJason Monk        public void onChange(boolean selfChange, Uri uri) {
515abe1974a11364b577e94966ca87047d7889c8edfJason Monk            super.onChange(selfChange, uri);
516abe1974a11364b577e94966ca87047d7889c8edfJason Monk            updateShowPercent();
517abe1974a11364b577e94966ca87047d7889c8edfJason Monk            postInvalidate();
518abe1974a11364b577e94966ca87047d7889c8edfJason Monk        }
519abe1974a11364b577e94966ca87047d7889c8edfJason Monk    }
520abe1974a11364b577e94966ca87047d7889c8edfJason Monk
521abe1974a11364b577e94966ca87047d7889c8edfJason Monk}
522