Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Toward regularizing color & level across battery indicators.
Browse files Browse the repository at this point in the history
Each of our existing assets is slightly incorrect in some
way: inconsistent pixel jumps from one percent to the next,
inconsistent color change, etc. The only way to get it
perfectly right is to draw it programmatically.

Bug: 8504254 // inconsistent color change threshold
-- previously --
Bug: 3136046 // in Gingerbread
Bug: 3387973 // Honeycomb
Bug: 5070948 // ICS
Change-Id: I6a3e7409ecec55e10328541ecb1e9d54aebdbe96
  • Loading branch information
dsandler committed Aug 14, 2013
1 parent 9955699 commit dfaf3bd
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 18 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions packages/SystemUI/res/layout/quick_settings_tile_battery.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
android:layout_height="match_parent"
android:layout_gravity="top"
android:orientation="vertical">
<ImageView
<com.android.systemui.BatteryMeterView
android:id="@+id/image"
android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
android:layout_width="@dimen/qs_tile_icon_size"
android:layout_height="@dimen/qs_tile_icon_size"
android:layout_width="22dp"
android:layout_height="32dp"
android:padding="3dp"
android:layout_gravity="top|center_horizontal"
android:scaleType="centerInside"
/>
<TextView
style="@style/TextAppearance.QuickSettings.TileView"
Expand All @@ -36,4 +36,4 @@
android:layout_gravity="top|center_horizontal"
android:gravity="top|center_horizontal"
/>
</LinearLayout>
</LinearLayout>
3 changes: 2 additions & 1 deletion packages/SystemUI/res/layout/signal_cluster_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@

<com.android.systemui.statusbar.SignalClusterView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:gravity="center"
android:orientation="horizontal"
>
<FrameLayout
Expand Down
10 changes: 6 additions & 4 deletions packages/SystemUI/res/layout/status_bar.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<ImageView
<!-- battery must be padded below by 1px to match assets -->
<com.android.systemui.BatteryMeterView
android:id="@+id/battery"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingStart="4dip"
android:layout_height="16dp"
android:layout_width="10dp"
android:paddingBottom="1px"
android:layout_marginStart="4dip"
/>
</LinearLayout>

Expand Down
12 changes: 12 additions & 0 deletions packages/SystemUI/res/values/arrays.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,16 @@
<item>@null</item>
</array>

<!-- BatteryMeterView parameters -->
<array name="batterymeter_color_levels">
<item>4</item>
<item>15</item>
<item>100</item>
</array>
<array name="batterymeter_color_values">
<item>#FFFF0000</item>
<item>#FFFE6600</item>
<item>#FF3792B4</item>
</array>

</resources>
2 changes: 2 additions & 0 deletions packages/SystemUI/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@
<drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
<drawable name="notification_header_bg">#FF000000</drawable>
<color name="notification_panel_scrim_color">#B0000000</color>

<color name="batterymeter_frame_color">#FF404040</color>
</resources>
3 changes: 3 additions & 0 deletions packages/SystemUI/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -503,4 +503,7 @@
<string name="status_bar_help_title">Notifications appear here</string>
<!-- Body of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] -->
<string name="status_bar_help_text">Access them anytime by swiping down.\nSwipe down again for system controls.</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>
302 changes: 302 additions & 0 deletions packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
/*
* Copyright (C) 2013 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.systemui;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.BatteryManager;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.View;

public class BatteryMeterView extends View {
public static final String TAG = BatteryMeterView.class.getSimpleName();
public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";

public static final boolean ENABLE_PERCENT = true;
public static final boolean SINGLE_DIGIT_PERCENT = false;
public static final boolean SHOW_100_PERCENT = false;

public static final int FULL = 96;
public static final int EMPTY = 4;

int[] mColors;

boolean mShowPercent = true;
Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint;
int mButtonHeight;
private float mTextHeight, mWarningTextHeight;
Drawable mLightning;

private int mHeight;
private int mWidth;
private String mWarningString;

private class BatteryTracker extends BroadcastReceiver {
// current battery status
int level;
String percentStr;
int plugType;
boolean plugged;
int health;
int status;
String technology;
int voltage;
int temperature;
boolean testmode = false;

@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
if (testmode && ! intent.getBooleanExtra("testmode", false)) return;

level = (int)(100f
* intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
/ intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));

plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
plugged = plugType != 0;
health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH,
BatteryManager.BATTERY_HEALTH_UNKNOWN);
status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);
temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);

setContentDescription(
context.getString(R.string.accessibility_battery_level, level));
postInvalidate();
} else if (action.equals(ACTION_LEVEL_TEST)) {
testmode = true;
post(new Runnable() {
int curLevel = 0;
int incr = 1;
int saveLevel = level;
int savePlugged = plugType;
Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
@Override
public void run() {
if (curLevel < 0) {
testmode = false;
dummy.putExtra("level", saveLevel);
dummy.putExtra("plugged", savePlugged);
dummy.putExtra("testmode", false);
} else {
dummy.putExtra("level", curLevel);
dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC : 0);
dummy.putExtra("testmode", true);
}
getContext().sendBroadcast(dummy);

if (!testmode) return;

curLevel += incr;
if (curLevel == 100) {
incr *= -1;
}
postDelayed(this, 200);
}
});
}
}
}

BatteryTracker mTracker = new BatteryTracker();

@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();

IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(ACTION_LEVEL_TEST);
getContext().registerReceiver(mTracker, filter);
}

@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();

getContext().unregisterReceiver(mTracker);
}

public BatteryMeterView(Context context) {
this(context, null, 0);
}

public BatteryMeterView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

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);
}

mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
context.getContentResolver(), "status_bar_show_battery_percent", 0);

mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);

mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFramePaint.setColor(res.getColor(R.color.batterymeter_frame_color));
mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBatteryPaint.setColor(0xFF00FF00); // will be replaced by something from mColors

mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(0xFFFFFFFF);
Typeface font = Typeface.create("sans-serif-condensed", Typeface.NORMAL);
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);

mLightning = getResources().getDrawable(R.drawable.lightning);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mHeight = h;
mWidth = w;
mWarningTextPaint.setTextSize(h * 0.75f);
mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
}

private int getColorForLevel(int percent) {
int thresh, color = 0;
for (int i=0; i<mColors.length; i+=2) {
thresh = mColors[i];
color = mColors[i+1];
if (percent <= thresh) return color;
}
return color;
}

@Override
public void draw(Canvas c) {
final int level = mTracker.level;
float drawFrac = (float) level / 100f;
final int pt = getPaddingTop();
final int pl = getPaddingLeft();
final int pr = getPaddingRight();
final int pb = getPaddingBottom();
int height = mHeight - pt - pb;
int width = mWidth - pl - pr;

mButtonHeight = (int) (height * 0.12f);

final RectF frame = new RectF(0, 0, width, height);
frame.offset(pl, pt);

// Log.v("BatteryGauge", String.format("canvas: %dx%d frame: %s",
// c.getWidth(), c.getHeight(), frame.toString()));

final RectF buttonframe = new RectF(
frame.left + width * 0.25f,
frame.top,
frame.right - width * 0.25f,
frame.top + mButtonHeight);

frame.top += mButtonHeight;

// first, draw the battery shape
c.drawRect(frame, mFramePaint);

// fill 'er up
final int pct = mTracker.level;
final int color = getColorForLevel(pct);
mBatteryPaint.setColor(color);

if (level >= FULL) {
drawFrac = 1f;
} else if (level <= EMPTY) {
drawFrac = 0f;
}

c.drawRect(buttonframe,
drawFrac == 1f ? mBatteryPaint : mFramePaint);

RectF clip = new RectF(frame);
clip.top += (frame.height() * (1f - drawFrac));

c.save(Canvas.CLIP_SAVE_FLAG);
c.clipRect(clip);
c.drawRect(frame, mBatteryPaint);
c.restore();

if (level <= EMPTY) {
final float x = mWidth * 0.5f;
final float y = (mHeight + mWarningTextHeight) * 0.48f;
c.drawText(mWarningString, x, y, mWarningTextPaint);
} else if (mTracker.plugged) {
final Rect r = new Rect(
(int)frame.left + width / 4, (int)frame.top + height / 5,
(int)frame.right - width / 4, (int)frame.bottom - height / 6);
mLightning.setBounds(r);
mLightning.draw(c);
} else if (mShowPercent && !(mTracker.level == 100 && !SHOW_100_PERCENT)) {
mTextPaint.setTextSize(height *
(SINGLE_DIGIT_PERCENT ? 0.75f
: (mTracker.level == 100 ? 0.38f : 0.5f)));
mTextHeight = -mTextPaint.getFontMetrics().ascent;

final String str = String.valueOf(SINGLE_DIGIT_PERCENT ? (pct/10) : pct);
final float x = mWidth * 0.5f;
final float y = (mHeight + mTextHeight) * 0.47f;
c.drawText(str,
x,
y,
mTextPaint);

// Paint pt = new Paint();
// pt.setStrokeWidth(1f);
// pt.setStyle(Paint.Style.STROKE);
// pt.setColor(0xFFFF0000);
// c.drawRect(x, y-mTextHeight, x+tw, y, pt);
//
// Slog.v(TAG, "tw=" + tw + " th=" + mTextHeight);
//
// pt.setColor(0xFFFF00FF);
// c.drawRect(1, 1, mWidth, mHeight, pt);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,6 @@ public boolean onTouch(View v, MotionEvent event) {
// Other icons
mLocationController = new LocationController(mContext); // will post a notification
mBatteryController = new BatteryController(mContext);
mBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.battery));
mNetworkController = new NetworkController(mContext);
mBluetoothController = new BluetoothController(mContext);
mRotationLockController = new RotationLockController(mContext);
Expand Down
Loading

0 comments on commit dfaf3bd

Please sign in to comment.