Merge "Move the logic of batteryMeterDrawable to settingslib"
This commit is contained in:
committed by
Android (Google) Code Review
commit
ba89ed754f
18
packages/SettingsLib/res/color/batterymeter_bolt_color.xml
Normal file
18
packages/SettingsLib/res/color/batterymeter_bolt_color.xml
Normal 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>
|
||||
18
packages/SettingsLib/res/color/batterymeter_charge_color.xml
Normal file
18
packages/SettingsLib/res/color/batterymeter_charge_color.xml
Normal 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>
|
||||
18
packages/SettingsLib/res/color/batterymeter_frame_color.xml
Normal file
18
packages/SettingsLib/res/color/batterymeter_frame_color.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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 -->
|
||||
|
||||
@@ -520,14 +520,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
|
||||
@@ -642,9 +634,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>
|
||||
|
||||
|
||||
@@ -819,9 +819,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
|
||||
|
||||
469
packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
Executable file → Normal file
469
packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
Executable file → Normal 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 {
|
||||
|
||||
@@ -25,7 +25,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.systemui.Dependency;
|
||||
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 {
|
||||
|
||||
|
||||
@@ -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.Dependency;
|
||||
import com.android.systemui.R;
|
||||
@@ -200,7 +200,8 @@ public class TunerService {
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user