blob: a46ab3a9e35b6cf280e63eca4dde0b5d3f45edc9 [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
Lucas Dupin8968f6a2019-08-09 17:41:15 -070022import static com.android.systemui.DejankUtils.whitelistIpcs;
Jason Monk8e4e4cb2018-12-04 11:10:24 -050023import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle;
24
Evan Laird4bf21df2018-10-22 14:24:32 -040025import static java.lang.annotation.RetentionPolicy.SOURCE;
26
shawnlinf603ea02019-03-12 15:44:37 +080027import android.animation.LayoutTransition;
28import android.animation.ObjectAnimator;
Evan Laird4bf21df2018-10-22 14:24:32 -040029import android.annotation.IntDef;
Jason Monka6f1db3a2017-08-30 19:18:00 -040030import android.app.ActivityManager;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040031import android.content.Context;
Jason Monkaa573e92017-01-27 17:00:29 -050032import android.content.res.Resources;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040033import android.content.res.TypedArray;
Dan Sandler055bb612017-02-08 16:21:49 -080034import android.database.ContentObserver;
Jason Monk9a376bc2017-05-10 09:52:10 -040035import android.graphics.Rect;
Dan Sandler055bb612017-02-08 16:21:49 -080036import android.net.Uri;
37import android.os.Handler;
38import android.provider.Settings;
Salvador Martinez7de89292019-04-23 14:55:36 -070039import android.text.TextUtils;
Jason Monk9a376bc2017-05-10 09:52:10 -040040import android.util.ArraySet;
41import android.util.AttributeSet;
42import android.util.TypedValue;
Dan Sandler055bb612017-02-08 16:21:49 -080043import android.view.Gravity;
44import android.view.LayoutInflater;
Evan Lairdd3e6b772019-12-12 11:33:17 -050045import android.view.View;
Dan Sandler055bb612017-02-08 16:21:49 -080046import android.view.ViewGroup;
Jason Monkabe19742015-09-29 09:47:06 -040047import android.widget.ImageView;
Jason Monkaa573e92017-01-27 17:00:29 -050048import android.widget.LinearLayout;
Dan Sandler055bb612017-02-08 16:21:49 -080049import android.widget.TextView;
Jason Monk9a376bc2017-05-10 09:52:10 -040050
Fabian Kozynskibca09b72019-04-04 15:57:42 -040051import androidx.annotation.StyleRes;
52
Jason Monk9a376bc2017-05-10 09:52:10 -040053import com.android.settingslib.Utils;
Evan Laird2259da42019-02-08 16:48:53 -050054import com.android.settingslib.graph.ThemedBatteryDrawable;
Fabian Kozynski5ca7a512019-10-16 19:56:11 +000055import com.android.systemui.broadcast.BroadcastDispatcher;
Beverly1be62f42018-12-19 17:17:48 -050056import com.android.systemui.plugins.DarkIconDispatcher;
57import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
Jason Monka6f1db3a2017-08-30 19:18:00 -040058import com.android.systemui.settings.CurrentUserTracker;
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040059import com.android.systemui.statusbar.CommandQueue;
Jason Monk3e189872016-01-12 09:10:34 -050060import com.android.systemui.statusbar.phone.StatusBarIconController;
Jorim Jaggi708f7722014-08-20 17:30:38 +020061import com.android.systemui.statusbar.policy.BatteryController;
Jason Monkaa573e92017-01-27 17:00:29 -050062import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
63import com.android.systemui.statusbar.policy.ConfigurationController;
64import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
Jason Monk3e189872016-01-12 09:10:34 -050065import com.android.systemui.tuner.TunerService;
Jason Monkaa573e92017-01-27 17:00:29 -050066import com.android.systemui.tuner.TunerService.Tunable;
Charles He6a79b0d2017-09-18 09:50:58 +010067import com.android.systemui.util.Utils.DisableStateTracker;
Jorim Jaggi708f7722014-08-20 17:30:38 +020068
Lucas Dupinc510d412018-06-12 13:08:23 -070069import java.io.FileDescriptor;
70import java.io.PrintWriter;
Evan Laird4bf21df2018-10-22 14:24:32 -040071import java.lang.annotation.Retention;
Dan Sandler055bb612017-02-08 16:21:49 -080072import java.text.NumberFormat;
73
74public class BatteryMeterView extends LinearLayout implements
Jason Monkaa573e92017-01-27 17:00:29 -050075 BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -040076
Evan Laird4bf21df2018-10-22 14:24:32 -040077
78 @Retention(SOURCE)
Evan Lairda5a73c52019-01-11 13:36:32 -050079 @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF, MODE_ESTIMATE})
Evan Laird4bf21df2018-10-22 14:24:32 -040080 public @interface BatteryPercentMode {}
81 public static final int MODE_DEFAULT = 0;
82 public static final int MODE_ON = 1;
83 public static final int MODE_OFF = 2;
Evan Lairda5a73c52019-01-11 13:36:32 -050084 public static final int MODE_ESTIMATE = 3;
Evan Laird4bf21df2018-10-22 14:24:32 -040085
Evan Laird2259da42019-02-08 16:48:53 -050086 private final ThemedBatteryDrawable mDrawable;
Jason Monk3e189872016-01-12 09:10:34 -050087 private final String mSlotBattery;
Dan Sandler055bb612017-02-08 16:21:49 -080088 private final ImageView mBatteryIconView;
Jason Monka6f1db3a2017-08-30 19:18:00 -040089 private final CurrentUserTracker mUserTracker;
Dan Sandler055bb612017-02-08 16:21:49 -080090 private TextView mBatteryPercentView;
91
Jorim Jaggi708f7722014-08-20 17:30:38 +020092 private BatteryController mBatteryController;
Dan Sandler055bb612017-02-08 16:21:49 -080093 private SettingObserver mSettingObserver;
Fabian Kozynskibca09b72019-04-04 15:57:42 -040094 private final @StyleRes int mPercentageStyleId;
Dan Sandler055bb612017-02-08 16:21:49 -080095 private int mTextColor;
96 private int mLevel;
Evan Laird4bf21df2018-10-22 14:24:32 -040097 private int mShowPercentMode = MODE_DEFAULT;
Jason Monkf13413e2017-02-15 15:49:32 -050098 private boolean mForceShowPercent;
Evan Laird54ff81b2018-06-13 20:08:17 -040099 private boolean mShowPercentAvailable;
Evan Laird698839b2018-12-05 15:49:12 -0500100 // Some places may need to show the battery conditionally, and not obey the tuner
101 private boolean mIgnoreTunerUpdates;
102 private boolean mIsSubscribedForTunerUpdates;
Evan Lairda5a73c52019-01-11 13:36:32 -0500103 private boolean mCharging;
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400104
Fabian Kozynskif86df992019-04-22 14:23:47 -0400105 private DualToneHandler mDualToneHandler;
Jason Monka6f1db3a2017-08-30 19:18:00 -0400106 private int mUser;
Jason Monk9a376bc2017-05-10 09:52:10 -0400107
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000108 /**
109 * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings.
110 */
111 private boolean mUseWallpaperTextColors;
112
Evan Laird2259da42019-02-08 16:48:53 -0500113 private int mNonAdaptedSingleToneColor;
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000114 private int mNonAdaptedForegroundColor;
115 private int mNonAdaptedBackgroundColor;
116
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400117 public BatteryMeterView(Context context, AttributeSet attrs) {
118 this(context, attrs, 0);
119 }
120
121 public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
122 super(context, attrs, defStyle);
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000123 BroadcastDispatcher broadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400124
Dan Sandler055bb612017-02-08 16:21:49 -0800125 setOrientation(LinearLayout.HORIZONTAL);
126 setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
127
John Spurlock29786fc2014-02-04 17:55:47 -0500128 TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
129 defStyle, 0);
130 final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
Daniel Nishi8af93cb2017-05-15 14:37:20 -0700131 context.getColor(R.color.meter_background_color));
Fabian Kozynskibca09b72019-04-04 15:57:42 -0400132 mPercentageStyleId = atts.getResourceId(R.styleable.BatteryMeterView_textAppearance, 0);
Evan Laird2259da42019-02-08 16:48:53 -0500133 mDrawable = new ThemedBatteryDrawable(context, frameColor);
John Spurlock29786fc2014-02-04 17:55:47 -0500134 atts.recycle();
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400135
Dan Sandler055bb612017-02-08 16:21:49 -0800136 mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
Evan Laird54ff81b2018-06-13 20:08:17 -0400137 mShowPercentAvailable = context.getResources().getBoolean(
138 com.android.internal.R.bool.config_battery_percentage_setting_available);
139
Dan Sandler055bb612017-02-08 16:21:49 -0800140
Charles He6a79b0d2017-09-18 09:50:58 +0100141 addOnAttachStateChangeListener(
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400142 new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS,
143 Dependency.get(CommandQueue.class)));
Charles He6a79b0d2017-09-18 09:50:58 +0100144
shawnlinf603ea02019-03-12 15:44:37 +0800145 setupLayoutTransition();
146
Jason Monk3e189872016-01-12 09:10:34 -0500147 mSlotBattery = context.getString(
148 com.android.internal.R.string.status_bar_battery);
Dan Sandler055bb612017-02-08 16:21:49 -0800149 mBatteryIconView = new ImageView(context);
150 mBatteryIconView.setImageDrawable(mDrawable);
151 final MarginLayoutParams mlp = new MarginLayoutParams(
152 getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width),
153 getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height));
154 mlp.setMargins(0, 0, 0,
155 getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom));
156 addView(mBatteryIconView, mlp);
157
158 updateShowPercent();
Fabian Kozynskif86df992019-04-22 14:23:47 -0400159 mDualToneHandler = new DualToneHandler(context);
Jason Monkd866b8a2017-03-29 15:30:44 -0400160 // Init to not dark at all.
161 onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Evan Lairdef160f22018-01-29 14:08:45 -0500162
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000163 mUserTracker = new CurrentUserTracker(broadcastDispatcher) {
Jason Monka6f1db3a2017-08-30 19:18:00 -0400164 @Override
165 public void onUserSwitched(int newUserId) {
166 mUser = newUserId;
167 getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
168 getContext().getContentResolver().registerContentObserver(
169 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver,
170 newUserId);
Evan Laird6ead1e32018-06-19 13:39:05 -0400171 updateShowPercent();
Jason Monka6f1db3a2017-08-30 19:18:00 -0400172 }
173 };
Evan Laird39ea8102018-05-18 19:49:07 -0400174
175 setClipChildren(false);
176 setClipToPadding(false);
Jason Monk8e4e4cb2018-12-04 11:10:24 -0500177 Dependency.get(ConfigurationController.class).observe(viewAttachLifecycle(this), this);
Dan Sandler055bb612017-02-08 16:21:49 -0800178 }
179
shawnlinf603ea02019-03-12 15:44:37 +0800180 private void setupLayoutTransition() {
181 LayoutTransition transition = new LayoutTransition();
182 transition.setDuration(200);
183
184 ObjectAnimator appearAnimator = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f);
185 transition.setAnimator(LayoutTransition.APPEARING, appearAnimator);
186 transition.setInterpolator(LayoutTransition.APPEARING, Interpolators.ALPHA_IN);
187
188 ObjectAnimator disappearAnimator = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
189 transition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT);
190 transition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnimator);
191
192 setLayoutTransition(transition);
193 }
194
Dan Sandlerdf14c202017-02-21 14:51:11 -0500195 public void setForceShowPercent(boolean show) {
Evan Laird4bf21df2018-10-22 14:24:32 -0400196 setPercentShowMode(show ? MODE_ON : MODE_DEFAULT);
197 }
198
199 /**
200 * Force a particular mode of showing percent
201 *
202 * 0 - No preference
203 * 1 - Force on
204 * 2 - Force off
205 * @param mode desired mode (none, on, off)
206 */
207 public void setPercentShowMode(@BatteryPercentMode int mode) {
208 mShowPercentMode = mode;
Jason Monkf13413e2017-02-15 15:49:32 -0500209 updateShowPercent();
210 }
211
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000212 /**
Evan Laird698839b2018-12-05 15:49:12 -0500213 * Set {@code true} to turn off BatteryMeterView's subscribing to the tuner for updates, and
214 * thus avoid it controlling its own visibility
215 *
216 * @param ignore whether to ignore the tuner or not
217 */
218 public void setIgnoreTunerUpdates(boolean ignore) {
219 mIgnoreTunerUpdates = ignore;
220 updateTunerSubscription();
221 }
222
223 private void updateTunerSubscription() {
224 if (mIgnoreTunerUpdates) {
225 unsubscribeFromTunerUpdates();
226 } else {
227 subscribeForTunerUpdates();
228 }
229 }
230
231 private void subscribeForTunerUpdates() {
232 if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) {
233 return;
234 }
235
236 Dependency.get(TunerService.class)
237 .addTunable(this, StatusBarIconController.ICON_BLACKLIST);
238 mIsSubscribedForTunerUpdates = true;
239 }
240
241 private void unsubscribeFromTunerUpdates() {
242 if (!mIsSubscribedForTunerUpdates) {
243 return;
244 }
245
246 Dependency.get(TunerService.class).removeTunable(this);
247 mIsSubscribedForTunerUpdates = false;
248 }
249
250 /**
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000251 * Sets whether the battery meter view uses the wallpaperTextColor. If we're not using it, we'll
252 * revert back to dark-mode-based/tinted colors.
253 *
254 * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for all
255 * components
256 */
257 public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) {
258 if (shouldUseWallpaperTextColor == mUseWallpaperTextColors) {
259 return;
260 }
261
262 mUseWallpaperTextColors = shouldUseWallpaperTextColor;
263
264 if (mUseWallpaperTextColors) {
265 updateColors(
Jason Changb4e879d2018-04-11 11:17:58 +0800266 Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor),
Evan Laird2259da42019-02-08 16:48:53 -0500267 Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColorSecondary),
268 Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor));
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000269 } else {
Evan Laird2259da42019-02-08 16:48:53 -0500270 updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
271 mNonAdaptedSingleToneColor);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000272 }
273 }
274
Evan Lairdef160f22018-01-29 14:08:45 -0500275 public void setColorsFromContext(Context context) {
276 if (context == null) {
277 return;
278 }
279
Fabian Kozynskif86df992019-04-22 14:23:47 -0400280 mDualToneHandler.setColorsFromContext(context);
Evan Lairdef160f22018-01-29 14:08:45 -0500281 }
282
Jorim Jaggi0d266892014-07-28 14:49:13 +0200283 @Override
284 public boolean hasOverlappingRendering() {
285 return false;
286 }
287
Jason Monkabe19742015-09-29 09:47:06 -0400288 @Override
Jason Monk3e189872016-01-12 09:10:34 -0500289 public void onTuningChanged(String key, String newValue) {
290 if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
JianYang Liue8df04c2020-01-13 10:45:12 -0800291 ArraySet<String> icons = StatusBarIconController.getIconBlacklist(
292 getContext(), newValue);
Evan Lairdd3e6b772019-12-12 11:33:17 -0500293 setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
Jason Monk3e189872016-01-12 09:10:34 -0500294 }
295 }
296
297 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400298 public void onAttachedToWindow() {
299 super.onAttachedToWindow();
Jason Monk9c7844c2017-01-18 15:21:53 -0500300 mBatteryController = Dependency.get(BatteryController.class);
Jason Monk9c7844c2017-01-18 15:21:53 -0500301 mBatteryController.addCallback(this);
Jason Monka6f1db3a2017-08-30 19:18:00 -0400302 mUser = ActivityManager.getCurrentUser();
Dan Sandler055bb612017-02-08 16:21:49 -0800303 getContext().getContentResolver().registerContentObserver(
Jason Monka6f1db3a2017-08-30 19:18:00 -0400304 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
Salvador Martinez7de89292019-04-23 14:55:36 -0700305 getContext().getContentResolver().registerContentObserver(
306 Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME),
307 false, mSettingObserver);
Dan Sandler055bb612017-02-08 16:21:49 -0800308 updateShowPercent();
Evan Laird698839b2018-12-05 15:49:12 -0500309 subscribeForTunerUpdates();
Jason Monka6f1db3a2017-08-30 19:18:00 -0400310 mUserTracker.startTracking();
Jason Monkabe19742015-09-29 09:47:06 -0400311 }
John Spurlock3c875662013-08-31 15:07:25 -0400312
313 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400314 public void onDetachedFromWindow() {
315 super.onDetachedFromWindow();
Jason Monka6f1db3a2017-08-30 19:18:00 -0400316 mUserTracker.stopTracking();
Jason Monk88529052016-11-04 13:29:58 -0400317 mBatteryController.removeCallback(this);
Dan Sandler055bb612017-02-08 16:21:49 -0800318 getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
Evan Laird698839b2018-12-05 15:49:12 -0500319 unsubscribeFromTunerUpdates();
John Spurlock3c875662013-08-31 15:07:25 -0400320 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400321
Jason Monkabe19742015-09-29 09:47:06 -0400322 @Override
323 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
jackqdyuleiff5bd942017-04-04 10:54:21 -0700324 mDrawable.setCharging(pluggedIn);
Evan Laird2259da42019-02-08 16:48:53 -0500325 mDrawable.setBatteryLevel(level);
Evan Lairda5a73c52019-01-11 13:36:32 -0500326 mCharging = pluggedIn;
Dan Sandler055bb612017-02-08 16:21:49 -0800327 mLevel = level;
328 updatePercentText();
John Spurlockf40d08f2015-05-29 10:48:22 -0400329 }
330
Jason Monkabe19742015-09-29 09:47:06 -0400331 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -0500332 public void onPowerSaveChanged(boolean isPowerSave) {
Evan Laird2259da42019-02-08 16:48:53 -0500333 mDrawable.setPowerSaveEnabled(isPowerSave);
Dan Sandler055bb612017-02-08 16:21:49 -0800334 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400335
Dan Sandler055bb612017-02-08 16:21:49 -0800336 private TextView loadPercentView() {
337 return (TextView) LayoutInflater.from(getContext())
338 .inflate(R.layout.battery_percentage_view, null);
339 }
340
Fabian Kozynski648e5552018-12-18 16:37:08 -0500341 /**
342 * Updates percent view by removing old one and reinflating if necessary
343 */
344 public void updatePercentView() {
345 if (mBatteryPercentView != null) {
346 removeView(mBatteryPercentView);
347 mBatteryPercentView = null;
348 }
349 updateShowPercent();
350 }
351
Dan Sandler055bb612017-02-08 16:21:49 -0800352 private void updatePercentText() {
Evan Lairda5a73c52019-01-11 13:36:32 -0500353 if (mBatteryController == null) {
354 return;
355 }
356
Dan Sandler055bb612017-02-08 16:21:49 -0800357 if (mBatteryPercentView != null) {
Evan Lairda5a73c52019-01-11 13:36:32 -0500358 if (mShowPercentMode == MODE_ESTIMATE && !mCharging) {
359 mBatteryController.getEstimatedTimeRemainingString((String estimate) -> {
Evan Laird85ee4a32019-03-06 18:09:20 -0500360 if (estimate != null) {
361 mBatteryPercentView.setText(estimate);
Amin Shaikh0fcc3372019-05-29 14:08:41 -0400362 setContentDescription(getContext().getString(
Amin Shaikh44386742019-05-31 08:53:50 -0400363 R.string.accessibility_battery_level_with_estimate,
364 mLevel, estimate));
Evan Laird85ee4a32019-03-06 18:09:20 -0500365 } else {
366 setPercentTextAtCurrentLevel();
367 }
Evan Lairda5a73c52019-01-11 13:36:32 -0500368 });
369 } else {
Evan Laird85ee4a32019-03-06 18:09:20 -0500370 setPercentTextAtCurrentLevel();
Evan Lairda5a73c52019-01-11 13:36:32 -0500371 }
Evan Laird7839fe82019-06-14 13:27:54 -0400372 } else {
373 setContentDescription(
374 getContext().getString(mCharging ? R.string.accessibility_battery_level_charging
375 : R.string.accessibility_battery_level, mLevel));
Dan Sandler055bb612017-02-08 16:21:49 -0800376 }
377 }
378
Evan Laird85ee4a32019-03-06 18:09:20 -0500379 private void setPercentTextAtCurrentLevel() {
380 mBatteryPercentView.setText(
381 NumberFormat.getPercentInstance().format(mLevel / 100f));
Amin Shaikh0fcc3372019-05-29 14:08:41 -0400382 setContentDescription(
383 getContext().getString(mCharging ? R.string.accessibility_battery_level_charging
384 : R.string.accessibility_battery_level, mLevel));
Evan Laird85ee4a32019-03-06 18:09:20 -0500385 }
386
Dan Sandler055bb612017-02-08 16:21:49 -0800387 private void updateShowPercent() {
388 final boolean showing = mBatteryPercentView != null;
Lucas Dupin8968f6a2019-08-09 17:41:15 -0700389 // TODO(b/140051051)
390 final boolean systemSetting = 0 != whitelistIpcs(() -> Settings.System
Evan Laird54ff81b2018-06-13 20:08:17 -0400391 .getIntForUser(getContext().getContentResolver(),
Lucas Dupin8968f6a2019-08-09 17:41:15 -0700392 SHOW_BATTERY_PERCENT, 0, mUser));
Evan Laird54ff81b2018-06-13 20:08:17 -0400393
Evan Laird4bf21df2018-10-22 14:24:32 -0400394 if ((mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
Evan Lairda5a73c52019-01-11 13:36:32 -0500395 || mShowPercentMode == MODE_ON || mShowPercentMode == MODE_ESTIMATE) {
Dan Sandler055bb612017-02-08 16:21:49 -0800396 if (!showing) {
397 mBatteryPercentView = loadPercentView();
Fabian Kozynskibca09b72019-04-04 15:57:42 -0400398 if (mPercentageStyleId != 0) { // Only set if specified as attribute
399 mBatteryPercentView.setTextAppearance(mPercentageStyleId);
400 }
Fabian Kozynski7c35d332019-04-12 09:24:13 -0400401 if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
Dan Sandler055bb612017-02-08 16:21:49 -0800402 updatePercentText();
403 addView(mBatteryPercentView,
Dan Sandler055bb612017-02-08 16:21:49 -0800404 new ViewGroup.LayoutParams(
405 LayoutParams.WRAP_CONTENT,
406 LayoutParams.MATCH_PARENT));
407 }
408 } else {
409 if (showing) {
410 removeView(mBatteryPercentView);
411 mBatteryPercentView = null;
412 }
413 }
John Spurlockf40d08f2015-05-29 10:48:22 -0400414 }
415
Jason Monkaa573e92017-01-27 17:00:29 -0500416 @Override
417 public void onDensityOrFontScaleChanged() {
418 scaleBatteryMeterViews();
419 }
420
421 /**
422 * Looks up the scale factor for status bar icons and scales the battery view by that amount.
423 */
424 private void scaleBatteryMeterViews() {
425 Resources res = getContext().getResources();
426 TypedValue typedValue = new TypedValue();
427
428 res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
429 float iconScaleFactor = typedValue.getFloat();
430
431 int batteryHeight = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_height);
432 int batteryWidth = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_width);
433 int marginBottom = res.getDimensionPixelSize(R.dimen.battery_margin_bottom);
434
435 LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
436 (int) (batteryWidth * iconScaleFactor), (int) (batteryHeight * iconScaleFactor));
Dan Sandler055bb612017-02-08 16:21:49 -0800437 scaledLayoutParams.setMargins(0, 0, 0, marginBottom);
Jason Monkaa573e92017-01-27 17:00:29 -0500438
Dan Sandler055bb612017-02-08 16:21:49 -0800439 mBatteryIconView.setLayoutParams(scaledLayoutParams);
Jason Monkaa573e92017-01-27 17:00:29 -0500440 }
441
442 @Override
443 public void onDarkChanged(Rect area, float darkIntensity, int tint) {
Jason Monk9a376bc2017-05-10 09:52:10 -0400444 float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
Fabian Kozynskif86df992019-04-22 14:23:47 -0400445 mNonAdaptedSingleToneColor = mDualToneHandler.getSingleColor(intensity);
446 mNonAdaptedForegroundColor = mDualToneHandler.getFillColor(intensity);
447 mNonAdaptedBackgroundColor = mDualToneHandler.getBackgroundColor(intensity);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000448
449 if (!mUseWallpaperTextColors) {
Evan Laird2259da42019-02-08 16:48:53 -0500450 updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
451 mNonAdaptedSingleToneColor);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000452 }
Dan Sandler055bb612017-02-08 16:21:49 -0800453 }
454
Evan Laird2259da42019-02-08 16:48:53 -0500455 private void updateColors(int foregroundColor, int backgroundColor, int singleToneColor) {
456 mDrawable.setColors(foregroundColor, backgroundColor, singleToneColor);
457 mTextColor = singleToneColor;
Dan Sandler055bb612017-02-08 16:21:49 -0800458 if (mBatteryPercentView != null) {
Evan Laird2259da42019-02-08 16:48:53 -0500459 mBatteryPercentView.setTextColor(singleToneColor);
Dan Sandler055bb612017-02-08 16:21:49 -0800460 }
Jason Monkabe19742015-09-29 09:47:06 -0400461 }
Jason Monk32508852017-01-18 09:17:13 -0500462
Lucas Dupinc510d412018-06-12 13:08:23 -0700463 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Evan Laird2259da42019-02-08 16:48:53 -0500464 String powerSave = mDrawable == null ? null : mDrawable.getPowerSaveEnabled() + "";
Lucas Dupinc510d412018-06-12 13:08:23 -0700465 CharSequence percent = mBatteryPercentView == null ? null : mBatteryPercentView.getText();
466 pw.println(" BatteryMeterView:");
467 pw.println(" mDrawable.getPowerSave: " + powerSave);
468 pw.println(" mBatteryPercentView.getText(): " + percent);
469 pw.println(" mTextColor: #" + Integer.toHexString(mTextColor));
470 pw.println(" mLevel: " + mLevel);
471 pw.println(" mForceShowPercent: " + mForceShowPercent);
472 }
473
Dan Sandler055bb612017-02-08 16:21:49 -0800474 private final class SettingObserver extends ContentObserver {
475 public SettingObserver(Handler handler) {
476 super(handler);
477 }
478
479 @Override
480 public void onChange(boolean selfChange, Uri uri) {
481 super.onChange(selfChange, uri);
482 updateShowPercent();
Salvador Martinez7de89292019-04-23 14:55:36 -0700483 if (TextUtils.equals(uri.getLastPathSegment(),
484 Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)) {
485 // update the text for sure if the estimate in the cache was updated
486 updatePercentText();
487 }
Dan Sandler055bb612017-02-08 16:21:49 -0800488 }
489 }
Daniel Sandlerdfaf3bd2013-04-12 01:39:02 -0400490}