Move battery % down in QS, fix a lot of things
- Move the battery percentage next to the system icons in quick settings - Always show the percentage, and optionally show the estimate text based on battery settings - Move the estimate text into the BatteryMeterView - Move the fetching of the estimate off of the main thread Test: visual Change-Id: Ie37952079b2394c67464f69eb8a2f0089b08875d Fixes: 119799219 - padding Fixes: 120996084 - moving estimate fetch off main thread Bug: 116481529
This commit is contained in:
@@ -51,11 +51,4 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:paddingEnd="2dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/batteryRemainingText"
|
||||
android:textAppearance="@style/TextAppearance.QS.TileLabel"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:gravity="center_vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -64,11 +64,5 @@
|
||||
|
||||
<include layout="@layout/ongoing_privacy_chip" />
|
||||
|
||||
<com.android.systemui.BatteryMeterView
|
||||
android:id="@+id/battery"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:gravity="center_vertical|end"
|
||||
android:layout_gravity="center_vertical|end" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -71,11 +71,12 @@ public class BatteryMeterView extends LinearLayout implements
|
||||
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF})
|
||||
@IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF, MODE_ESTIMATE})
|
||||
public @interface BatteryPercentMode {}
|
||||
public static final int MODE_DEFAULT = 0;
|
||||
public static final int MODE_ON = 1;
|
||||
public static final int MODE_OFF = 2;
|
||||
public static final int MODE_ESTIMATE = 3;
|
||||
|
||||
private final BatteryMeterDrawableBase mDrawable;
|
||||
private final String mSlotBattery;
|
||||
@@ -93,6 +94,7 @@ public class BatteryMeterView extends LinearLayout implements
|
||||
// Some places may need to show the battery conditionally, and not obey the tuner
|
||||
private boolean mIgnoreTunerUpdates;
|
||||
private boolean mIsSubscribedForTunerUpdates;
|
||||
private boolean mCharging;
|
||||
|
||||
private int mDarkModeBackgroundColor;
|
||||
private int mDarkModeFillColor;
|
||||
@@ -308,6 +310,7 @@ public class BatteryMeterView extends LinearLayout implements
|
||||
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
|
||||
mDrawable.setBatteryLevel(level);
|
||||
mDrawable.setCharging(pluggedIn);
|
||||
mCharging = pluggedIn;
|
||||
mLevel = level;
|
||||
updatePercentText();
|
||||
setContentDescription(
|
||||
@@ -337,9 +340,19 @@ public class BatteryMeterView extends LinearLayout implements
|
||||
}
|
||||
|
||||
private void updatePercentText() {
|
||||
if (mBatteryController == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBatteryPercentView != null) {
|
||||
mBatteryPercentView.setText(
|
||||
NumberFormat.getPercentInstance().format(mLevel / 100f));
|
||||
if (mShowPercentMode == MODE_ESTIMATE && !mCharging) {
|
||||
mBatteryController.getEstimatedTimeRemainingString((String estimate) -> {
|
||||
mBatteryPercentView.setText(estimate);
|
||||
});
|
||||
} else {
|
||||
mBatteryPercentView.setText(
|
||||
NumberFormat.getPercentInstance().format(mLevel / 100f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +363,7 @@ public class BatteryMeterView extends LinearLayout implements
|
||||
SHOW_BATTERY_PERCENT, 0, mUser);
|
||||
|
||||
if ((mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
|
||||
|| mShowPercentMode == MODE_ON) {
|
||||
|| mShowPercentMode == MODE_ON || mShowPercentMode == MODE_ESTIMATE) {
|
||||
if (!showing) {
|
||||
mBatteryPercentView = loadPercentView();
|
||||
if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
|
||||
|
||||
@@ -141,14 +141,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
private View mStatusSeparator;
|
||||
private ImageView mRingerModeIcon;
|
||||
private TextView mRingerModeTextView;
|
||||
private BatteryMeterView mBatteryMeterView;
|
||||
private Clock mClockView;
|
||||
private DateView mDateView;
|
||||
private OngoingPrivacyChip mPrivacyChip;
|
||||
private Space mSpace;
|
||||
private BatteryMeterView mBatteryRemainingIcon;
|
||||
private TextView mBatteryRemainingText;
|
||||
private boolean mShowBatteryPercentAndEstimate;
|
||||
|
||||
private PrivacyItemController mPrivacyItemController;
|
||||
/** Counts how many times the long press tooltip has been shown to the user. */
|
||||
@@ -229,13 +226,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
// 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.setPercentShowMode(mShowBatteryPercentAndEstimate
|
||||
? BatteryMeterView.MODE_ON : BatteryMeterView.MODE_OFF);
|
||||
mBatteryMeterView.setOnClickListener(this);
|
||||
mClockView = findViewById(R.id.clock);
|
||||
mClockView.setOnClickListener(this);
|
||||
mDateView = findViewById(R.id.date);
|
||||
@@ -245,13 +235,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
|
||||
// Tint for the battery icons are handled in setupHost()
|
||||
mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
|
||||
mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_OFF);
|
||||
// Don't need to worry about tuner settings for this icon
|
||||
mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
|
||||
|
||||
mBatteryRemainingText = findViewById(R.id.batteryRemainingText);
|
||||
mBatteryRemainingText.setTextColor(fillColor);
|
||||
|
||||
updateShowPercent();
|
||||
}
|
||||
|
||||
@@ -268,10 +253,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
}
|
||||
|
||||
private void setChipVisibility(boolean chipVisible) {
|
||||
mBatteryMeterView.setVisibility(View.VISIBLE);
|
||||
if (chipVisible) {
|
||||
mPrivacyChip.setVisibility(View.VISIBLE);
|
||||
if (mHasTopCutout) mBatteryMeterView.setVisibility(View.GONE);
|
||||
} else {
|
||||
mPrivacyChip.setVisibility(View.GONE);
|
||||
}
|
||||
@@ -339,7 +322,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
// Update color schemes in landscape to use wallpaperTextColor
|
||||
boolean shouldUseWallpaperTextColor =
|
||||
newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
|
||||
mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor);
|
||||
mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
|
||||
}
|
||||
|
||||
@@ -415,13 +397,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
.build();
|
||||
}
|
||||
|
||||
private void updateBatteryRemainingText() {
|
||||
if (!mShowBatteryPercentAndEstimate) {
|
||||
return;
|
||||
}
|
||||
mBatteryRemainingText.setText(mBatteryController.getEstimatedTimeRemainingString());
|
||||
}
|
||||
|
||||
public void setExpanded(boolean expanded) {
|
||||
if (mExpanded == expanded) return;
|
||||
mExpanded = expanded;
|
||||
@@ -519,7 +494,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
}
|
||||
}
|
||||
mSpace.setLayoutParams(lp);
|
||||
// Decide whether to show BatteryMeterView
|
||||
setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
|
||||
return super.onApplyWindowInsets(insets);
|
||||
}
|
||||
@@ -546,7 +520,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
mAlarmController.addCallback(this);
|
||||
mContext.registerReceiver(mRingerReceiver,
|
||||
new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
|
||||
updateBatteryRemainingText();
|
||||
} else {
|
||||
mZenController.removeCallback(this);
|
||||
mAlarmController.removeCallback(this);
|
||||
@@ -559,9 +532,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
if (v == mClockView) {
|
||||
mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
|
||||
AlarmClock.ACTION_SHOW_ALARMS),0);
|
||||
} else if (v == mBatteryMeterView) {
|
||||
mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
|
||||
Intent.ACTION_POWER_USAGE_SUMMARY),0);
|
||||
} else if (v == mPrivacyChip) {
|
||||
Handler mUiHandler = new Handler(Looper.getMainLooper());
|
||||
mUiHandler.post(() -> {
|
||||
@@ -713,9 +683,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
|
||||
mHeaderQsPanel.setHost(host, null /* No customization in header */);
|
||||
|
||||
// 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(),
|
||||
@@ -763,22 +730,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
|
||||
.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);
|
||||
}
|
||||
mBatteryRemainingIcon.setPercentShowMode(systemSetting
|
||||
? BatteryMeterView.MODE_ESTIMATE : BatteryMeterView.MODE_ON);
|
||||
}
|
||||
|
||||
private final class PercentSettingObserver extends ContentObserver {
|
||||
|
||||
@@ -48,18 +48,36 @@ public interface BatteryController extends DemoMode, Dumpable,
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener that will be notified whenever a change in battery level or power save mode
|
||||
* has occurred.
|
||||
* A listener that will be notified whenever a change in battery level or power save mode has
|
||||
* occurred.
|
||||
*/
|
||||
interface BatteryStateChangeCallback {
|
||||
default void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {}
|
||||
default void onPowerSaveChanged(boolean isPowerSave) {}
|
||||
|
||||
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
|
||||
* If available, get the estimated battery time remaining as a string.
|
||||
*
|
||||
* @param completion A lambda that will be called with the result of fetching the estimate. The
|
||||
* first time this method is called may need to be dispatched to a background thread. The
|
||||
* completion is called on the main thread
|
||||
*/
|
||||
default String getEstimatedTimeRemainingString() {
|
||||
return null;
|
||||
default void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) {}
|
||||
|
||||
/**
|
||||
* Callback called when the estimated time remaining text is fetched.
|
||||
*/
|
||||
public interface EstimateFetchCompletion {
|
||||
|
||||
/**
|
||||
* The callback
|
||||
* @param estimate the estimate
|
||||
*/
|
||||
void onBatteryRemainingEstimateRetrieved(String estimate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,12 @@ import android.os.PowerManager;
|
||||
import android.os.PowerSaveState;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
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;
|
||||
|
||||
@@ -56,6 +59,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
|
||||
|
||||
private final EnhancedEstimates mEstimates;
|
||||
private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
|
||||
private final ArrayList<EstimateFetchCompletion> mFetchCallbacks = new ArrayList<>();
|
||||
private final PowerManager mPowerManager;
|
||||
private final Handler mHandler;
|
||||
private final Context mContext;
|
||||
@@ -70,6 +74,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
|
||||
private boolean mHasReceivedBattery = false;
|
||||
private Estimate mEstimate;
|
||||
private long mLastEstimateTimestamp = -1;
|
||||
private boolean mFetchingEstimate = false;
|
||||
|
||||
@Inject
|
||||
public BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates) {
|
||||
@@ -197,20 +202,61 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEstimatedTimeRemainingString() {
|
||||
if (mEstimate == null
|
||||
|| System.currentTimeMillis() > mLastEstimateTimestamp + UPDATE_GRANULARITY_MSEC) {
|
||||
updateEstimate();
|
||||
public void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) {
|
||||
if (mEstimate != null
|
||||
&& mLastEstimateTimestamp > System.currentTimeMillis() - UPDATE_GRANULARITY_MSEC) {
|
||||
String percentage = generateTimeRemainingString();
|
||||
completion.onBatteryRemainingEstimateRetrieved(percentage);
|
||||
return;
|
||||
}
|
||||
// Estimates may not exist yet even if we've checked
|
||||
|
||||
// Need to fetch or refresh the estimate, but it may involve binder calls so offload the
|
||||
// work
|
||||
synchronized (mFetchCallbacks) {
|
||||
mFetchCallbacks.add(completion);
|
||||
}
|
||||
updateEstimateInBackground();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String generateTimeRemainingString() {
|
||||
if (mEstimate == null) {
|
||||
return null;
|
||||
}
|
||||
final String percentage = NumberFormat.getPercentInstance().format((double) mLevel / 100.0);
|
||||
|
||||
String percentage = NumberFormat.getPercentInstance().format((double) mLevel / 100.0);
|
||||
return PowerUtil.getBatteryRemainingShortStringFormatted(
|
||||
mContext, mEstimate.estimateMillis);
|
||||
}
|
||||
|
||||
private void updateEstimateInBackground() {
|
||||
if (mFetchingEstimate) {
|
||||
// Already dispatched a fetch. It will notify all listeners when finished
|
||||
return;
|
||||
}
|
||||
|
||||
mFetchingEstimate = true;
|
||||
Dependency.get(Dependency.BG_HANDLER).post(() -> {
|
||||
mEstimate = mEstimates.getEstimate();
|
||||
mLastEstimateTimestamp = System.currentTimeMillis();
|
||||
mFetchingEstimate = false;
|
||||
|
||||
Dependency.get(Dependency.MAIN_HANDLER).post(this::notifyEstimateFetchCallbacks);
|
||||
});
|
||||
}
|
||||
|
||||
private void notifyEstimateFetchCallbacks() {
|
||||
String estimate = generateTimeRemainingString();
|
||||
|
||||
synchronized (mFetchCallbacks) {
|
||||
for (EstimateFetchCompletion completion : mFetchCallbacks) {
|
||||
completion.onBatteryRemainingEstimateRetrieved(estimate);
|
||||
}
|
||||
|
||||
mFetchCallbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateEstimate() {
|
||||
mEstimate = mEstimates.getEstimate();
|
||||
mLastEstimateTimestamp = System.currentTimeMillis();
|
||||
|
||||
Reference in New Issue
Block a user