blob: fd2447bd47b4ac5de9c4bb9682adf56ffd1a55c9 [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;
Jason Monka6f1db3a2017-08-30 19:18:00 -040021import android.app.ActivityManager;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040022import android.content.Context;
Jason Monkaa573e92017-01-27 17:00:29 -050023import android.content.res.Resources;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040024import android.content.res.TypedArray;
Dan Sandler055bb612017-02-08 16:21:49 -080025import android.database.ContentObserver;
Jason Monk9a376bc2017-05-10 09:52:10 -040026import android.graphics.Rect;
Dan Sandler055bb612017-02-08 16:21:49 -080027import android.net.Uri;
28import android.os.Handler;
29import android.provider.Settings;
Jason Monk9a376bc2017-05-10 09:52:10 -040030import android.util.ArraySet;
31import android.util.AttributeSet;
32import android.util.TypedValue;
33import android.view.ContextThemeWrapper;
Dan Sandler055bb612017-02-08 16:21:49 -080034import android.view.Gravity;
35import android.view.LayoutInflater;
Jason Monk3e189872016-01-12 09:10:34 -050036import android.view.View;
Dan Sandler055bb612017-02-08 16:21:49 -080037import android.view.ViewGroup;
Jason Monkabe19742015-09-29 09:47:06 -040038import android.widget.ImageView;
Jason Monkaa573e92017-01-27 17:00:29 -050039import android.widget.LinearLayout;
Dan Sandler055bb612017-02-08 16:21:49 -080040import android.widget.TextView;
Jason Monk9a376bc2017-05-10 09:52:10 -040041
42import com.android.settingslib.Utils;
Dan Sandler055bb612017-02-08 16:21:49 -080043import com.android.settingslib.graph.BatteryMeterDrawableBase;
Jason Monka6f1db3a2017-08-30 19:18:00 -040044import com.android.systemui.settings.CurrentUserTracker;
Jason Monk3e189872016-01-12 09:10:34 -050045import com.android.systemui.statusbar.phone.StatusBarIconController;
Jorim Jaggi708f7722014-08-20 17:30:38 +020046import com.android.systemui.statusbar.policy.BatteryController;
Jason Monkaa573e92017-01-27 17:00:29 -050047import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
48import com.android.systemui.statusbar.policy.ConfigurationController;
49import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
50import com.android.systemui.statusbar.policy.DarkIconDispatcher;
51import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
Jason Monk3e189872016-01-12 09:10:34 -050052import com.android.systemui.tuner.TunerService;
Jason Monkaa573e92017-01-27 17:00:29 -050053import com.android.systemui.tuner.TunerService.Tunable;
Jorim Jaggi708f7722014-08-20 17:30:38 +020054
Dan Sandler055bb612017-02-08 16:21:49 -080055import java.text.NumberFormat;
56
57public class BatteryMeterView extends LinearLayout implements
Jason Monkaa573e92017-01-27 17:00:29 -050058 BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040059
Dan Sandler055bb612017-02-08 16:21:49 -080060 private final BatteryMeterDrawableBase mDrawable;
Jason Monk3e189872016-01-12 09:10:34 -050061 private final String mSlotBattery;
Dan Sandler055bb612017-02-08 16:21:49 -080062 private final ImageView mBatteryIconView;
Jason Monka6f1db3a2017-08-30 19:18:00 -040063 private final CurrentUserTracker mUserTracker;
Dan Sandler055bb612017-02-08 16:21:49 -080064 private TextView mBatteryPercentView;
65
Jorim Jaggi708f7722014-08-20 17:30:38 +020066 private BatteryController mBatteryController;
Dan Sandler055bb612017-02-08 16:21:49 -080067 private SettingObserver mSettingObserver;
68 private int mTextColor;
69 private int mLevel;
Jason Monkf13413e2017-02-15 15:49:32 -050070 private boolean mForceShowPercent;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040071
Jason Monk9a376bc2017-05-10 09:52:10 -040072 private int mDarkModeBackgroundColor;
73 private int mDarkModeFillColor;
74
75 private int mLightModeBackgroundColor;
76 private int mLightModeFillColor;
Lucas Dupin987f1932017-05-13 21:02:52 -070077 private float mDarkIntensity;
Jason Monka6f1db3a2017-08-30 19:18:00 -040078 private int mUser;
Jason Monk9a376bc2017-05-10 09:52:10 -040079
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040080 public BatteryMeterView(Context context) {
81 this(context, null, 0);
82 }
83
84 public BatteryMeterView(Context context, AttributeSet attrs) {
85 this(context, attrs, 0);
86 }
87
88 public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
89 super(context, attrs, defStyle);
90
Dan Sandler055bb612017-02-08 16:21:49 -080091 setOrientation(LinearLayout.HORIZONTAL);
92 setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
93
John Spurlock29786fc2014-02-04 17:55:47 -050094 TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
95 defStyle, 0);
96 final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
Daniel Nishi8af93cb2017-05-15 14:37:20 -070097 context.getColor(R.color.meter_background_color));
Dan Sandler055bb612017-02-08 16:21:49 -080098 mDrawable = new BatteryMeterDrawableBase(context, frameColor);
John Spurlock29786fc2014-02-04 17:55:47 -050099 atts.recycle();
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400100
Dan Sandler055bb612017-02-08 16:21:49 -0800101 mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
102
Jason Monk3e189872016-01-12 09:10:34 -0500103 mSlotBattery = context.getString(
104 com.android.internal.R.string.status_bar_battery);
Dan Sandler055bb612017-02-08 16:21:49 -0800105 mBatteryIconView = new ImageView(context);
106 mBatteryIconView.setImageDrawable(mDrawable);
107 final MarginLayoutParams mlp = new MarginLayoutParams(
108 getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width),
109 getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height));
110 mlp.setMargins(0, 0, 0,
111 getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom));
112 addView(mBatteryIconView, mlp);
113
114 updateShowPercent();
Jason Monk9a376bc2017-05-10 09:52:10 -0400115
116 Context dualToneDarkTheme = new ContextThemeWrapper(context,
117 Utils.getThemeAttr(context, R.attr.darkIconTheme));
118 Context dualToneLightTheme = new ContextThemeWrapper(context,
119 Utils.getThemeAttr(context, R.attr.lightIconTheme));
120 mDarkModeBackgroundColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.backgroundColor);
121 mDarkModeFillColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.fillColor);
122 mLightModeBackgroundColor = Utils.getColorAttr(dualToneLightTheme, R.attr.backgroundColor);
123 mLightModeFillColor = Utils.getColorAttr(dualToneLightTheme, R.attr.fillColor);
124
Jason Monkd866b8a2017-03-29 15:30:44 -0400125 // Init to not dark at all.
126 onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Jason Monka6f1db3a2017-08-30 19:18:00 -0400127 mUserTracker = new CurrentUserTracker(mContext) {
128 @Override
129 public void onUserSwitched(int newUserId) {
130 mUser = newUserId;
131 getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
132 getContext().getContentResolver().registerContentObserver(
133 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver,
134 newUserId);
135 }
136 };
Dan Sandler055bb612017-02-08 16:21:49 -0800137 }
138
Dan Sandlerdf14c202017-02-21 14:51:11 -0500139 public void setForceShowPercent(boolean show) {
140 mForceShowPercent = show;
Jason Monkf13413e2017-02-15 15:49:32 -0500141 updateShowPercent();
142 }
143
Jorim Jaggi0d266892014-07-28 14:49:13 +0200144 @Override
145 public boolean hasOverlappingRendering() {
146 return false;
147 }
148
Jason Monkabe19742015-09-29 09:47:06 -0400149 @Override
Jason Monk3e189872016-01-12 09:10:34 -0500150 public void onTuningChanged(String key, String newValue) {
151 if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
152 ArraySet<String> icons = StatusBarIconController.getIconBlacklist(newValue);
153 setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
154 }
155 }
156
157 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400158 public void onAttachedToWindow() {
159 super.onAttachedToWindow();
Jason Monk9c7844c2017-01-18 15:21:53 -0500160 mBatteryController = Dependency.get(BatteryController.class);
Jason Monk9c7844c2017-01-18 15:21:53 -0500161 mBatteryController.addCallback(this);
Jason Monka6f1db3a2017-08-30 19:18:00 -0400162 mUser = ActivityManager.getCurrentUser();
Dan Sandler055bb612017-02-08 16:21:49 -0800163 getContext().getContentResolver().registerContentObserver(
Jason Monka6f1db3a2017-08-30 19:18:00 -0400164 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
Dan Sandler055bb612017-02-08 16:21:49 -0800165 updateShowPercent();
Jason Monkde850bb2017-02-01 19:26:30 -0500166 Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
Jason Monkaa573e92017-01-27 17:00:29 -0500167 Dependency.get(ConfigurationController.class).addCallback(this);
Jason Monka6f1db3a2017-08-30 19:18:00 -0400168 mUserTracker.startTracking();
Jason Monkabe19742015-09-29 09:47:06 -0400169 }
John Spurlock3c875662013-08-31 15:07:25 -0400170
171 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400172 public void onDetachedFromWindow() {
173 super.onDetachedFromWindow();
Jason Monka6f1db3a2017-08-30 19:18:00 -0400174 mUserTracker.stopTracking();
Jason Monk88529052016-11-04 13:29:58 -0400175 mBatteryController.removeCallback(this);
Dan Sandler055bb612017-02-08 16:21:49 -0800176 getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
Jason Monkde850bb2017-02-01 19:26:30 -0500177 Dependency.get(TunerService.class).removeTunable(this);
Jason Monkaa573e92017-01-27 17:00:29 -0500178 Dependency.get(ConfigurationController.class).removeCallback(this);
John Spurlock3c875662013-08-31 15:07:25 -0400179 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400180
Jason Monkabe19742015-09-29 09:47:06 -0400181 @Override
182 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
Dan Sandler055bb612017-02-08 16:21:49 -0800183 mDrawable.setBatteryLevel(level);
jackqdyuleiff5bd942017-04-04 10:54:21 -0700184 mDrawable.setCharging(pluggedIn);
Dan Sandler055bb612017-02-08 16:21:49 -0800185 mLevel = level;
186 updatePercentText();
Jason Monkabe19742015-09-29 09:47:06 -0400187 setContentDescription(
Adrian Roos70dcf832016-04-20 15:51:42 -0700188 getContext().getString(charging ? R.string.accessibility_battery_level_charging
189 : R.string.accessibility_battery_level, level));
John Spurlockf40d08f2015-05-29 10:48:22 -0400190 }
191
Jason Monkabe19742015-09-29 09:47:06 -0400192 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -0500193 public void onPowerSaveChanged(boolean isPowerSave) {
Dan Sandler055bb612017-02-08 16:21:49 -0800194 mDrawable.setPowerSave(isPowerSave);
195 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400196
Dan Sandler055bb612017-02-08 16:21:49 -0800197 private TextView loadPercentView() {
198 return (TextView) LayoutInflater.from(getContext())
199 .inflate(R.layout.battery_percentage_view, null);
200 }
201
202 private void updatePercentText() {
203 if (mBatteryPercentView != null) {
204 mBatteryPercentView.setText(
Jason Monk9a376bc2017-05-10 09:52:10 -0400205 NumberFormat.getPercentInstance().format(mLevel / 100f));
Dan Sandler055bb612017-02-08 16:21:49 -0800206 }
207 }
208
209 private void updateShowPercent() {
210 final boolean showing = mBatteryPercentView != null;
Jason Monka6f1db3a2017-08-30 19:18:00 -0400211 if (0 != Settings.System.getIntForUser(getContext().getContentResolver(),
212 SHOW_BATTERY_PERCENT, 0, mUser) || mForceShowPercent) {
Dan Sandler055bb612017-02-08 16:21:49 -0800213 if (!showing) {
214 mBatteryPercentView = loadPercentView();
215 if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
216 updatePercentText();
217 addView(mBatteryPercentView,
Evan Laird09ebefd2017-03-24 10:55:29 -0400218 0,
Dan Sandler055bb612017-02-08 16:21:49 -0800219 new ViewGroup.LayoutParams(
220 LayoutParams.WRAP_CONTENT,
221 LayoutParams.MATCH_PARENT));
222 }
223 } else {
224 if (showing) {
225 removeView(mBatteryPercentView);
226 mBatteryPercentView = null;
227 }
228 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400229 }
230
Jason Monkaa573e92017-01-27 17:00:29 -0500231 @Override
232 public void onDensityOrFontScaleChanged() {
233 scaleBatteryMeterViews();
234 }
235
236 /**
237 * Looks up the scale factor for status bar icons and scales the battery view by that amount.
238 */
239 private void scaleBatteryMeterViews() {
240 Resources res = getContext().getResources();
241 TypedValue typedValue = new TypedValue();
242
243 res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
244 float iconScaleFactor = typedValue.getFloat();
245
246 int batteryHeight = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_height);
247 int batteryWidth = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_width);
248 int marginBottom = res.getDimensionPixelSize(R.dimen.battery_margin_bottom);
249
250 LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
251 (int) (batteryWidth * iconScaleFactor), (int) (batteryHeight * iconScaleFactor));
Dan Sandler055bb612017-02-08 16:21:49 -0800252 scaledLayoutParams.setMargins(0, 0, 0, marginBottom);
Jason Monkaa573e92017-01-27 17:00:29 -0500253
Dan Sandler055bb612017-02-08 16:21:49 -0800254 mBatteryIconView.setLayoutParams(scaledLayoutParams);
Evan Lairdecc93f22017-06-16 09:57:29 -0400255 FontSizeUtils.updateFontSize(mBatteryPercentView, R.dimen.qs_time_expanded_size);
Jason Monkaa573e92017-01-27 17:00:29 -0500256 }
257
258 @Override
259 public void onDarkChanged(Rect area, float darkIntensity, int tint) {
Lucas Dupin987f1932017-05-13 21:02:52 -0700260 mDarkIntensity = darkIntensity;
Jason Monk9a376bc2017-05-10 09:52:10 -0400261 float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
262 int foreground = getColorForDarkIntensity(intensity, mLightModeFillColor,
263 mDarkModeFillColor);
264 int background = getColorForDarkIntensity(intensity, mLightModeBackgroundColor,
265 mDarkModeBackgroundColor);
266 mDrawable.setColors(foreground, background);
267 setTextColor(foreground);
Dan Sandler055bb612017-02-08 16:21:49 -0800268 }
269
270 public void setTextColor(int color) {
271 mTextColor = color;
272 if (mBatteryPercentView != null) {
273 mBatteryPercentView.setTextColor(color);
274 }
Jason Monkabe19742015-09-29 09:47:06 -0400275 }
Jason Monk32508852017-01-18 09:17:13 -0500276
Lucas Dupin987f1932017-05-13 21:02:52 -0700277 public void setFillColor(int color) {
278 if (mLightModeFillColor == color) {
279 return;
280 }
281 mLightModeFillColor = color;
282 onDarkChanged(new Rect(), mDarkIntensity, DarkIconDispatcher.DEFAULT_ICON_TINT);
283 }
284
Jason Monk9a376bc2017-05-10 09:52:10 -0400285 private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
286 return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
Jason Monk32508852017-01-18 09:17:13 -0500287 }
Dan Sandler055bb612017-02-08 16:21:49 -0800288
289 private final class SettingObserver extends ContentObserver {
290 public SettingObserver(Handler handler) {
291 super(handler);
292 }
293
294 @Override
295 public void onChange(boolean selfChange, Uri uri) {
296 super.onChange(selfChange, uri);
297 updateShowPercent();
298 }
299 }
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400300}