diff options
20 files changed, 713 insertions, 545 deletions
| diff --git a/packages/SettingsLib/res/color/batterymeter_bolt_color.xml b/packages/SettingsLib/res/color/batterymeter_bolt_color.xml new file mode 100644 index 000000000000..34de5489a28b --- /dev/null +++ b/packages/SettingsLib/res/color/batterymeter_bolt_color.xml @@ -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>
\ No newline at end of file diff --git a/packages/SettingsLib/res/color/batterymeter_charge_color.xml b/packages/SettingsLib/res/color/batterymeter_charge_color.xml new file mode 100644 index 000000000000..15944c3a2a07 --- /dev/null +++ b/packages/SettingsLib/res/color/batterymeter_charge_color.xml @@ -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>
\ No newline at end of file diff --git a/packages/SettingsLib/res/color/batterymeter_frame_color.xml b/packages/SettingsLib/res/color/batterymeter_frame_color.xml new file mode 100644 index 000000000000..34de5489a28b --- /dev/null +++ b/packages/SettingsLib/res/color/batterymeter_frame_color.xml @@ -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>
\ No newline at end of file diff --git a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml new file mode 100644 index 000000000000..c8a80ac57c00 --- /dev/null +++ b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml @@ -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>
\ No newline at end of file diff --git a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml new file mode 100644 index 000000000000..8dcfdbb8cf1e --- /dev/null +++ b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml @@ -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>
\ No newline at end of file diff --git a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml new file mode 100644 index 000000000000..34de5489a28b --- /dev/null +++ b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml @@ -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>
\ No newline at end of file diff --git a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml new file mode 100644 index 000000000000..15944c3a2a07 --- /dev/null +++ b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml @@ -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>
\ No newline at end of file diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml index 7bbca5edbc85..eb64b3a9bbd9 100644 --- a/packages/SettingsLib/res/values/arrays.xml +++ b/packages/SettingsLib/res/values/arrays.xml @@ -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> diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml index 2e8b30fb5abf..b72bcc71f046 100644 --- a/packages/SettingsLib/res/values/dimens.xml +++ b/packages/SettingsLib/res/values/dimens.xml @@ -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> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 01296327f689..5475b325773f 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -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> diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java new file mode 100755 index 000000000000..d25bb2e1b1b7 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java @@ -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; +    } +} diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java new file mode 100644 index 000000000000..fab00dab5be7 --- /dev/null +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java @@ -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()); +    } +} diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml deleted file mode 100644 index bf0cba22ab0c..000000000000 --- a/packages/SystemUI/res/values/arrays.xml +++ /dev/null @@ -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> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 1ec611a43b56..aef2d7de371a 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -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 --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index ddcc4baf8350..9193260f911b 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -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> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index d3e965aedc98..04308a6f8e16 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java index 5a6afca627ec..2bdb2f33a37e 100755..100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java @@ -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; -        mSettingObserver = new SettingObserver(new Handler(mContext.getMainLooper())); -        final Resources res = context.getResources(); -        TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels); -        TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values); - -        final int N = levels.length(); -        mColors = new int[2*N]; -        for (int i=0; i<N; i++) { -            mColors[2*i] = levels.getInt(i, 0); -            mColors[2*i+1] = colors.getColor(i, 0); -        } -        levels.recycle(); -        colors.recycle(); -        updateShowPercent(); -        mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol); -        mCriticalLevel = mContext.getResources().getInteger( -                com.android.internal.R.integer.config_criticalBatteryWarningLevel); -        mButtonHeightFraction = context.getResources().getFraction( -                R.fraction.battery_button_height_fraction, 1, 1); -        mSubpixelSmoothingLeft = context.getResources().getFraction( -                R.fraction.battery_subpixel_smoothing_left, 1, 1); -        mSubpixelSmoothingRight = context.getResources().getFraction( -                R.fraction.battery_subpixel_smoothing_right, 1, 1); - -        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG); -        mFramePaint.setColor(frameColor); -        mFramePaint.setDither(true); -        mFramePaint.setStrokeWidth(0); -        mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE); - -        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG); -        mBatteryPaint.setDither(true); -        mBatteryPaint.setStrokeWidth(0); -        mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE); - -        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); -        Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD); -        mTextPaint.setTypeface(font); -        mTextPaint.setTextAlign(Paint.Align.CENTER); - -        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); -        mWarningTextPaint.setColor(mColors[1]); -        font = Typeface.create("sans-serif", Typeface.BOLD); -        mWarningTextPaint.setTypeface(font); -        mWarningTextPaint.setTextAlign(Paint.Align.CENTER); - -        mChargeColor = context.getColor(R.color.batterymeter_charge_color); - -        mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG); -        mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color)); -        mBoltPoints = loadBoltPoints(res); - -        mPlusPaint = new Paint(mBoltPaint); -        mPlusPoints = loadPlusPoints(res); - -        mDarkModeBackgroundColor = -                context.getColor(R.color.dark_mode_icon_color_dual_tone_background); -        mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill); -        mLightModeBackgroundColor = -                context.getColor(R.color.light_mode_icon_color_dual_tone_background); -        mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill); - -        mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width); -        mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height); -    } - -    @Override -    public int getIntrinsicHeight() { -        return mIntrinsicHeight; -    } - -    @Override -    public int getIntrinsicWidth() { -        return mIntrinsicWidth; -    } - -    public void startListening() { -        mListening = true; -        mContext.getContentResolver().registerContentObserver( -                Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver); -        updateShowPercent(); -        mBatteryController.addCallback(this); -    } - -    public void stopListening() { -        mListening = false; -        mContext.getContentResolver().unregisterContentObserver(mSettingObserver); -        mBatteryController.removeCallback(this); -    } +        super(context, frameColor); -    public void disableShowPercent() { -        mShowPercent = false; -        postInvalidate(); -    } - -    private void postInvalidate() { -        scheduleSelf(this::invalidateSelf, 0); -    } - -    public void setBatteryController(BatteryController batteryController) { -        mBatteryController = batteryController; -        mPowerSaveEnabled = mBatteryController.isPowerSave(); +        mSettingObserver = new SettingObserver(new Handler(mContext.getMainLooper()));      }      @Override @@ -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 { diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java index 9998283e1a05..d9c1667e2694 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java @@ -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 { diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java index fb94061f4093..6b4638a2c15a 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java @@ -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); diff --git a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java index cb0f7a388d01..09808d47a995 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java @@ -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; @@ -51,24 +50,6 @@ public class BatteryMeterDrawableTest extends SysuiTestCase {      }      @Test -    public void testGetIntrinsicSize() { -        assertEquals( -                mResources.getDimensionPixelSize(R.dimen.battery_width), -                mBatteryMeter.getIntrinsicWidth()); -        assertEquals( -                mResources.getDimensionPixelSize(R.dimen.battery_height), -                mBatteryMeter.getIntrinsicHeight()); -    } - -    @Test -    public void testDrawNothingBeforeOnBatteryLevelChanged() { -        final Canvas canvas = mock(Canvas.class); -        mBatteryMeter.draw(canvas); -        verify(canvas, never()).drawPath(any(), any()); -        verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any()); -    } - -    @Test      public void testDrawImageButNoTextIfPluggedIn() {          mBatteryMeter.onBatteryLevelChanged(0, true, true);          final Canvas canvas = mock(Canvas.class); |