Add estimated time remaining text to QS
- Add an API to BatteryController to get an estimated time remaining
string.
- BatteryController will now check up to once per minute what the
estimated time will be and builds the string using PowerUtil.
- If the "show percentage" setting is on, the estimated time remaining
string (and battery icon) will show next to the system icons in QS
- Also make the battery percent in QS obey the setting
Test: visual
Bug: 116481529
Change-Id: Iaafa00127c8b8baae40956254a1237c8b7ac079b
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index f6fec54..053ea67 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -19,7 +19,10 @@
import static android.app.StatusBarManager.DISABLE_NONE;
import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
import android.animation.ArgbEvaluator;
+import android.annotation.IntDef;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
@@ -55,15 +58,23 @@
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.Utils.DisableStateTracker;
-import com.android.systemui.R;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
import java.text.NumberFormat;
public class BatteryMeterView extends LinearLayout implements
BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
+
+ @Retention(SOURCE)
+ @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF})
+ public @interface BatteryPercentMode {}
+ public static final int MODE_DEFAULT = 0;
+ public static final int MODE_ON = 1;
+ public static final int MODE_OFF = 2;
+
private final BatteryMeterDrawableBase mDrawable;
private final String mSlotBattery;
private final ImageView mBatteryIconView;
@@ -74,6 +85,7 @@
private SettingObserver mSettingObserver;
private int mTextColor;
private int mLevel;
+ private int mShowPercentMode = MODE_DEFAULT;
private boolean mForceShowPercent;
private boolean mShowPercentAvailable;
@@ -154,7 +166,19 @@
}
public void setForceShowPercent(boolean show) {
- mForceShowPercent = show;
+ setPercentShowMode(show ? MODE_ON : MODE_DEFAULT);
+ }
+
+ /**
+ * Force a particular mode of showing percent
+ *
+ * 0 - No preference
+ * 1 - Force on
+ * 2 - Force off
+ * @param mode desired mode (none, on, off)
+ */
+ public void setPercentShowMode(@BatteryPercentMode int mode) {
+ mShowPercentMode = mode;
updateShowPercent();
}
@@ -273,7 +297,8 @@
.getIntForUser(getContext().getContentResolver(),
SHOW_BATTERY_PERCENT, 0, mUser);
- if ((mShowPercentAvailable && systemSetting) || mForceShowPercent) {
+ if ((mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
+ || mShowPercentMode == MODE_ON) {
if (!showing) {
mBatteryPercentView = loadPercentView();
if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 7929099..e3f85d9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -15,6 +15,7 @@
package com.android.systemui.qs;
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
+import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -28,12 +29,15 @@
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.graphics.Color;
import android.graphics.Rect;
import android.media.AudioManager;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.AlarmClock;
+import android.provider.Settings;
import android.service.notification.ZenModeConfig;
import android.text.format.DateUtils;
import android.util.AttributeSet;
@@ -68,6 +72,7 @@
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
@@ -132,6 +137,9 @@
private DateView mDateView;
private OngoingPrivacyChip mPrivacyChip;
private Space mSpace;
+ private BatteryMeterView mBatteryRemainingIcon;
+ private TextView mBatteryRemainingText;
+ private boolean mShowBatteryPercentAndEstimate;
private NextAlarmController mAlarmController;
private ZenModeController mZenController;
@@ -148,6 +156,9 @@
};
private boolean mHasTopCutout = false;
+ private final PercentSettingObserver mPercentSettingObserver =
+ new PercentSettingObserver(new Handler(mContext.getMainLooper()));
+
/**
* Runnable for automatically fading out the long press tooltip (as if it were animating away).
*/
@@ -204,8 +215,12 @@
// Set the correct tint for the status icons so they contrast
mIconManager.setTint(fillColor);
+ mShowBatteryPercentAndEstimate = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_battery_percentage_setting_available);
+
mBatteryMeterView = findViewById(R.id.battery);
- mBatteryMeterView.setForceShowPercent(true);
+ mBatteryMeterView.setPercentShowMode(mShowBatteryPercentAndEstimate
+ ? BatteryMeterView.MODE_ON : BatteryMeterView.MODE_OFF);
mBatteryMeterView.setOnClickListener(this);
mClockView = findViewById(R.id.clock);
mClockView.setOnClickListener(this);
@@ -213,6 +228,15 @@
mPrivacyChip = findViewById(R.id.privacy_chip);
mPrivacyChip.setOnClickListener(this);
mSpace = findViewById(R.id.space);
+
+ // Tint for the battery icons are handled in setupHost()
+ mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
+ mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_OFF);
+
+ mBatteryRemainingText = findViewById(R.id.batteryRemainingText);
+ mBatteryRemainingText.setTextColor(fillColor);
+
+ updateShowPercent();
}
private void updateStatusText() {
@@ -371,6 +395,14 @@
.build();
}
+ private void updateBatteryRemainingText() {
+ if (!mShowBatteryPercentAndEstimate) {
+ return;
+ }
+ mBatteryRemainingText.setText(
+ Dependency.get(BatteryController.class).getEstimatedTimeRemainingString());
+ }
+
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
@@ -436,6 +468,9 @@
super.onAttachedToWindow();
Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
requestApplyInsets();
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mPercentSettingObserver,
+ ActivityManager.getCurrentUser());
}
@Override
@@ -475,6 +510,7 @@
public void onDetachedFromWindow() {
setListening(false);
Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager);
+ mContext.getContentResolver().unregisterContentObserver(mPercentSettingObserver);
super.onDetachedFromWindow();
}
@@ -491,6 +527,7 @@
mAlarmController.addCallback(this);
mContext.registerReceiver(mRingerReceiver,
new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
+ updateBatteryRemainingText();
} else {
mZenController.removeCallback(this);
mAlarmController.removeCallback(this);
@@ -660,6 +697,14 @@
// Use SystemUI context to get battery meter colors, and let it use the default tint (white)
mBatteryMeterView.setColorsFromContext(mHost.getContext());
mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
+
+ Rect tintArea = new Rect(0, 0, 0, 0);
+ int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
+ android.R.attr.colorForeground);
+ float intensity = getColorIntensity(colorForeground);
+ int fillColor = fillColorForIntensity(intensity, getContext());
+ mBatteryRemainingIcon.setColorsFromContext(mHost.getContext());
+ mBatteryRemainingIcon.onDarkChanged(tintArea, intensity, fillColor);
}
public void setCallback(Callback qsPanelCallback) {
@@ -692,4 +737,39 @@
lp.rightMargin = sideMargins;
}
}
+
+ private void updateShowPercent() {
+ final boolean systemSetting = 0 != Settings.System
+ .getIntForUser(getContext().getContentResolver(),
+ SHOW_BATTERY_PERCENT, 0, ActivityManager.getCurrentUser());
+
+ mShowBatteryPercentAndEstimate = systemSetting;
+
+ updateBatteryViews();
+ }
+
+ private void updateBatteryViews() {
+ if (mShowBatteryPercentAndEstimate) {
+ mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ON);
+ mBatteryRemainingIcon.setVisibility(View.VISIBLE);
+ mBatteryRemainingText.setVisibility(View.VISIBLE);
+ updateBatteryRemainingText();
+ } else {
+ mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_OFF);
+ mBatteryRemainingIcon.setVisibility(View.GONE);
+ mBatteryRemainingText.setVisibility(View.GONE);
+ }
+ }
+
+ private final class PercentSettingObserver extends ContentObserver {
+ PercentSettingObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ updateShowPercent();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 7f3537c..da2828e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -20,6 +20,7 @@
import android.graphics.drawable.Drawable;
import android.service.quicksettings.Tile;
import android.widget.Switch;
+
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.graph.BatteryMeterDrawableBase;
import com.android.systemui.Dependency;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 6f4026d..f65f826 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -55,4 +55,11 @@
default void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {}
default void onPowerSaveChanged(boolean isPowerSave) {}
}
+
+ /**
+ * If available, get the estimated battery time remaining as a string
+ */
+ default String getEstimatedTimeRemainingString() {
+ return null;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 7221efa..ddcfbf6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -29,9 +29,14 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
+import com.android.settingslib.utils.PowerUtil;
+import com.android.systemui.Dependency;
+import com.android.systemui.power.EnhancedEstimates;
+import com.android.systemui.power.Estimate;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.text.NumberFormat;
import java.util.ArrayList;
/**
@@ -44,7 +49,9 @@
public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final int UPDATE_GRANULARITY_MSEC = 1000 * 60;
+ private final EnhancedEstimates mEstimates = Dependency.get(EnhancedEstimates.class);
private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
private final PowerManager mPowerManager;
private final Handler mHandler;
@@ -58,6 +65,8 @@
protected boolean mAodPowerSave;
private boolean mTestmode = false;
private boolean mHasReceivedBattery = false;
+ private Estimate mEstimate;
+ private long mLastEstimateTimestamp = -1;
public BatteryControllerImpl(Context context) {
this(context, context.getSystemService(PowerManager.class));
@@ -71,6 +80,7 @@
registerReceiver();
updatePowerSave();
+ updateEstimate();
}
private void registerReceiver() {
@@ -180,6 +190,26 @@
return mAodPowerSave;
}
+ @Override
+ public String getEstimatedTimeRemainingString() {
+ if (mEstimate == null
+ || System.currentTimeMillis() > mLastEstimateTimestamp + UPDATE_GRANULARITY_MSEC) {
+ updateEstimate();
+ }
+ // Estimates may not exist yet even if we've checked
+ if (mEstimate == null) {
+ return null;
+ }
+ final String percentage = NumberFormat.getPercentInstance().format((double) mLevel / 100.0);
+ return PowerUtil.getBatteryRemainingShortStringFormatted(
+ mContext, mEstimate.estimateMillis);
+ }
+
+ private void updateEstimate() {
+ mEstimate = mEstimates.getEstimate();
+ mLastEstimateTimestamp = System.currentTimeMillis();
+ }
+
private void updatePowerSave() {
setPowerSave(mPowerManager.isPowerSaveMode());
}