blob: 59501f0970c249a0cfb4d99232d56a6eabaa12a1 [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
Charles He6a79b0d2017-09-18 09:50:58 +010018import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
19import static android.app.StatusBarManager.DISABLE_NONE;
Evan Lairdbcf631d2017-03-10 10:56:45 -050020import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
21
Jason Monk9a376bc2017-05-10 09:52:10 -040022import android.animation.ArgbEvaluator;
Jason Monka6f1db3a2017-08-30 19:18:00 -040023import android.app.ActivityManager;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040024import android.content.Context;
Jason Monkaa573e92017-01-27 17:00:29 -050025import android.content.res.Resources;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040026import android.content.res.TypedArray;
Dan Sandler055bb612017-02-08 16:21:49 -080027import android.database.ContentObserver;
Jason Monk9a376bc2017-05-10 09:52:10 -040028import android.graphics.Rect;
Dan Sandler055bb612017-02-08 16:21:49 -080029import android.net.Uri;
30import android.os.Handler;
31import android.provider.Settings;
Jason Monk9a376bc2017-05-10 09:52:10 -040032import android.util.ArraySet;
33import android.util.AttributeSet;
34import android.util.TypedValue;
35import android.view.ContextThemeWrapper;
Dan Sandler055bb612017-02-08 16:21:49 -080036import android.view.Gravity;
37import android.view.LayoutInflater;
Jason Monk3e189872016-01-12 09:10:34 -050038import android.view.View;
Dan Sandler055bb612017-02-08 16:21:49 -080039import android.view.ViewGroup;
Jason Monkabe19742015-09-29 09:47:06 -040040import android.widget.ImageView;
Jason Monkaa573e92017-01-27 17:00:29 -050041import android.widget.LinearLayout;
Dan Sandler055bb612017-02-08 16:21:49 -080042import android.widget.TextView;
Jason Monk9a376bc2017-05-10 09:52:10 -040043
44import com.android.settingslib.Utils;
Dan Sandler055bb612017-02-08 16:21:49 -080045import com.android.settingslib.graph.BatteryMeterDrawableBase;
Jason Monka6f1db3a2017-08-30 19:18:00 -040046import com.android.systemui.settings.CurrentUserTracker;
Jason Monk3e189872016-01-12 09:10:34 -050047import com.android.systemui.statusbar.phone.StatusBarIconController;
Jorim Jaggi708f7722014-08-20 17:30:38 +020048import com.android.systemui.statusbar.policy.BatteryController;
Jason Monkaa573e92017-01-27 17:00:29 -050049import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
50import com.android.systemui.statusbar.policy.ConfigurationController;
51import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
52import com.android.systemui.statusbar.policy.DarkIconDispatcher;
53import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
Jason Monkf8c2f7b2017-09-06 09:22:29 -040054import com.android.systemui.statusbar.policy.IconLogger;
Jason Monk3e189872016-01-12 09:10:34 -050055import com.android.systemui.tuner.TunerService;
Jason Monkaa573e92017-01-27 17:00:29 -050056import com.android.systemui.tuner.TunerService.Tunable;
Charles He6a79b0d2017-09-18 09:50:58 +010057import com.android.systemui.util.Utils.DisableStateTracker;
Jorim Jaggi708f7722014-08-20 17:30:38 +020058
Dan Sandler055bb612017-02-08 16:21:49 -080059import java.text.NumberFormat;
60
61public class BatteryMeterView extends LinearLayout implements
Jason Monkaa573e92017-01-27 17:00:29 -050062 BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040063
Dan Sandler055bb612017-02-08 16:21:49 -080064 private final BatteryMeterDrawableBase mDrawable;
Jason Monk3e189872016-01-12 09:10:34 -050065 private final String mSlotBattery;
Dan Sandler055bb612017-02-08 16:21:49 -080066 private final ImageView mBatteryIconView;
Jason Monka6f1db3a2017-08-30 19:18:00 -040067 private final CurrentUserTracker mUserTracker;
Dan Sandler055bb612017-02-08 16:21:49 -080068 private TextView mBatteryPercentView;
69
Jorim Jaggi708f7722014-08-20 17:30:38 +020070 private BatteryController mBatteryController;
Dan Sandler055bb612017-02-08 16:21:49 -080071 private SettingObserver mSettingObserver;
72 private int mTextColor;
73 private int mLevel;
Jason Monkf13413e2017-02-15 15:49:32 -050074 private boolean mForceShowPercent;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040075
Jason Monk9a376bc2017-05-10 09:52:10 -040076 private int mDarkModeBackgroundColor;
77 private int mDarkModeFillColor;
78
79 private int mLightModeBackgroundColor;
80 private int mLightModeFillColor;
Lucas Dupin987f1932017-05-13 21:02:52 -070081 private float mDarkIntensity;
Jason Monka6f1db3a2017-08-30 19:18:00 -040082 private int mUser;
Jason Monk9a376bc2017-05-10 09:52:10 -040083
Rohan Shahcc3d1d82018-03-30 21:24:17 +000084 /**
85 * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings.
86 */
87 private boolean mUseWallpaperTextColors;
88
89 private int mNonAdaptedForegroundColor;
90 private int mNonAdaptedBackgroundColor;
91
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040092 public BatteryMeterView(Context context) {
93 this(context, null, 0);
94 }
95
96 public BatteryMeterView(Context context, AttributeSet attrs) {
97 this(context, attrs, 0);
98 }
99
100 public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
101 super(context, attrs, defStyle);
102
Dan Sandler055bb612017-02-08 16:21:49 -0800103 setOrientation(LinearLayout.HORIZONTAL);
104 setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
105
John Spurlock29786fc2014-02-04 17:55:47 -0500106 TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
107 defStyle, 0);
108 final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
Daniel Nishi8af93cb2017-05-15 14:37:20 -0700109 context.getColor(R.color.meter_background_color));
Dan Sandler055bb612017-02-08 16:21:49 -0800110 mDrawable = new BatteryMeterDrawableBase(context, frameColor);
John Spurlock29786fc2014-02-04 17:55:47 -0500111 atts.recycle();
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400112
Dan Sandler055bb612017-02-08 16:21:49 -0800113 mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
114
Charles He6a79b0d2017-09-18 09:50:58 +0100115 addOnAttachStateChangeListener(
116 new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS));
117
Jason Monk3e189872016-01-12 09:10:34 -0500118 mSlotBattery = context.getString(
119 com.android.internal.R.string.status_bar_battery);
Dan Sandler055bb612017-02-08 16:21:49 -0800120 mBatteryIconView = new ImageView(context);
121 mBatteryIconView.setImageDrawable(mDrawable);
122 final MarginLayoutParams mlp = new MarginLayoutParams(
123 getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width),
124 getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height));
125 mlp.setMargins(0, 0, 0,
126 getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom));
127 addView(mBatteryIconView, mlp);
128
129 updateShowPercent();
Evan Lairdef160f22018-01-29 14:08:45 -0500130 setColorsFromContext(context);
Jason Monkd866b8a2017-03-29 15:30:44 -0400131 // Init to not dark at all.
132 onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Evan Lairdef160f22018-01-29 14:08:45 -0500133
Jason Monka6f1db3a2017-08-30 19:18:00 -0400134 mUserTracker = new CurrentUserTracker(mContext) {
135 @Override
136 public void onUserSwitched(int newUserId) {
137 mUser = newUserId;
138 getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
139 getContext().getContentResolver().registerContentObserver(
140 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver,
141 newUserId);
142 }
143 };
Evan Laird39ea8102018-05-18 19:49:07 -0400144
145 setClipChildren(false);
146 setClipToPadding(false);
Dan Sandler055bb612017-02-08 16:21:49 -0800147 }
148
Dan Sandlerdf14c202017-02-21 14:51:11 -0500149 public void setForceShowPercent(boolean show) {
150 mForceShowPercent = show;
Jason Monkf13413e2017-02-15 15:49:32 -0500151 updateShowPercent();
152 }
153
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000154 /**
155 * Sets whether the battery meter view uses the wallpaperTextColor. If we're not using it, we'll
156 * revert back to dark-mode-based/tinted colors.
157 *
158 * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for all
159 * components
160 */
161 public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) {
162 if (shouldUseWallpaperTextColor == mUseWallpaperTextColors) {
163 return;
164 }
165
166 mUseWallpaperTextColors = shouldUseWallpaperTextColor;
167
168 if (mUseWallpaperTextColors) {
169 updateColors(
170 Utils.getColorAttr(mContext, R.attr.wallpaperTextColor),
171 Utils.getColorAttr(mContext, R.attr.wallpaperTextColorSecondary));
172 } else {
173 updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor);
174 }
175 }
176
Evan Lairdef160f22018-01-29 14:08:45 -0500177 public void setColorsFromContext(Context context) {
178 if (context == null) {
179 return;
180 }
181
182 Context dualToneDarkTheme = new ContextThemeWrapper(context,
183 Utils.getThemeAttr(context, R.attr.darkIconTheme));
184 Context dualToneLightTheme = new ContextThemeWrapper(context,
185 Utils.getThemeAttr(context, R.attr.lightIconTheme));
186 mDarkModeBackgroundColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.backgroundColor);
187 mDarkModeFillColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.fillColor);
188 mLightModeBackgroundColor = Utils.getColorAttr(dualToneLightTheme, R.attr.backgroundColor);
189 mLightModeFillColor = Utils.getColorAttr(dualToneLightTheme, R.attr.fillColor);
190 }
191
Jorim Jaggi0d266892014-07-28 14:49:13 +0200192 @Override
193 public boolean hasOverlappingRendering() {
194 return false;
195 }
196
Jason Monkabe19742015-09-29 09:47:06 -0400197 @Override
Jason Monk3e189872016-01-12 09:10:34 -0500198 public void onTuningChanged(String key, String newValue) {
199 if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
200 ArraySet<String> icons = StatusBarIconController.getIconBlacklist(newValue);
Jason Monkf8c2f7b2017-09-06 09:22:29 -0400201 boolean hidden = icons.contains(mSlotBattery);
202 Dependency.get(IconLogger.class).onIconVisibility(mSlotBattery, !hidden);
203 setVisibility(hidden ? View.GONE : View.VISIBLE);
Jason Monk3e189872016-01-12 09:10:34 -0500204 }
205 }
206
207 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400208 public void onAttachedToWindow() {
209 super.onAttachedToWindow();
Jason Monk9c7844c2017-01-18 15:21:53 -0500210 mBatteryController = Dependency.get(BatteryController.class);
Jason Monk9c7844c2017-01-18 15:21:53 -0500211 mBatteryController.addCallback(this);
Jason Monka6f1db3a2017-08-30 19:18:00 -0400212 mUser = ActivityManager.getCurrentUser();
Dan Sandler055bb612017-02-08 16:21:49 -0800213 getContext().getContentResolver().registerContentObserver(
Jason Monka6f1db3a2017-08-30 19:18:00 -0400214 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
Dan Sandler055bb612017-02-08 16:21:49 -0800215 updateShowPercent();
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000216 Dependency.get(TunerService.class)
217 .addTunable(this, StatusBarIconController.ICON_BLACKLIST);
Jason Monkaa573e92017-01-27 17:00:29 -0500218 Dependency.get(ConfigurationController.class).addCallback(this);
Jason Monka6f1db3a2017-08-30 19:18:00 -0400219 mUserTracker.startTracking();
Jason Monkabe19742015-09-29 09:47:06 -0400220 }
John Spurlock3c875662013-08-31 15:07:25 -0400221
222 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400223 public void onDetachedFromWindow() {
224 super.onDetachedFromWindow();
Jason Monka6f1db3a2017-08-30 19:18:00 -0400225 mUserTracker.stopTracking();
Jason Monk88529052016-11-04 13:29:58 -0400226 mBatteryController.removeCallback(this);
Dan Sandler055bb612017-02-08 16:21:49 -0800227 getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
Jason Monkde850bb2017-02-01 19:26:30 -0500228 Dependency.get(TunerService.class).removeTunable(this);
Jason Monkaa573e92017-01-27 17:00:29 -0500229 Dependency.get(ConfigurationController.class).removeCallback(this);
John Spurlock3c875662013-08-31 15:07:25 -0400230 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400231
Jason Monkabe19742015-09-29 09:47:06 -0400232 @Override
233 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
Dan Sandler055bb612017-02-08 16:21:49 -0800234 mDrawable.setBatteryLevel(level);
jackqdyuleiff5bd942017-04-04 10:54:21 -0700235 mDrawable.setCharging(pluggedIn);
Dan Sandler055bb612017-02-08 16:21:49 -0800236 mLevel = level;
237 updatePercentText();
Jason Monkabe19742015-09-29 09:47:06 -0400238 setContentDescription(
Adrian Roos70dcf832016-04-20 15:51:42 -0700239 getContext().getString(charging ? R.string.accessibility_battery_level_charging
240 : R.string.accessibility_battery_level, level));
John Spurlockf40d08f2015-05-29 10:48:22 -0400241 }
242
Jason Monkabe19742015-09-29 09:47:06 -0400243 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -0500244 public void onPowerSaveChanged(boolean isPowerSave) {
Dan Sandler055bb612017-02-08 16:21:49 -0800245 mDrawable.setPowerSave(isPowerSave);
246 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400247
Dan Sandler055bb612017-02-08 16:21:49 -0800248 private TextView loadPercentView() {
249 return (TextView) LayoutInflater.from(getContext())
250 .inflate(R.layout.battery_percentage_view, null);
251 }
252
253 private void updatePercentText() {
254 if (mBatteryPercentView != null) {
255 mBatteryPercentView.setText(
Jason Monk9a376bc2017-05-10 09:52:10 -0400256 NumberFormat.getPercentInstance().format(mLevel / 100f));
Dan Sandler055bb612017-02-08 16:21:49 -0800257 }
258 }
259
260 private void updateShowPercent() {
261 final boolean showing = mBatteryPercentView != null;
Jason Monka6f1db3a2017-08-30 19:18:00 -0400262 if (0 != Settings.System.getIntForUser(getContext().getContentResolver(),
263 SHOW_BATTERY_PERCENT, 0, mUser) || mForceShowPercent) {
Dan Sandler055bb612017-02-08 16:21:49 -0800264 if (!showing) {
265 mBatteryPercentView = loadPercentView();
266 if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
267 updatePercentText();
268 addView(mBatteryPercentView,
Dan Sandler055bb612017-02-08 16:21:49 -0800269 new ViewGroup.LayoutParams(
270 LayoutParams.WRAP_CONTENT,
271 LayoutParams.MATCH_PARENT));
272 }
273 } else {
274 if (showing) {
275 removeView(mBatteryPercentView);
276 mBatteryPercentView = null;
277 }
278 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400279 }
280
Jason Monkaa573e92017-01-27 17:00:29 -0500281 @Override
282 public void onDensityOrFontScaleChanged() {
283 scaleBatteryMeterViews();
284 }
285
286 /**
287 * Looks up the scale factor for status bar icons and scales the battery view by that amount.
288 */
289 private void scaleBatteryMeterViews() {
290 Resources res = getContext().getResources();
291 TypedValue typedValue = new TypedValue();
292
293 res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
294 float iconScaleFactor = typedValue.getFloat();
295
296 int batteryHeight = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_height);
297 int batteryWidth = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_width);
298 int marginBottom = res.getDimensionPixelSize(R.dimen.battery_margin_bottom);
299
300 LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
301 (int) (batteryWidth * iconScaleFactor), (int) (batteryHeight * iconScaleFactor));
Dan Sandler055bb612017-02-08 16:21:49 -0800302 scaledLayoutParams.setMargins(0, 0, 0, marginBottom);
Jason Monkaa573e92017-01-27 17:00:29 -0500303
Dan Sandler055bb612017-02-08 16:21:49 -0800304 mBatteryIconView.setLayoutParams(scaledLayoutParams);
Evan Lairdecc93f22017-06-16 09:57:29 -0400305 FontSizeUtils.updateFontSize(mBatteryPercentView, R.dimen.qs_time_expanded_size);
Jason Monkaa573e92017-01-27 17:00:29 -0500306 }
307
308 @Override
309 public void onDarkChanged(Rect area, float darkIntensity, int tint) {
Lucas Dupin987f1932017-05-13 21:02:52 -0700310 mDarkIntensity = darkIntensity;
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000311
Jason Monk9a376bc2017-05-10 09:52:10 -0400312 float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000313 mNonAdaptedForegroundColor = getColorForDarkIntensity(
314 intensity, mLightModeFillColor, mDarkModeFillColor);
315 mNonAdaptedBackgroundColor = getColorForDarkIntensity(
316 intensity, mLightModeBackgroundColor,mDarkModeBackgroundColor);
317
318 if (!mUseWallpaperTextColors) {
319 updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor);
320 }
Dan Sandler055bb612017-02-08 16:21:49 -0800321 }
322
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000323 private void updateColors(int foregroundColor, int backgroundColor) {
324 mDrawable.setColors(foregroundColor, backgroundColor);
325 mTextColor = foregroundColor;
Dan Sandler055bb612017-02-08 16:21:49 -0800326 if (mBatteryPercentView != null) {
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000327 mBatteryPercentView.setTextColor(foregroundColor);
Dan Sandler055bb612017-02-08 16:21:49 -0800328 }
Jason Monkabe19742015-09-29 09:47:06 -0400329 }
Jason Monk32508852017-01-18 09:17:13 -0500330
Lucas Dupin987f1932017-05-13 21:02:52 -0700331 public void setFillColor(int color) {
332 if (mLightModeFillColor == color) {
333 return;
334 }
335 mLightModeFillColor = color;
336 onDarkChanged(new Rect(), mDarkIntensity, DarkIconDispatcher.DEFAULT_ICON_TINT);
337 }
338
Jason Monk9a376bc2017-05-10 09:52:10 -0400339 private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
340 return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
Jason Monk32508852017-01-18 09:17:13 -0500341 }
Dan Sandler055bb612017-02-08 16:21:49 -0800342
343 private final class SettingObserver extends ContentObserver {
344 public SettingObserver(Handler handler) {
345 super(handler);
346 }
347
348 @Override
349 public void onChange(boolean selfChange, Uri uri) {
350 super.onChange(selfChange, uri);
351 updateShowPercent();
352 }
353 }
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400354}