blob: 6476416a4e728e5978abd2fb71c7f8666cbf3994 [file] [log] [blame]
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040016package com.android.systemui;
17
Evan Lairdbcf631d2017-03-10 10:56:45 -050018import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
19
Jason Monk9a376bc2017-05-10 09:52:10 -040020import android.animation.ArgbEvaluator;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040021import android.content.Context;
Jason Monkaa573e92017-01-27 17:00:29 -050022import android.content.res.Resources;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040023import android.content.res.TypedArray;
Dan Sandler055bb612017-02-08 16:21:49 -080024import android.database.ContentObserver;
Jason Monk9a376bc2017-05-10 09:52:10 -040025import android.graphics.Rect;
Dan Sandler055bb612017-02-08 16:21:49 -080026import android.net.Uri;
27import android.os.Handler;
28import android.provider.Settings;
Jason Monk9a376bc2017-05-10 09:52:10 -040029import android.util.ArraySet;
30import android.util.AttributeSet;
31import android.util.TypedValue;
32import android.view.ContextThemeWrapper;
Dan Sandler055bb612017-02-08 16:21:49 -080033import android.view.Gravity;
34import android.view.LayoutInflater;
Jason Monk3e189872016-01-12 09:10:34 -050035import android.view.View;
Dan Sandler055bb612017-02-08 16:21:49 -080036import android.view.ViewGroup;
Jason Monkabe19742015-09-29 09:47:06 -040037import android.widget.ImageView;
Jason Monkaa573e92017-01-27 17:00:29 -050038import android.widget.LinearLayout;
Dan Sandler055bb612017-02-08 16:21:49 -080039import android.widget.TextView;
Jason Monk9a376bc2017-05-10 09:52:10 -040040
41import com.android.settingslib.Utils;
Dan Sandler055bb612017-02-08 16:21:49 -080042import com.android.settingslib.graph.BatteryMeterDrawableBase;
Jason Monk3e189872016-01-12 09:10:34 -050043import com.android.systemui.statusbar.phone.StatusBarIconController;
Jorim Jaggi708f7722014-08-20 17:30:38 +020044import com.android.systemui.statusbar.policy.BatteryController;
Jason Monkaa573e92017-01-27 17:00:29 -050045import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
46import com.android.systemui.statusbar.policy.ConfigurationController;
47import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
48import com.android.systemui.statusbar.policy.DarkIconDispatcher;
49import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
Jason Monk3e189872016-01-12 09:10:34 -050050import com.android.systemui.tuner.TunerService;
Jason Monkaa573e92017-01-27 17:00:29 -050051import com.android.systemui.tuner.TunerService.Tunable;
Jorim Jaggi708f7722014-08-20 17:30:38 +020052
Dan Sandler055bb612017-02-08 16:21:49 -080053import java.text.NumberFormat;
54
55public class BatteryMeterView extends LinearLayout implements
Jason Monkaa573e92017-01-27 17:00:29 -050056 BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040057
Dan Sandler055bb612017-02-08 16:21:49 -080058 private final BatteryMeterDrawableBase mDrawable;
Jason Monk3e189872016-01-12 09:10:34 -050059 private final String mSlotBattery;
Dan Sandler055bb612017-02-08 16:21:49 -080060 private final ImageView mBatteryIconView;
61 private TextView mBatteryPercentView;
62
Jorim Jaggi708f7722014-08-20 17:30:38 +020063 private BatteryController mBatteryController;
Dan Sandler055bb612017-02-08 16:21:49 -080064 private SettingObserver mSettingObserver;
65 private int mTextColor;
66 private int mLevel;
Jason Monkf13413e2017-02-15 15:49:32 -050067 private boolean mForceShowPercent;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040068
Jason Monk9a376bc2017-05-10 09:52:10 -040069 private int mDarkModeBackgroundColor;
70 private int mDarkModeFillColor;
71
72 private int mLightModeBackgroundColor;
73 private int mLightModeFillColor;
Lucas Dupin987f1932017-05-13 21:02:52 -070074 private float mDarkIntensity;
Jason Monk9a376bc2017-05-10 09:52:10 -040075
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040076 public BatteryMeterView(Context context) {
77 this(context, null, 0);
78 }
79
80 public BatteryMeterView(Context context, AttributeSet attrs) {
81 this(context, attrs, 0);
82 }
83
84 public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
85 super(context, attrs, defStyle);
86
Dan Sandler055bb612017-02-08 16:21:49 -080087 setOrientation(LinearLayout.HORIZONTAL);
88 setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
89
John Spurlock29786fc2014-02-04 17:55:47 -050090 TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
91 defStyle, 0);
92 final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
Daniel Nishi8af93cb2017-05-15 14:37:20 -070093 context.getColor(R.color.meter_background_color));
Dan Sandler055bb612017-02-08 16:21:49 -080094 mDrawable = new BatteryMeterDrawableBase(context, frameColor);
John Spurlock29786fc2014-02-04 17:55:47 -050095 atts.recycle();
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040096
Dan Sandler055bb612017-02-08 16:21:49 -080097 mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
98
Jason Monk3e189872016-01-12 09:10:34 -050099 mSlotBattery = context.getString(
100 com.android.internal.R.string.status_bar_battery);
Dan Sandler055bb612017-02-08 16:21:49 -0800101 mBatteryIconView = new ImageView(context);
102 mBatteryIconView.setImageDrawable(mDrawable);
103 final MarginLayoutParams mlp = new MarginLayoutParams(
104 getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width),
105 getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height));
106 mlp.setMargins(0, 0, 0,
107 getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom));
108 addView(mBatteryIconView, mlp);
109
110 updateShowPercent();
Jason Monk9a376bc2017-05-10 09:52:10 -0400111
112 Context dualToneDarkTheme = new ContextThemeWrapper(context,
113 Utils.getThemeAttr(context, R.attr.darkIconTheme));
114 Context dualToneLightTheme = new ContextThemeWrapper(context,
115 Utils.getThemeAttr(context, R.attr.lightIconTheme));
116 mDarkModeBackgroundColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.backgroundColor);
117 mDarkModeFillColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.fillColor);
118 mLightModeBackgroundColor = Utils.getColorAttr(dualToneLightTheme, R.attr.backgroundColor);
119 mLightModeFillColor = Utils.getColorAttr(dualToneLightTheme, R.attr.fillColor);
120
Jason Monkd866b8a2017-03-29 15:30:44 -0400121 // Init to not dark at all.
122 onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Dan Sandler055bb612017-02-08 16:21:49 -0800123 }
124
Dan Sandlerdf14c202017-02-21 14:51:11 -0500125 public void setForceShowPercent(boolean show) {
126 mForceShowPercent = show;
Jason Monkf13413e2017-02-15 15:49:32 -0500127 updateShowPercent();
128 }
129
Jorim Jaggi0d266892014-07-28 14:49:13 +0200130 @Override
131 public boolean hasOverlappingRendering() {
132 return false;
133 }
134
Jason Monkabe19742015-09-29 09:47:06 -0400135 @Override
Jason Monk3e189872016-01-12 09:10:34 -0500136 public void onTuningChanged(String key, String newValue) {
137 if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
138 ArraySet<String> icons = StatusBarIconController.getIconBlacklist(newValue);
139 setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
140 }
141 }
142
143 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400144 public void onAttachedToWindow() {
145 super.onAttachedToWindow();
Jason Monk9c7844c2017-01-18 15:21:53 -0500146 mBatteryController = Dependency.get(BatteryController.class);
Jason Monk9c7844c2017-01-18 15:21:53 -0500147 mBatteryController.addCallback(this);
Dan Sandler055bb612017-02-08 16:21:49 -0800148 getContext().getContentResolver().registerContentObserver(
Evan Lairdbcf631d2017-03-10 10:56:45 -0500149 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver);
Dan Sandler055bb612017-02-08 16:21:49 -0800150 updateShowPercent();
Jason Monkde850bb2017-02-01 19:26:30 -0500151 Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
Jason Monkaa573e92017-01-27 17:00:29 -0500152 Dependency.get(ConfigurationController.class).addCallback(this);
Jason Monkabe19742015-09-29 09:47:06 -0400153 }
John Spurlock3c875662013-08-31 15:07:25 -0400154
155 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400156 public void onDetachedFromWindow() {
157 super.onDetachedFromWindow();
Jason Monk88529052016-11-04 13:29:58 -0400158 mBatteryController.removeCallback(this);
Dan Sandler055bb612017-02-08 16:21:49 -0800159 getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
Jason Monkde850bb2017-02-01 19:26:30 -0500160 Dependency.get(TunerService.class).removeTunable(this);
Jason Monkaa573e92017-01-27 17:00:29 -0500161 Dependency.get(ConfigurationController.class).removeCallback(this);
John Spurlock3c875662013-08-31 15:07:25 -0400162 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400163
Jason Monkabe19742015-09-29 09:47:06 -0400164 @Override
165 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
Dan Sandler055bb612017-02-08 16:21:49 -0800166 mDrawable.setBatteryLevel(level);
jackqdyuleiff5bd942017-04-04 10:54:21 -0700167 mDrawable.setCharging(pluggedIn);
Dan Sandler055bb612017-02-08 16:21:49 -0800168 mLevel = level;
169 updatePercentText();
Jason Monkabe19742015-09-29 09:47:06 -0400170 setContentDescription(
Adrian Roos70dcf832016-04-20 15:51:42 -0700171 getContext().getString(charging ? R.string.accessibility_battery_level_charging
172 : R.string.accessibility_battery_level, level));
John Spurlockf40d08f2015-05-29 10:48:22 -0400173 }
174
Jason Monkabe19742015-09-29 09:47:06 -0400175 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -0500176 public void onPowerSaveChanged(boolean isPowerSave) {
Dan Sandler055bb612017-02-08 16:21:49 -0800177 mDrawable.setPowerSave(isPowerSave);
178 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400179
Dan Sandler055bb612017-02-08 16:21:49 -0800180 private TextView loadPercentView() {
181 return (TextView) LayoutInflater.from(getContext())
182 .inflate(R.layout.battery_percentage_view, null);
183 }
184
185 private void updatePercentText() {
186 if (mBatteryPercentView != null) {
187 mBatteryPercentView.setText(
Jason Monk9a376bc2017-05-10 09:52:10 -0400188 NumberFormat.getPercentInstance().format(mLevel / 100f));
Dan Sandler055bb612017-02-08 16:21:49 -0800189 }
190 }
191
192 private void updateShowPercent() {
193 final boolean showing = mBatteryPercentView != null;
194 if (0 != Settings.System.getInt(getContext().getContentResolver(),
Evan Lairdbcf631d2017-03-10 10:56:45 -0500195 SHOW_BATTERY_PERCENT, 0) || mForceShowPercent) {
Dan Sandler055bb612017-02-08 16:21:49 -0800196 if (!showing) {
197 mBatteryPercentView = loadPercentView();
198 if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
199 updatePercentText();
200 addView(mBatteryPercentView,
Evan Laird09ebefd2017-03-24 10:55:29 -0400201 0,
Dan Sandler055bb612017-02-08 16:21:49 -0800202 new ViewGroup.LayoutParams(
203 LayoutParams.WRAP_CONTENT,
204 LayoutParams.MATCH_PARENT));
205 }
206 } else {
207 if (showing) {
208 removeView(mBatteryPercentView);
209 mBatteryPercentView = null;
210 }
211 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400212 }
213
Jason Monkaa573e92017-01-27 17:00:29 -0500214 @Override
215 public void onDensityOrFontScaleChanged() {
216 scaleBatteryMeterViews();
217 }
218
219 /**
220 * Looks up the scale factor for status bar icons and scales the battery view by that amount.
221 */
222 private void scaleBatteryMeterViews() {
223 Resources res = getContext().getResources();
224 TypedValue typedValue = new TypedValue();
225
226 res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
227 float iconScaleFactor = typedValue.getFloat();
228
229 int batteryHeight = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_height);
230 int batteryWidth = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_width);
231 int marginBottom = res.getDimensionPixelSize(R.dimen.battery_margin_bottom);
232
233 LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
234 (int) (batteryWidth * iconScaleFactor), (int) (batteryHeight * iconScaleFactor));
Dan Sandler055bb612017-02-08 16:21:49 -0800235 scaledLayoutParams.setMargins(0, 0, 0, marginBottom);
Jason Monkaa573e92017-01-27 17:00:29 -0500236
Dan Sandler055bb612017-02-08 16:21:49 -0800237 mBatteryIconView.setLayoutParams(scaledLayoutParams);
Jason Monkaa573e92017-01-27 17:00:29 -0500238 }
239
240 @Override
241 public void onDarkChanged(Rect area, float darkIntensity, int tint) {
Lucas Dupin987f1932017-05-13 21:02:52 -0700242 mDarkIntensity = darkIntensity;
Jason Monk9a376bc2017-05-10 09:52:10 -0400243 float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
244 int foreground = getColorForDarkIntensity(intensity, mLightModeFillColor,
245 mDarkModeFillColor);
246 int background = getColorForDarkIntensity(intensity, mLightModeBackgroundColor,
247 mDarkModeBackgroundColor);
248 mDrawable.setColors(foreground, background);
249 setTextColor(foreground);
Dan Sandler055bb612017-02-08 16:21:49 -0800250 }
251
252 public void setTextColor(int color) {
253 mTextColor = color;
254 if (mBatteryPercentView != null) {
255 mBatteryPercentView.setTextColor(color);
256 }
Jason Monkabe19742015-09-29 09:47:06 -0400257 }
Jason Monk32508852017-01-18 09:17:13 -0500258
Lucas Dupin987f1932017-05-13 21:02:52 -0700259 public void setFillColor(int color) {
260 if (mLightModeFillColor == color) {
261 return;
262 }
263 mLightModeFillColor = color;
264 onDarkChanged(new Rect(), mDarkIntensity, DarkIconDispatcher.DEFAULT_ICON_TINT);
265 }
266
Jason Monk9a376bc2017-05-10 09:52:10 -0400267 private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
268 return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
Jason Monk32508852017-01-18 09:17:13 -0500269 }
Dan Sandler055bb612017-02-08 16:21:49 -0800270
271 private final class SettingObserver extends ContentObserver {
272 public SettingObserver(Handler handler) {
273 super(handler);
274 }
275
276 @Override
277 public void onChange(boolean selfChange, Uri uri) {
278 super.onChange(selfChange, uri);
279 updateShowPercent();
280 }
281 }
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400282}