Move the logic of batteryMeterDrawable to settingslib

In Settings, we also need a BatteryMeterDrawable to show battery meter,
that's why I move it to settingslib.

In this cl, what I have changed is listed below:
1. Create BatteryMeterDrawableLib that contains logic of battery
drawing.
2. Still Keep the battery control logic in systemui.
3. Remove hardcoded battery color by using the color state lists.
4. Move some tests to settingslib

Bug: 34771849
Test: make SettingsLibTests

Change-Id: I39c0f0e31ca5e1b958467298db1d0590d16c9f6d
This commit is contained in:
jackqdyulei
2017-01-27 13:31:40 -08:00
parent 1f2b03a42a
commit 597b10f6db
20 changed files with 713 additions and 545 deletions

View File

@@ -0,0 +1,18 @@
<?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>

View File

@@ -0,0 +1,18 @@
<?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>

View File

@@ -0,0 +1,18 @@
<?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>

View File

@@ -0,0 +1,18 @@
<?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>

View File

@@ -0,0 +1,18 @@
<?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>

View File

@@ -0,0 +1,18 @@
<?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>

View File

@@ -0,0 +1,18 @@
<?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>

View File

@@ -520,4 +520,37 @@
<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>

View File

@@ -57,4 +57,15 @@
<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>

View File

@@ -900,4 +900,7 @@
<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>

View File

@@ -0,0 +1,468 @@
/*
* 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;
}
}

View File

@@ -0,0 +1,51 @@
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());
}
}

View File

@@ -1,54 +0,0 @@
<?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>

View File

@@ -26,9 +26,6 @@
<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 -->

View File

@@ -515,14 +515,6 @@
<!-- 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
@@ -637,9 +629,6 @@
<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>

View File

@@ -817,9 +817,6 @@
<!-- 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

View File

@@ -16,193 +16,24 @@
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;
super(context, frameColor);
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);
}
public void disableShowPercent() {
mShowPercent = false;
postInvalidate();
}
private void postInvalidate() {
scheduleSelf(this::invalidateSelf, 0);
}
public void setBatteryController(BatteryController batteryController) {
mBatteryController = batteryController;
mPowerSaveEnabled = mBatteryController.isPowerSave();
}
@Override
@@ -219,293 +50,27 @@ public class BatteryMeterDrawable extends Drawable implements
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 {

View File

@@ -24,7 +24,7 @@ import com.android.internal.logging.MetricsLogger;
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 {

View File

@@ -38,7 +38,7 @@ import android.text.TextUtils;
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;
@@ -199,7 +199,8 @@ public class TunerService extends 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);

View File

@@ -16,7 +16,6 @@
package com.android.systemui;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyFloat;
@@ -50,24 +49,6 @@ public class BatteryMeterDrawableTest extends SysuiTestCase {
mBatteryMeter = new BatteryMeterDrawable(mContext, 0);
}
@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);