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:
Evan Laird
2019-01-11 13:36:32 -05:00
parent 5af6efd9de
commit a5a73c5a9e
6 changed files with 96 additions and 79 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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);
}
}

View File

@@ -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();