1597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei/*
2597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei * Copyright (C) 2017 The Android Open Source Project
3597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei *
4597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei * Licensed under the Apache License, Version 2.0 (the "License");
5597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei * you may not use this file except in compliance with the License.
6597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei * You may obtain a copy of the License at
7597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei *
8597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei *      http://www.apache.org/licenses/LICENSE-2.0
9597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei *
10597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei * Unless required by applicable law or agreed to in writing, software
11597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei * distributed under the License is distributed on an "AS IS" BASIS,
12597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei * See the License for the specific language governing permissions and
14597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei * limitations under the License.
15597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei */
16597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
17597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleipackage com.android.settingslib.graph;
18597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
19597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.annotation.Nullable;
20597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.content.Context;
21597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.content.res.Resources;
22597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.content.res.TypedArray;
23597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.graphics.Canvas;
24597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.graphics.Color;
25597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.graphics.ColorFilter;
26597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.graphics.Paint;
27d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Lairdimport android.graphics.Paint.Style;
28597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.graphics.Path;
296a600b8f628ddfbcaddc8dc281684b8edf294005Jason Monkimport android.graphics.Path.Direction;
306a600b8f628ddfbcaddc8dc281684b8edf294005Jason Monkimport android.graphics.Path.FillType;
31d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Lairdimport android.graphics.Path.Op;
326f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Lairdimport android.graphics.Rect;
33597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.graphics.RectF;
34597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.graphics.Typeface;
35597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport android.graphics.drawable.Drawable;
3658be7a675b7aa505255f0c91fee755f8290e8363Jason Monkimport android.util.TypedValue;
3758be7a675b7aa505255f0c91fee755f8290e8363Jason Monk
38597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport com.android.settingslib.R;
39597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleiimport com.android.settingslib.Utils;
40597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
41597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyuleipublic class BatteryMeterDrawableBase extends Drawable {
42597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
436a600b8f628ddfbcaddc8dc281684b8edf294005Jason Monk    private static final float ASPECT_RATIO = .58f;
44597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    public static final String TAG = BatteryMeterDrawableBase.class.getSimpleName();
45706d9684afb4d46541521d290aa99c08531a5f4cEvan Laird    private static final float RADIUS_RATIO = 1.0f / 17f;
46597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
47597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    protected final Context mContext;
48ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    protected final Paint mFramePaint;
49ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    protected final Paint mBatteryPaint;
50ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    protected final Paint mWarningTextPaint;
51ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    protected final Paint mTextPaint;
52ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    protected final Paint mBoltPaint;
53ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    protected final Paint mPlusPaint;
54d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird    protected final Paint mPowersavePaint;
55d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei    protected float mButtonHeightFraction;
56597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
576aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    private int mLevel = -1;
58ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    private boolean mCharging;
596aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    private boolean mPowerSaveEnabled;
6081905164906b49ac4c5d84761088e9164fd9877cEvan Laird    protected boolean mPowerSaveAsColorError = true;
616aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    private boolean mShowPercent;
62597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
63597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private static final boolean SINGLE_DIGIT_PERCENT = false;
64597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
65597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private static final int FULL = 96;
66597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
67597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private static final float BOLT_LEVEL_THRESHOLD = 0.3f;  // opaque bolt below this fraction
68597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
69597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final int[] mColors;
70597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final int mIntrinsicWidth;
71597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final int mIntrinsicHeight;
72597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
73597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private float mSubpixelSmoothingLeft;
74597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private float mSubpixelSmoothingRight;
75597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private float mTextHeight, mWarningTextHeight;
76597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private int mIconTint = Color.WHITE;
77d866b8aa0341e960399c425b021b4a6aedfa5b9eJason Monk    private float mOldDarkIntensity = -1f;
78597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
79597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private int mHeight;
80597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private int mWidth;
81597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private String mWarningString;
82597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final int mCriticalLevel;
83597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private int mChargeColor;
84597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final float[] mBoltPoints;
85597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final Path mBoltPath = new Path();
86597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final float[] mPlusPoints;
87597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final Path mPlusPath = new Path();
88597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
896f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird    private final Rect mPadding = new Rect();
90597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final RectF mFrame = new RectF();
91597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final RectF mButtonFrame = new RectF();
92597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final RectF mBoltFrame = new RectF();
93597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final RectF mPlusFrame = new RectF();
94597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
95597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final Path mShapePath = new Path();
96d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird    private final Path mOutlinePath = new Path();
97597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private final Path mTextPath = new Path();
98597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
99597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    public BatteryMeterDrawableBase(Context context, int frameColor) {
100597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mContext = context;
101597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        final Resources res = context.getResources();
102597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
103597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
104597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
105597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        final int N = levels.length();
106597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mColors = new int[2 * N];
107af68d729738a028da585ddf0f82128fee7587d79jackqdyulei        for (int i = 0; i < N; i++) {
108597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            mColors[2 * i] = levels.getInt(i, 0);
10958be7a675b7aa505255f0c91fee755f8290e8363Jason Monk            if (colors.getType(i) == TypedValue.TYPE_ATTRIBUTE) {
1107c8564e6adb259ddf8c5626c8f59079e2e32cb79Jason Monk                mColors[2 * i + 1] = Utils.getColorAttr(context, colors.getThemeAttributeId(i, 0));
11158be7a675b7aa505255f0c91fee755f8290e8363Jason Monk            } else {
11258be7a675b7aa505255f0c91fee755f8290e8363Jason Monk                mColors[2 * i + 1] = colors.getColor(i, 0);
11358be7a675b7aa505255f0c91fee755f8290e8363Jason Monk            }
114597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        }
115597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        levels.recycle();
116597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        colors.recycle();
1176aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler
118597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
119597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mCriticalLevel = mContext.getResources().getInteger(
120597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                com.android.internal.R.integer.config_criticalBatteryWarningLevel);
121597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mButtonHeightFraction = context.getResources().getFraction(
122597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                R.fraction.battery_button_height_fraction, 1, 1);
123597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mSubpixelSmoothingLeft = context.getResources().getFraction(
124597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                R.fraction.battery_subpixel_smoothing_left, 1, 1);
125597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mSubpixelSmoothingRight = context.getResources().getFraction(
126597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                R.fraction.battery_subpixel_smoothing_right, 1, 1);
127597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
128597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
129597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mFramePaint.setColor(frameColor);
130597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mFramePaint.setDither(true);
131597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mFramePaint.setStrokeWidth(0);
132597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
133597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
134597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
135597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mBatteryPaint.setDither(true);
136597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mBatteryPaint.setStrokeWidth(0);
137597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
138597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
139597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
140597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
141597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mTextPaint.setTypeface(font);
142597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mTextPaint.setTextAlign(Paint.Align.CENTER);
143597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
144597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
145597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        font = Typeface.create("sans-serif", Typeface.BOLD);
146597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mWarningTextPaint.setTypeface(font);
147597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
148597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        if (mColors.length > 1) {
149597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            mWarningTextPaint.setColor(mColors[1]);
150597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        }
151597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
1528af93cb2403372eaee0e705aec409d09227cb5edDaniel Nishi        mChargeColor = Utils.getDefaultColor(mContext, R.color.meter_consumed_color);
153597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
154597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
155597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mBoltPaint.setColor(Utils.getDefaultColor(mContext, R.color.batterymeter_bolt_color));
1566aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        mBoltPoints = loadPoints(res, R.array.batterymeter_bolt_points);
157597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
1589eb4610db728a051b6725d7efb76790e9e1f3520Evan Laird        mPlusPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
1599eb4610db728a051b6725d7efb76790e9e1f3520Evan Laird        mPlusPaint.setColor(Utils.getDefaultColor(mContext, R.color.batterymeter_plus_color));
1606aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        mPlusPoints = loadPoints(res, R.array.batterymeter_plus_points);
161597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
162d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        mPowersavePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
163d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        mPowersavePaint.setColor(mPlusPaint.getColor());
164d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        mPowersavePaint.setStyle(Style.STROKE);
165d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        mPowersavePaint.setStrokeWidth(context.getResources()
166d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird                .getDimensionPixelSize(R.dimen.battery_powersave_outline_thickness));
167d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird
168597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
169597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
170597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
171597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
172597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    @Override
173597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    public int getIntrinsicHeight() {
174597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        return mIntrinsicHeight;
175597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
176597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
177597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    @Override
178597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    public int getIntrinsicWidth() {
179597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        return mIntrinsicWidth;
180597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
181597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
1826aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    public void setShowPercent(boolean show) {
1836aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        mShowPercent = show;
184597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        postInvalidate();
185597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
186597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
187ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    public void setCharging(boolean val) {
188ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei        mCharging = val;
1896aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        postInvalidate();
190597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
191597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
192ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    public boolean getCharging() {
193ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei        return mCharging;
194ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    }
195ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei
1966aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    public void setBatteryLevel(int val) {
1976aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        mLevel = val;
1986aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        postInvalidate();
1996aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    }
2006aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler
201ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    public int getBatteryLevel() {
202ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei        return mLevel;
203ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    }
204ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei
2056aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    public void setPowerSave(boolean val) {
2066aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        mPowerSaveEnabled = val;
2076aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        postInvalidate();
208597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
209597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
2109eb4610db728a051b6725d7efb76790e9e1f3520Evan Laird    protected void setPowerSaveAsColorError(boolean asError) {
2119eb4610db728a051b6725d7efb76790e9e1f3520Evan Laird        mPowerSaveAsColorError = asError;
2129eb4610db728a051b6725d7efb76790e9e1f3520Evan Laird    }
2139eb4610db728a051b6725d7efb76790e9e1f3520Evan Laird
2146aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    // an approximation of View.postInvalidate()
2156aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    protected void postInvalidate() {
2166aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        unscheduleSelf(this::invalidateSelf);
2176aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        scheduleSelf(this::invalidateSelf, 0);
2186aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    }
2196aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler
2206aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler    private static float[] loadPoints(Resources res, int pointArrayRes) {
2216aa6e6e640ddaea3272144aee68762dd17674773Dan Sandler        final int[] pts = res.getIntArray(pointArrayRes);
222597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        int maxX = 0, maxY = 0;
223597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        for (int i = 0; i < pts.length; i += 2) {
224597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            maxX = Math.max(maxX, pts[i]);
225597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            maxY = Math.max(maxY, pts[i + 1]);
226597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        }
227597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        final float[] ptsF = new float[pts.length];
228597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        for (int i = 0; i < pts.length; i += 2) {
229597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            ptsF[i] = (float) pts[i] / maxX;
230597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            ptsF[i + 1] = (float) pts[i + 1] / maxY;
231597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        }
232597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        return ptsF;
233597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
234597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
235597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    @Override
236597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    public void setBounds(int left, int top, int right, int bottom) {
237597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        super.setBounds(left, top, right, bottom);
2386f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        updateSize();
2396f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird    }
2406f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird
2416f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird    private void updateSize() {
2426f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        final Rect bounds = getBounds();
2436f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird
2446f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        mHeight = (bounds.bottom - mPadding.bottom) - (bounds.top + mPadding.top);
2456f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        mWidth = (bounds.right - mPadding.right) - (bounds.left + mPadding.left);
246597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mWarningTextPaint.setTextSize(mHeight * 0.75f);
247597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
248597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
249597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
2506f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird    @Override
2516f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird    public boolean getPadding(Rect padding) {
2526f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        if (mPadding.left == 0
2536f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird            && mPadding.top == 0
2546f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird            && mPadding.right == 0
2556f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird            && mPadding.bottom == 0) {
2566f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird            return super.getPadding(padding);
2576f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        }
2586f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird
2596f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        padding.set(mPadding);
2606f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        return true;
2616f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird    }
2626f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird
2636f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird    public void setPadding(int left, int top, int right, int bottom) {
2646f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        mPadding.left = left;
2656f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        mPadding.top = top;
2666f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        mPadding.right = right;
2676f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        mPadding.bottom = bottom;
2686f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird
2696f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        updateSize();
2706f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird    }
2716f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird
272597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    private int getColorForLevel(int percent) {
273597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        int thresh, color = 0;
274597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        for (int i = 0; i < mColors.length; i += 2) {
275597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            thresh = mColors[i];
276597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            color = mColors[i + 1];
277597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            if (percent <= thresh) {
278597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
279597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                // Respect tinting for "normal" level
280597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                if (i == mColors.length - 2) {
281597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                    return mIconTint;
282597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                } else {
283597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                    return color;
284597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                }
285597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            }
286597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        }
287597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        return color;
288597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
289597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
290597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    public void setColors(int fillColor, int backgroundColor) {
291597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mIconTint = fillColor;
292597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mFramePaint.setColor(backgroundColor);
293597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mBoltPaint.setColor(fillColor);
294597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mChargeColor = fillColor;
295597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        invalidateSelf();
296597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
297597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
2986f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird    protected int batteryColorForLevel(int level) {
299d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        return (mCharging || (mPowerSaveEnabled && mPowerSaveAsColorError))
300d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird                ? mChargeColor
301d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird                : getColorForLevel(level);
3026f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird    }
3036f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird
304597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    @Override
305597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    public void draw(Canvas c) {
306597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        final int level = mLevel;
30798b7fdbd5c11af30afdf147d0c4cc44fe4ef240ajackqdyulei        final Rect bounds = getBounds();
308597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
309597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        if (level == -1) return;
310597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
311597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        float drawFrac = (float) level / 100f;
312597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        final int height = mHeight;
313d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei        final int width = (int) (getAspectRatio() * mHeight);
3146f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        final int px = (mWidth - width) / 2;
3156a600b8f628ddfbcaddc8dc281684b8edf294005Jason Monk        final int buttonHeight = Math.round(height * mButtonHeightFraction);
31698b7fdbd5c11af30afdf147d0c4cc44fe4ef240ajackqdyulei        final int left = mPadding.left + bounds.left;
31798b7fdbd5c11af30afdf147d0c4cc44fe4ef240ajackqdyulei        final int top = bounds.bottom - mPadding.bottom - height;
318597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
31998b7fdbd5c11af30afdf147d0c4cc44fe4ef240ajackqdyulei        mFrame.set(left, top, width + left, height + top);
320597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mFrame.offset(px, 0);
321597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
322597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        // button-frame: area above the battery body
323597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mButtonFrame.set(
324706d9684afb4d46541521d290aa99c08531a5f4cEvan Laird                mFrame.left + Math.round(width * 0.28f),
325597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mFrame.top,
326706d9684afb4d46541521d290aa99c08531a5f4cEvan Laird                mFrame.right - Math.round(width * 0.28f),
327597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mFrame.top + buttonHeight);
328597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
329597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        // frame: battery body area
330597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mFrame.top += buttonHeight;
331597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
332597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        // set the battery charging color
3336f4179c3b8788456095ec79fd35e7c1a3d0589a0Evan Laird        mBatteryPaint.setColor(batteryColorForLevel(level));
334597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
335597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        if (level >= FULL) {
336597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            drawFrac = 1f;
337597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        } else if (level <= mCriticalLevel) {
338597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            drawFrac = 0f;
339597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        }
340597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
341597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        final float levelTop = drawFrac == 1f ? mButtonFrame.top
342597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
343597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
344597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        // define the battery shape
345597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mShapePath.reset();
346d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        mOutlinePath.reset();
347d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei        final float radius = getRadiusRatio() * (mFrame.height() + buttonHeight);
3486a600b8f628ddfbcaddc8dc281684b8edf294005Jason Monk        mShapePath.setFillType(FillType.WINDING);
3496a600b8f628ddfbcaddc8dc281684b8edf294005Jason Monk        mShapePath.addRoundRect(mFrame, radius, radius, Direction.CW);
3506a600b8f628ddfbcaddc8dc281684b8edf294005Jason Monk        mShapePath.addRect(mButtonFrame, Direction.CW);
351d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        mOutlinePath.addRoundRect(mFrame, radius, radius, Direction.CW);
352d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        Path p = new Path();
353d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        p.addRect(mButtonFrame, Direction.CW);
354d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        mOutlinePath.op(p, Op.XOR);
355597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
356ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei        if (mCharging) {
357597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            // define the bolt shape
358706d9684afb4d46541521d290aa99c08531a5f4cEvan Laird            // Shift right by 1px for maximal bolt-goodness
359706d9684afb4d46541521d290aa99c08531a5f4cEvan Laird            final float bl = mFrame.left + mFrame.width() / 4f + 1;
360597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            final float bt = mFrame.top + mFrame.height() / 6f;
361706d9684afb4d46541521d290aa99c08531a5f4cEvan Laird            final float br = mFrame.right - mFrame.width() / 4f + 1;
362597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            final float bb = mFrame.bottom - mFrame.height() / 10f;
363597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            if (mBoltFrame.left != bl || mBoltFrame.top != bt
364597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                    || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
365597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mBoltFrame.set(bl, bt, br, bb);
366597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mBoltPath.reset();
367597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mBoltPath.moveTo(
368597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
369597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
370597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                for (int i = 2; i < mBoltPoints.length; i += 2) {
371597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                    mBoltPath.lineTo(
372597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                            mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
373597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                            mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
374597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                }
375597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mBoltPath.lineTo(
376597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
377597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
378597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            }
379597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
380597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
381597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            boltPct = Math.min(Math.max(boltPct, 0), 1);
382597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
383597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                // draw the bolt if opaque
384597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                c.drawPath(mBoltPath, mBoltPaint);
385597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            } else {
386597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                // otherwise cut the bolt out of the overall shape
387597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
388597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            }
389597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        } else if (mPowerSaveEnabled) {
390597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            // define the plus shape
391597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            final float pw = mFrame.width() * 2 / 3;
392597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            final float pl = mFrame.left + (mFrame.width() - pw) / 2;
393597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            final float pt = mFrame.top + (mFrame.height() - pw) / 2;
394597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            final float pr = mFrame.right - (mFrame.width() - pw) / 2;
395597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
396597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            if (mPlusFrame.left != pl || mPlusFrame.top != pt
397597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                    || mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
398597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mPlusFrame.set(pl, pt, pr, pb);
399597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mPlusPath.reset();
400597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mPlusPath.moveTo(
401597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
402597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
403597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                for (int i = 2; i < mPlusPoints.length; i += 2) {
404597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                    mPlusPath.lineTo(
405597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                            mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
406597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                            mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
407597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                }
408597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mPlusPath.lineTo(
409597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
410597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
411597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            }
412597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
4136596266aa4503d63d64f2102a1acb03a346dc90bEvan Laird            // Always cut out of the whole shape, and sometimes filled colorError
4146596266aa4503d63d64f2102a1acb03a346dc90bEvan Laird            mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
4156596266aa4503d63d64f2102a1acb03a346dc90bEvan Laird            if (mPowerSaveAsColorError) {
416597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                c.drawPath(mPlusPath, mPlusPaint);
417597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            }
418597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        }
419597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
420597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        // compute percentage text
421597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        boolean pctOpaque = false;
422597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        float pctX = 0, pctY = 0;
423597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        String pctText = null;
424ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei        if (!mCharging && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
425597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            mTextPaint.setColor(getColorForLevel(level));
426597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            mTextPaint.setTextSize(height *
427597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                    (SINGLE_DIGIT_PERCENT ? 0.75f
428597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                            : (mLevel == 100 ? 0.38f : 0.5f)));
429597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            mTextHeight = -mTextPaint.getFontMetrics().ascent;
430597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level / 10) : level);
4315466c8f22aecb61e7b520997198878830cd103bbjackqdyulei            pctX = mWidth * 0.5f + left;
4325466c8f22aecb61e7b520997198878830cd103bbjackqdyulei            pctY = (mHeight + mTextHeight) * 0.47f + top;
433597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            pctOpaque = levelTop > pctY;
434597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            if (!pctOpaque) {
435597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mTextPath.reset();
436597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
437597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                // cut the percentage text out of the overall shape
438597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
439597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            }
440597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        }
441597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
442597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        // draw the battery shape background
443597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        c.drawPath(mShapePath, mFramePaint);
444597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
445597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        // draw the battery shape, clipped to charging level
446597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mFrame.top = levelTop;
447003db4e4d1c8a11b65d5b44f8bf5851294047911Derek Sollenberger        c.save();
448003db4e4d1c8a11b65d5b44f8bf5851294047911Derek Sollenberger        c.clipRect(mFrame);
449597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        c.drawPath(mShapePath, mBatteryPaint);
450003db4e4d1c8a11b65d5b44f8bf5851294047911Derek Sollenberger        c.restore();
451597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
452ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei        if (!mCharging && !mPowerSaveEnabled) {
453597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            if (level <= mCriticalLevel) {
454597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                // draw the warning text
4555466c8f22aecb61e7b520997198878830cd103bbjackqdyulei                final float x = mWidth * 0.5f + left;
4565466c8f22aecb61e7b520997198878830cd103bbjackqdyulei                final float y = (mHeight + mWarningTextHeight) * 0.48f + top;
457597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                c.drawText(mWarningString, x, y, mWarningTextPaint);
458597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            } else if (pctOpaque) {
459597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                // draw the percentage text
460597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei                c.drawText(pctText, pctX, pctY, mTextPaint);
461597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei            }
462597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        }
463d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird
464d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        // Draw the powersave outline last
465d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        if (!mCharging && mPowerSaveEnabled && mPowerSaveAsColorError) {
466d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird            c.drawPath(mOutlinePath, mPowersavePaint);
467d783c8af01098a36a36bfa4f8c5fed370cfb3654Evan Laird        }
468597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
469597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
470597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    // Some stuff required by Drawable.
471597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    @Override
472597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    public void setAlpha(int alpha) {
473597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
474597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
475597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    @Override
476597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    public void setColorFilter(@Nullable ColorFilter colorFilter) {
477597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mFramePaint.setColorFilter(colorFilter);
478597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mBatteryPaint.setColorFilter(colorFilter);
479597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mWarningTextPaint.setColorFilter(colorFilter);
480597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mBoltPaint.setColorFilter(colorFilter);
481597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        mPlusPaint.setColorFilter(colorFilter);
482597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
483597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei
484597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    @Override
485597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    public int getOpacity() {
486597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei        return 0;
487597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei    }
488ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei
489ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    public int getCriticalLevel() {
490ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei        return mCriticalLevel;
491ff5bd948b0b5fc2122b4fe9dafe5245a2c05694cjackqdyulei    }
492d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei
493d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei    protected float getAspectRatio() {
494d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei        return ASPECT_RATIO;
495d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei    }
496d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei
497d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei    protected float getRadiusRatio() {
498d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei        return RADIUS_RATIO;
499d94a9388e81a395f74a91dfa2997c35d7c6df574jackqdyulei    }
500597b10f6db2401f7685191f96e3aaedcbccc56b0jackqdyulei}
501