--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/colorForeground" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.24" android:color="?android:attr/colorBackground" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.47" android:color="?android:attr/colorBackground" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/colorForeground" />
+</selector>
\ No newline at end of file
<item>7</item>
</integer-array>
+ <!-- BatteryMeterView parameters -->
+ <array name="batterymeter_color_levels">
+ <item>15</item>
+ <item>100</item>
+ </array>
+ <array name="batterymeter_color_values">
+ <item>@*android:color/battery_saver_mode_color</item>
+ <item>@android:color/white</item>
+ </array>
+ <array name="batterymeter_bolt_points">
+ <item>73</item> <item>0</item>
+ <item>392</item><item>0</item>
+ <item>201</item><item>259</item>
+ <item>442</item><item>259</item>
+ <item>4</item> <item>703</item>
+ <item>157</item><item>334</item>
+ <item>0</item> <item>334</item>
+ </array>
+ <array name="batterymeter_plus_points">
+ <item>3</item><item>0</item>
+ <item>5</item><item>0</item>
+ <item>5</item><item>3</item>
+ <item>8</item><item>3</item>
+ <item>8</item><item>5</item>
+ <item>5</item><item>5</item>
+ <item>5</item><item>8</item>
+ <item>3</item><item>8</item>
+ <item>3</item><item>5</item>
+ <item>0</item><item>5</item>
+ <item>0</item><item>3</item>
+ <item>3</item><item>3</item>
+ </array>
+
</resources>
<dimen name="drawer_width">300dp</dimen>
<dimen name="drawer_item_top_bottom_margin">4dp</dimen>
<dimen name="drawer_spacer_height">32dp</dimen>
+
+ <dimen name="battery_height">48dp</dimen>
+ <dimen name="battery_width">38dp</dimen>
+
+ <!-- Margin on the right side of the system icon group on Keyguard. -->
+ <fraction name="battery_button_height_fraction">10.5%</fraction>
+
+ <!-- Fraction value to smooth the edges of the battery icon. The path will be inset by this
+ fraction of a pixel.-->
+ <fraction name="battery_subpixel_smoothing_left">0%</fraction>
+ <fraction name="battery_subpixel_smoothing_right">0%</fraction>
</resources>
<string name="retail_demo_reset_next">Next</string>
<!-- Title for carrier demo mode factory reset confirmation dialog. [CHAR LIMIT=40] -->
<string name="retail_demo_reset_title">Password required</string>
+
+ <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
+ <string name="battery_meter_very_low_overlay_symbol">!</string>
</resources>
--- /dev/null
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.graph;
+
+import android.animation.ArgbEvaluator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.provider.Settings;
+import com.android.settingslib.R;
+import com.android.settingslib.Utils;
+
+public class BatteryMeterDrawableBase extends Drawable {
+
+ private static final float ASPECT_RATIO = 9.5f / 14.5f;
+ public static final String TAG = BatteryMeterDrawableBase.class.getSimpleName();
+ public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
+
+ protected final Context mContext;
+
+ protected int mLevel = -1;
+ protected boolean mPluggedIn;
+ protected boolean mPowerSaveEnabled;
+ protected boolean mShowPercent;
+
+ private static final boolean SINGLE_DIGIT_PERCENT = false;
+
+ private static final int FULL = 96;
+
+ private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction
+
+ private final int[] mColors;
+ private final int mIntrinsicWidth;
+ private final int mIntrinsicHeight;
+
+ private float mButtonHeightFraction;
+ private float mSubpixelSmoothingLeft;
+ private float mSubpixelSmoothingRight;
+ private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint,
+ mPlusPaint;
+ private float mTextHeight, mWarningTextHeight;
+ private int mIconTint = Color.WHITE;
+ private float mOldDarkIntensity = 0f;
+
+ private int mHeight;
+ private int mWidth;
+ private String mWarningString;
+ private final int mCriticalLevel;
+ private int mChargeColor;
+ private final float[] mBoltPoints;
+ private final Path mBoltPath = new Path();
+ private final float[] mPlusPoints;
+ private final Path mPlusPath = new Path();
+
+ private final RectF mFrame = new RectF();
+ private final RectF mButtonFrame = new RectF();
+ private final RectF mBoltFrame = new RectF();
+ private final RectF mPlusFrame = new RectF();
+
+ private final Path mShapePath = new Path();
+ private final Path mClipPath = new Path();
+ private final Path mTextPath = new Path();
+
+ private int mDarkModeBackgroundColor;
+ private int mDarkModeFillColor;
+
+ private int mLightModeBackgroundColor;
+ private int mLightModeFillColor;
+
+ public BatteryMeterDrawableBase(Context context, int frameColor) {
+ mContext = context;
+ final Resources res = context.getResources();
+ TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
+ TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
+
+ final int N = levels.length();
+ mColors = new int[2 * N];
+ for (int i = 0; i < N; i++) {
+ mColors[2 * i] = levels.getInt(i, 0);
+ mColors[2 * i + 1] = colors.getColor(i, 0);
+ }
+ levels.recycle();
+ colors.recycle();
+ updateShowPercent();
+ mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
+ mCriticalLevel = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+ mButtonHeightFraction = context.getResources().getFraction(
+ R.fraction.battery_button_height_fraction, 1, 1);
+ mSubpixelSmoothingLeft = context.getResources().getFraction(
+ R.fraction.battery_subpixel_smoothing_left, 1, 1);
+ mSubpixelSmoothingRight = context.getResources().getFraction(
+ R.fraction.battery_subpixel_smoothing_right, 1, 1);
+
+ mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mFramePaint.setColor(frameColor);
+ mFramePaint.setDither(true);
+ mFramePaint.setStrokeWidth(0);
+ mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBatteryPaint.setDither(true);
+ mBatteryPaint.setStrokeWidth(0);
+ mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
+ mTextPaint.setTypeface(font);
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+
+ mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ font = Typeface.create("sans-serif", Typeface.BOLD);
+ mWarningTextPaint.setTypeface(font);
+ mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
+ if (mColors.length > 1) {
+ mWarningTextPaint.setColor(mColors[1]);
+ }
+
+ mChargeColor = Utils.getDefaultColor(mContext, R.color.batterymeter_charge_color);
+
+ mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBoltPaint.setColor(Utils.getDefaultColor(mContext, R.color.batterymeter_bolt_color));
+ mBoltPoints = loadBoltPoints(res);
+
+ mPlusPaint = new Paint(mBoltPaint);
+ mPlusPoints = loadPlusPoints(res);
+
+ mDarkModeBackgroundColor =
+ Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_background);
+ mDarkModeFillColor =
+ Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_fill);
+ mLightModeBackgroundColor =
+ Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_background);
+ mLightModeFillColor =
+ Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_fill);
+
+ mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
+ mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mIntrinsicHeight;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mIntrinsicWidth;
+ }
+
+ public void disableShowPercent() {
+ mShowPercent = false;
+ postInvalidate();
+ }
+
+ protected void postInvalidate() {
+ scheduleSelf(this::invalidateSelf, 0);
+ }
+
+ private static float[] loadBoltPoints(Resources res) {
+ final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
+ int maxX = 0, maxY = 0;
+ for (int i = 0; i < pts.length; i += 2) {
+ maxX = Math.max(maxX, pts[i]);
+ maxY = Math.max(maxY, pts[i + 1]);
+ }
+ final float[] ptsF = new float[pts.length];
+ for (int i = 0; i < pts.length; i += 2) {
+ ptsF[i] = (float) pts[i] / maxX;
+ ptsF[i + 1] = (float) pts[i + 1] / maxY;
+ }
+ return ptsF;
+ }
+
+ private static float[] loadPlusPoints(Resources res) {
+ final int[] pts = res.getIntArray(R.array.batterymeter_plus_points);
+ int maxX = 0, maxY = 0;
+ for (int i = 0; i < pts.length; i += 2) {
+ maxX = Math.max(maxX, pts[i]);
+ maxY = Math.max(maxY, pts[i + 1]);
+ }
+ final float[] ptsF = new float[pts.length];
+ for (int i = 0; i < pts.length; i += 2) {
+ ptsF[i] = (float) pts[i] / maxX;
+ ptsF[i + 1] = (float) pts[i + 1] / maxY;
+ }
+ return ptsF;
+ }
+
+ @Override
+ public void setBounds(int left, int top, int right, int bottom) {
+ super.setBounds(left, top, right, bottom);
+ mHeight = bottom - top;
+ mWidth = right - left;
+ mWarningTextPaint.setTextSize(mHeight * 0.75f);
+ mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
+ }
+
+ protected void updateShowPercent() {
+ mShowPercent = true;
+ }
+
+ private int getColorForLevel(int percent) {
+ // If we are in power save mode, always use the normal color.
+ if (mPowerSaveEnabled) {
+ return mColors[mColors.length - 1];
+ }
+ int thresh, color = 0;
+ for (int i = 0; i < mColors.length; i += 2) {
+ thresh = mColors[i];
+ color = mColors[i + 1];
+ if (percent <= thresh) {
+
+ // Respect tinting for "normal" level
+ if (i == mColors.length - 2) {
+ return mIconTint;
+ } else {
+ return color;
+ }
+ }
+ }
+ return color;
+ }
+
+ public void setDarkIntensity(float darkIntensity) {
+ if (darkIntensity == mOldDarkIntensity) {
+ return;
+ }
+ int backgroundColor = getBackgroundColor(darkIntensity);
+ int fillColor = getFillColor(darkIntensity);
+ setColors(fillColor, backgroundColor);
+ mOldDarkIntensity = darkIntensity;
+ }
+
+ public void setColors(int fillColor, int backgroundColor) {
+ mIconTint = fillColor;
+ mFramePaint.setColor(backgroundColor);
+ mBoltPaint.setColor(fillColor);
+ mChargeColor = fillColor;
+ invalidateSelf();
+ }
+
+ private int getBackgroundColor(float darkIntensity) {
+ return getColorForDarkIntensity(
+ darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
+ }
+
+ private int getFillColor(float darkIntensity) {
+ return getColorForDarkIntensity(
+ darkIntensity, mLightModeFillColor, mDarkModeFillColor);
+ }
+
+ private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
+ return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
+ }
+
+ @Override
+ public void draw(Canvas c) {
+ final int level = mLevel;
+
+ if (level == -1) return;
+
+ float drawFrac = (float) level / 100f;
+ final int height = mHeight;
+ final int width = (int) (ASPECT_RATIO * mHeight);
+ int px = (mWidth - width) / 2;
+
+ final int buttonHeight = (int) (height * mButtonHeightFraction);
+
+ mFrame.set(0, 0, width, height);
+ mFrame.offset(px, 0);
+
+ // button-frame: area above the battery body
+ mButtonFrame.set(
+ mFrame.left + Math.round(width * 0.25f),
+ mFrame.top,
+ mFrame.right - Math.round(width * 0.25f),
+ mFrame.top + buttonHeight);
+
+ mButtonFrame.top += mSubpixelSmoothingLeft;
+ mButtonFrame.left += mSubpixelSmoothingLeft;
+ mButtonFrame.right -= mSubpixelSmoothingRight;
+
+ // frame: battery body area
+ mFrame.top += buttonHeight;
+ mFrame.left += mSubpixelSmoothingLeft;
+ mFrame.top += mSubpixelSmoothingLeft;
+ mFrame.right -= mSubpixelSmoothingRight;
+ mFrame.bottom -= mSubpixelSmoothingRight;
+
+ // set the battery charging color
+ mBatteryPaint.setColor(mPluggedIn ? mChargeColor : getColorForLevel(level));
+
+ if (level >= FULL) {
+ drawFrac = 1f;
+ } else if (level <= mCriticalLevel) {
+ drawFrac = 0f;
+ }
+
+ final float levelTop = drawFrac == 1f ? mButtonFrame.top
+ : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
+
+ // define the battery shape
+ mShapePath.reset();
+ mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
+ mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
+ mShapePath.lineTo(mButtonFrame.right, mFrame.top);
+ mShapePath.lineTo(mFrame.right, mFrame.top);
+ mShapePath.lineTo(mFrame.right, mFrame.bottom);
+ mShapePath.lineTo(mFrame.left, mFrame.bottom);
+ mShapePath.lineTo(mFrame.left, mFrame.top);
+ mShapePath.lineTo(mButtonFrame.left, mFrame.top);
+ mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
+
+ if (mPluggedIn) {
+ // define the bolt shape
+ final float bl = mFrame.left + mFrame.width() / 4f;
+ final float bt = mFrame.top + mFrame.height() / 6f;
+ final float br = mFrame.right - mFrame.width() / 4f;
+ final float bb = mFrame.bottom - mFrame.height() / 10f;
+ if (mBoltFrame.left != bl || mBoltFrame.top != bt
+ || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
+ mBoltFrame.set(bl, bt, br, bb);
+ mBoltPath.reset();
+ mBoltPath.moveTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ for (int i = 2; i < mBoltPoints.length; i += 2) {
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+ }
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ }
+
+ float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
+ boltPct = Math.min(Math.max(boltPct, 0), 1);
+ if (boltPct <= BOLT_LEVEL_THRESHOLD) {
+ // draw the bolt if opaque
+ c.drawPath(mBoltPath, mBoltPaint);
+ } else {
+ // otherwise cut the bolt out of the overall shape
+ mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
+ }
+ } else if (mPowerSaveEnabled) {
+ // define the plus shape
+ final float pw = mFrame.width() * 2 / 3;
+ final float pl = mFrame.left + (mFrame.width() - pw) / 2;
+ final float pt = mFrame.top + (mFrame.height() - pw) / 2;
+ final float pr = mFrame.right - (mFrame.width() - pw) / 2;
+ final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
+ if (mPlusFrame.left != pl || mPlusFrame.top != pt
+ || mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
+ mPlusFrame.set(pl, pt, pr, pb);
+ mPlusPath.reset();
+ mPlusPath.moveTo(
+ mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
+ mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
+ for (int i = 2; i < mPlusPoints.length; i += 2) {
+ mPlusPath.lineTo(
+ mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
+ mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
+ }
+ mPlusPath.lineTo(
+ mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
+ mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
+ }
+
+ float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
+ boltPct = Math.min(Math.max(boltPct, 0), 1);
+ if (boltPct <= BOLT_LEVEL_THRESHOLD) {
+ // draw the bolt if opaque
+ c.drawPath(mPlusPath, mPlusPaint);
+ } else {
+ // otherwise cut the bolt out of the overall shape
+ mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
+ }
+ }
+
+ // compute percentage text
+ boolean pctOpaque = false;
+ float pctX = 0, pctY = 0;
+ String pctText = null;
+ if (!mPluggedIn && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
+ mTextPaint.setColor(getColorForLevel(level));
+ mTextPaint.setTextSize(height *
+ (SINGLE_DIGIT_PERCENT ? 0.75f
+ : (mLevel == 100 ? 0.38f : 0.5f)));
+ mTextHeight = -mTextPaint.getFontMetrics().ascent;
+ pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level / 10) : level);
+ pctX = mWidth * 0.5f;
+ pctY = (mHeight + mTextHeight) * 0.47f;
+ pctOpaque = levelTop > pctY;
+ if (!pctOpaque) {
+ mTextPath.reset();
+ mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
+ // cut the percentage text out of the overall shape
+ mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
+ }
+ }
+
+ // draw the battery shape background
+ c.drawPath(mShapePath, mFramePaint);
+
+ // draw the battery shape, clipped to charging level
+ mFrame.top = levelTop;
+ mClipPath.reset();
+ mClipPath.addRect(mFrame, Path.Direction.CCW);
+ mShapePath.op(mClipPath, Path.Op.INTERSECT);
+ c.drawPath(mShapePath, mBatteryPaint);
+
+ if (!mPluggedIn && !mPowerSaveEnabled) {
+ if (level <= mCriticalLevel) {
+ // draw the warning text
+ final float x = mWidth * 0.5f;
+ final float y = (mHeight + mWarningTextHeight) * 0.48f;
+ c.drawText(mWarningString, x, y, mWarningTextPaint);
+ } else if (pctOpaque) {
+ // draw the percentage text
+ c.drawText(pctText, pctX, pctY, mTextPaint);
+ }
+ }
+ }
+
+ // Some stuff required by Drawable.
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ mFramePaint.setColorFilter(colorFilter);
+ mBatteryPaint.setColorFilter(colorFilter);
+ mWarningTextPaint.setColorFilter(colorFilter);
+ mBoltPaint.setColorFilter(colorFilter);
+ mPlusPaint.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+}
--- /dev/null
+package com.android.settingslib.graph;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import com.android.settingslib.R;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatteryMeterDrawableBaseTest {
+ private Context mContext;
+ private Resources mResources;
+ private BatteryMeterDrawableBase mBatteryDrawable;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mResources = mContext.getResources();
+ mBatteryDrawable = new BatteryMeterDrawableBase(mContext, 0);
+ }
+
+ @Test
+ public void testGetIntrinsicSize() {
+ assertThat(mBatteryDrawable.getIntrinsicWidth()).
+ isEqualTo(mResources.getDimensionPixelSize(R.dimen.battery_width));
+ assertThat(mBatteryDrawable.getIntrinsicHeight()).
+ isEqualTo(mResources.getDimensionPixelSize(R.dimen.battery_height));
+ }
+
+ @Test
+ public void testDrawNothingBeforeOnBatteryLevelChanged() {
+ final Canvas canvas = mock(Canvas.class);
+ mBatteryDrawable.draw(canvas);
+ verify(canvas, never()).drawPath(any(), any());
+ verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
+ }
+}
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/colors.xml
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- BatteryMeterView parameters -->
- <array name="batterymeter_color_levels">
- <item>15</item>
- <item>100</item>
- </array>
- <array name="batterymeter_color_values">
- <item>@*android:color/battery_saver_mode_color</item>
- <item>#FFFFFFFF</item>
- </array>
- <array name="batterymeter_bolt_points">
- <item>73</item> <item>0</item>
- <item>392</item><item>0</item>
- <item>201</item><item>259</item>
- <item>442</item><item>259</item>
- <item>4</item> <item>703</item>
- <item>157</item><item>334</item>
- <item>0</item> <item>334</item>
- </array>
- <array name="batterymeter_plus_points">
- <item>3</item><item>0</item>
- <item>5</item><item>0</item>
- <item>5</item><item>3</item>
- <item>8</item><item>3</item>
- <item>8</item><item>5</item>
- <item>5</item><item>5</item>
- <item>5</item><item>8</item>
- <item>3</item><item>8</item>
- <item>3</item><item>5</item>
- <item>0</item><item>5</item>
- <item>0</item><item>3</item>
- <item>3</item><item>3</item>
- </array>
-</resources>
<drawable name="status_bar_notification_row_background_color">#ff090909</drawable>
<color name="notification_list_shadow_top">#80000000</color>
<drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
- <color name="batterymeter_frame_color">#4DFFFFFF</color><!-- 30% white -->
- <color name="batterymeter_charge_color">#FFFFFFFF</color>
- <color name="batterymeter_bolt_color">#FFFFFFFF</color>
<color name="qs_batterymeter_frame_color">#FF404040</color>
<color name="system_warning_color">@*android:color/system_error</color>
<color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
<!-- How much two taps can be apart to still be recognized as a double tap on the lockscreen -->
<dimen name="double_tap_slop">32dp</dimen>
- <!-- Margin on the right side of the system icon group on Keyguard. -->
- <fraction name="battery_button_height_fraction">10.5%</fraction>
-
- <!-- Fraction value to smooth the edges of the battery icon. The path will be inset by this
- fraction of a pixel.-->
- <fraction name="battery_subpixel_smoothing_left">0%</fraction>
- <fraction name="battery_subpixel_smoothing_right">0%</fraction>
-
<dimen name="battery_margin_bottom">0dp</dimen>
<!-- Padding at the end of the view that displays the mobile signal icons. If the view is
<dimen name="docked_divider_handle_width">16dp</dimen>
<dimen name="docked_divider_handle_height">2dp</dimen>
- <dimen name="battery_height">14.5dp</dimen>
- <dimen name="battery_width">9.5dp</dimen>
-
<dimen name="battery_detail_graph_space_top">27dp</dimen>
<dimen name="battery_detail_graph_space_bottom">27dp</dimen>
<!-- Expanded Status Bar Header: Not charging [CHAR LIMIT=40] -->
<string name="expanded_header_battery_not_charging">Not charging</string>
- <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
- <string name="battery_meter_very_low_overlay_symbol">!</string>
-
<!-- Shows up when there is a user SSL CA Cert installed on the
device. Indicates to the user that SSL traffic can be intercepted.
If the text fits on one line (~14 chars), it should start with a
package com.android.systemui;
-import android.animation.ArgbEvaluator;
-import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.database.ContentObserver;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
-
+import com.android.settingslib.graph.BatteryMeterDrawableBase;
import com.android.systemui.statusbar.policy.BatteryController;
-public class BatteryMeterDrawable extends Drawable implements
+public class BatteryMeterDrawable extends BatteryMeterDrawableBase implements
BatteryController.BatteryStateChangeCallback {
- private static final float ASPECT_RATIO = 9.5f / 14.5f;
- public static final String TAG = BatteryMeterDrawable.class.getSimpleName();
- public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
-
- private static final boolean SINGLE_DIGIT_PERCENT = false;
-
- private static final int FULL = 96;
-
- private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction
-
- private final int[] mColors;
- private final int mIntrinsicWidth;
- private final int mIntrinsicHeight;
-
- private boolean mShowPercent;
- private float mButtonHeightFraction;
- private float mSubpixelSmoothingLeft;
- private float mSubpixelSmoothingRight;
- private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint,
- mPlusPaint;
- private float mTextHeight, mWarningTextHeight;
- private int mIconTint = Color.WHITE;
- private float mOldDarkIntensity = 0f;
-
- private int mHeight;
- private int mWidth;
- private String mWarningString;
- private final int mCriticalLevel;
- private int mChargeColor;
- private final float[] mBoltPoints;
- private final Path mBoltPath = new Path();
- private final float[] mPlusPoints;
- private final Path mPlusPath = new Path();
-
- private final RectF mFrame = new RectF();
- private final RectF mButtonFrame = new RectF();
- private final RectF mBoltFrame = new RectF();
- private final RectF mPlusFrame = new RectF();
-
- private final Path mShapePath = new Path();
- private final Path mClipPath = new Path();
- private final Path mTextPath = new Path();
-
private BatteryController mBatteryController;
- private boolean mPowerSaveEnabled;
-
- private int mDarkModeBackgroundColor;
- private int mDarkModeFillColor;
-
- private int mLightModeBackgroundColor;
- private int mLightModeFillColor;
-
- private final SettingObserver mSettingObserver;
-
- private final Context mContext;
-
- private int mLevel = -1;
- private boolean mPluggedIn;
- private boolean mListening;
+ private SettingObserver mSettingObserver;
public BatteryMeterDrawable(Context context, int frameColor) {
- mContext = context;
- mSettingObserver = new SettingObserver(new Handler(mContext.getMainLooper()));
- final Resources res = context.getResources();
- TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
- TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
-
- final int N = levels.length();
- mColors = new int[2*N];
- for (int i=0; i<N; i++) {
- mColors[2*i] = levels.getInt(i, 0);
- mColors[2*i+1] = colors.getColor(i, 0);
- }
- levels.recycle();
- colors.recycle();
- updateShowPercent();
- mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
- mCriticalLevel = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_criticalBatteryWarningLevel);
- mButtonHeightFraction = context.getResources().getFraction(
- R.fraction.battery_button_height_fraction, 1, 1);
- mSubpixelSmoothingLeft = context.getResources().getFraction(
- R.fraction.battery_subpixel_smoothing_left, 1, 1);
- mSubpixelSmoothingRight = context.getResources().getFraction(
- R.fraction.battery_subpixel_smoothing_right, 1, 1);
-
- mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mFramePaint.setColor(frameColor);
- mFramePaint.setDither(true);
- mFramePaint.setStrokeWidth(0);
- mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
- mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBatteryPaint.setDither(true);
- mBatteryPaint.setStrokeWidth(0);
- mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
- mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
- mTextPaint.setTypeface(font);
- mTextPaint.setTextAlign(Paint.Align.CENTER);
-
- mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mWarningTextPaint.setColor(mColors[1]);
- font = Typeface.create("sans-serif", Typeface.BOLD);
- mWarningTextPaint.setTypeface(font);
- mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
-
- mChargeColor = context.getColor(R.color.batterymeter_charge_color);
-
- mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
- mBoltPoints = loadBoltPoints(res);
-
- mPlusPaint = new Paint(mBoltPaint);
- mPlusPoints = loadPlusPoints(res);
-
- mDarkModeBackgroundColor =
- context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
- mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
- mLightModeBackgroundColor =
- context.getColor(R.color.light_mode_icon_color_dual_tone_background);
- mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
-
- mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
- mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
- }
-
- @Override
- public int getIntrinsicHeight() {
- return mIntrinsicHeight;
- }
-
- @Override
- public int getIntrinsicWidth() {
- return mIntrinsicWidth;
- }
-
- public void startListening() {
- mListening = true;
- mContext.getContentResolver().registerContentObserver(
- Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
- updateShowPercent();
- mBatteryController.addCallback(this);
- }
-
- public void stopListening() {
- mListening = false;
- mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
- mBatteryController.removeCallback(this);
- }
+ super(context, frameColor);
- public void disableShowPercent() {
- mShowPercent = false;
- postInvalidate();
- }
-
- private void postInvalidate() {
- scheduleSelf(this::invalidateSelf, 0);
- }
-
- public void setBatteryController(BatteryController batteryController) {
- mBatteryController = batteryController;
- mPowerSaveEnabled = mBatteryController.isPowerSave();
+ mSettingObserver = new SettingObserver(new Handler(mContext.getMainLooper()));
}
@Override
invalidateSelf();
}
- private static float[] loadBoltPoints(Resources res) {
- final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
- int maxX = 0, maxY = 0;
- for (int i = 0; i < pts.length; i += 2) {
- maxX = Math.max(maxX, pts[i]);
- maxY = Math.max(maxY, pts[i + 1]);
- }
- final float[] ptsF = new float[pts.length];
- for (int i = 0; i < pts.length; i += 2) {
- ptsF[i] = (float)pts[i] / maxX;
- ptsF[i + 1] = (float)pts[i + 1] / maxY;
- }
- return ptsF;
+ public void startListening() {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
+ updateShowPercent();
+ mBatteryController.addCallback(this);
}
- private static float[] loadPlusPoints(Resources res) {
- final int[] pts = res.getIntArray(R.array.batterymeter_plus_points);
- int maxX = 0, maxY = 0;
- for (int i = 0; i < pts.length; i += 2) {
- maxX = Math.max(maxX, pts[i]);
- maxY = Math.max(maxY, pts[i + 1]);
- }
- final float[] ptsF = new float[pts.length];
- for (int i = 0; i < pts.length; i += 2) {
- ptsF[i] = (float)pts[i] / maxX;
- ptsF[i + 1] = (float)pts[i + 1] / maxY;
- }
- return ptsF;
+ public void stopListening() {
+ mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
+ mBatteryController.removeCallback(this);
}
@Override
- public void setBounds(int left, int top, int right, int bottom) {
- super.setBounds(left, top, right, bottom);
- mHeight = bottom - top;
- mWidth = right - left;
- mWarningTextPaint.setTextSize(mHeight * 0.75f);
- mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
- }
-
- private void updateShowPercent() {
+ protected void updateShowPercent() {
mShowPercent = 0 != Settings.System.getInt(mContext.getContentResolver(),
SHOW_PERCENT_SETTING, 0);
}
- private int getColorForLevel(int percent) {
-
- // If we are in power save mode, always use the normal color.
- if (mPowerSaveEnabled) {
- return mColors[mColors.length-1];
- }
- int thresh, color = 0;
- for (int i=0; i<mColors.length; i+=2) {
- thresh = mColors[i];
- color = mColors[i+1];
- if (percent <= thresh) {
-
- // Respect tinting for "normal" level
- if (i == mColors.length-2) {
- return mIconTint;
- } else {
- return color;
- }
- }
- }
- return color;
- }
-
- public void setDarkIntensity(float darkIntensity) {
- if (darkIntensity == mOldDarkIntensity) {
- return;
- }
- int backgroundColor = getBackgroundColor(darkIntensity);
- int fillColor = getFillColor(darkIntensity);
- setColors(fillColor, backgroundColor);
- mOldDarkIntensity = darkIntensity;
- }
-
- public void setColors(int fillColor, int backgroundColor) {
- mIconTint = fillColor;
- mFramePaint.setColor(backgroundColor);
- mBoltPaint.setColor(fillColor);
- mChargeColor = fillColor;
- invalidateSelf();
- }
-
- private int getBackgroundColor(float darkIntensity) {
- return getColorForDarkIntensity(
- darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
- }
-
- private int getFillColor(float darkIntensity) {
- return getColorForDarkIntensity(
- darkIntensity, mLightModeFillColor, mDarkModeFillColor);
- }
-
- private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
- return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
- }
-
- @Override
- public void draw(Canvas c) {
- final int level = mLevel;
-
- if (level == -1) return;
-
- float drawFrac = (float) level / 100f;
- final int height = mHeight;
- final int width = (int) (ASPECT_RATIO * mHeight);
- int px = (mWidth - width) / 2;
-
- final int buttonHeight = (int) (height * mButtonHeightFraction);
-
- mFrame.set(0, 0, width, height);
- mFrame.offset(px, 0);
-
- // button-frame: area above the battery body
- mButtonFrame.set(
- mFrame.left + Math.round(width * 0.25f),
- mFrame.top,
- mFrame.right - Math.round(width * 0.25f),
- mFrame.top + buttonHeight);
-
- mButtonFrame.top += mSubpixelSmoothingLeft;
- mButtonFrame.left += mSubpixelSmoothingLeft;
- mButtonFrame.right -= mSubpixelSmoothingRight;
-
- // frame: battery body area
- mFrame.top += buttonHeight;
- mFrame.left += mSubpixelSmoothingLeft;
- mFrame.top += mSubpixelSmoothingLeft;
- mFrame.right -= mSubpixelSmoothingRight;
- mFrame.bottom -= mSubpixelSmoothingRight;
-
- // set the battery charging color
- mBatteryPaint.setColor(mPluggedIn ? mChargeColor : getColorForLevel(level));
-
- if (level >= FULL) {
- drawFrac = 1f;
- } else if (level <= mCriticalLevel) {
- drawFrac = 0f;
- }
-
- final float levelTop = drawFrac == 1f ? mButtonFrame.top
- : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
-
- // define the battery shape
- mShapePath.reset();
- mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
-
- if (mPluggedIn) {
- // define the bolt shape
- final float bl = mFrame.left + mFrame.width() / 4f;
- final float bt = mFrame.top + mFrame.height() / 6f;
- final float br = mFrame.right - mFrame.width() / 4f;
- final float bb = mFrame.bottom - mFrame.height() / 10f;
- if (mBoltFrame.left != bl || mBoltFrame.top != bt
- || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
- mBoltFrame.set(bl, bt, br, bb);
- mBoltPath.reset();
- mBoltPath.moveTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
- for (int i = 2; i < mBoltPoints.length; i += 2) {
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
- }
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
- }
-
- float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
- boltPct = Math.min(Math.max(boltPct, 0), 1);
- if (boltPct <= BOLT_LEVEL_THRESHOLD) {
- // draw the bolt if opaque
- c.drawPath(mBoltPath, mBoltPaint);
- } else {
- // otherwise cut the bolt out of the overall shape
- mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
- }
- } else if (mPowerSaveEnabled) {
- // define the plus shape
- final float pw = mFrame.width() * 2 / 3;
- final float pl = mFrame.left + (mFrame.width() - pw) / 2;
- final float pt = mFrame.top + (mFrame.height() - pw) / 2;
- final float pr = mFrame.right - (mFrame.width() - pw) / 2;
- final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
- if (mPlusFrame.left != pl || mPlusFrame.top != pt
- || mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
- mPlusFrame.set(pl, pt, pr, pb);
- mPlusPath.reset();
- mPlusPath.moveTo(
- mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
- mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
- for (int i = 2; i < mPlusPoints.length; i += 2) {
- mPlusPath.lineTo(
- mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
- mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
- }
- mPlusPath.lineTo(
- mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
- mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
- }
-
- float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
- boltPct = Math.min(Math.max(boltPct, 0), 1);
- if (boltPct <= BOLT_LEVEL_THRESHOLD) {
- // draw the bolt if opaque
- c.drawPath(mPlusPath, mPlusPaint);
- } else {
- // otherwise cut the bolt out of the overall shape
- mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
- }
- }
-
- // compute percentage text
- boolean pctOpaque = false;
- float pctX = 0, pctY = 0;
- String pctText = null;
- if (!mPluggedIn && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
- mTextPaint.setColor(getColorForLevel(level));
- mTextPaint.setTextSize(height *
- (SINGLE_DIGIT_PERCENT ? 0.75f
- : (mLevel == 100 ? 0.38f : 0.5f)));
- mTextHeight = -mTextPaint.getFontMetrics().ascent;
- pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
- pctX = mWidth * 0.5f;
- pctY = (mHeight + mTextHeight) * 0.47f;
- pctOpaque = levelTop > pctY;
- if (!pctOpaque) {
- mTextPath.reset();
- mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
- // cut the percentage text out of the overall shape
- mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
- }
- }
-
- // draw the battery shape background
- c.drawPath(mShapePath, mFramePaint);
-
- // draw the battery shape, clipped to charging level
- mFrame.top = levelTop;
- mClipPath.reset();
- mClipPath.addRect(mFrame, Path.Direction.CCW);
- mShapePath.op(mClipPath, Path.Op.INTERSECT);
- c.drawPath(mShapePath, mBatteryPaint);
-
- if (!mPluggedIn && !mPowerSaveEnabled) {
- if (level <= mCriticalLevel) {
- // draw the warning text
- final float x = mWidth * 0.5f;
- final float y = (mHeight + mWarningTextHeight) * 0.48f;
- c.drawText(mWarningString, x, y, mWarningTextPaint);
- } else if (pctOpaque) {
- // draw the percentage text
- c.drawText(pctText, pctX, pctY, mTextPaint);
- }
- }
- }
-
- // Some stuff required by Drawable.
- @Override
- public void setAlpha(int alpha) {
- }
-
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
- mFramePaint.setColorFilter(colorFilter);
- mBatteryPaint.setColorFilter(colorFilter);
- mWarningTextPaint.setColorFilter(colorFilter);
- mTextPaint.setColorFilter(colorFilter);
- mBoltPaint.setColorFilter(colorFilter);
- mPlusPaint.setColorFilter(colorFilter);
- }
-
- @Override
- public int getOpacity() {
- return 0;
+ public void setBatteryController(BatteryController batteryController) {
+ mBatteryController = batteryController;
+ mPowerSaveEnabled = mBatteryController.isPowerSave();
}
private final class SettingObserver extends ContentObserver {
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.statusbar.phone.StatusBarIconController;
-import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
+import static com.android.settingslib.graph.BatteryMeterDrawableBase.SHOW_PERCENT_SETTING;
public class BatteryPreference extends DropDownPreference implements TunerService.Tunable {
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.systemui.BatteryMeterDrawable;
+import com.android.settingslib.graph.BatteryMeterDrawableBase;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
public void clearAll() {
// A couple special cases.
Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
- Settings.System.putString(mContentResolver, BatteryMeterDrawable.SHOW_PERCENT_SETTING, null);
+ Settings.System.putString(mContentResolver,
+ BatteryMeterDrawableBase.SHOW_PERCENT_SETTING, null);
Intent intent = new Intent(DemoMode.ACTION_DEMO);
intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
mContext.sendBroadcast(intent);
package com.android.systemui;
-import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyFloat;
}
@Test
- public void testGetIntrinsicSize() {
- assertEquals(
- mResources.getDimensionPixelSize(R.dimen.battery_width),
- mBatteryMeter.getIntrinsicWidth());
- assertEquals(
- mResources.getDimensionPixelSize(R.dimen.battery_height),
- mBatteryMeter.getIntrinsicHeight());
- }
-
- @Test
- public void testDrawNothingBeforeOnBatteryLevelChanged() {
- final Canvas canvas = mock(Canvas.class);
- mBatteryMeter.draw(canvas);
- verify(canvas, never()).drawPath(any(), any());
- verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
- }
-
- @Test
public void testDrawImageButNoTextIfPluggedIn() {
mBatteryMeter.onBatteryLevelChanged(0, true, true);
final Canvas canvas = mock(Canvas.class);