diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml index 2000104ad0cd2..74002ac38c021 100644 --- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml +++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml @@ -51,11 +51,4 @@ android:layout_width="wrap_content" android:paddingEnd="2dp" /> - - diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml index 4b65b6a013f82..cd9f780ca2492 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml @@ -64,11 +64,5 @@ - diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 6864ea185834c..9c62686564e7b 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -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); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 28285e14ef4b3..75ab5dfd2977d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -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 { 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 f65f8261dcfb7..5e94152e7eab5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -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); } } 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 6190c8fff8cce..af3c96f736429 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -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 mChangeCallbacks = new ArrayList<>(); + private final ArrayList 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();