Files
frameworks_base/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
Fabian Kozynski bca09b7c00 Visual changes to QS header
Change TextAppearance in QS header.

Also, reduce size of QS tile background. Removed extra padding in the
bottom of QSIconViewImpl that was not needed.

Test: visual
Bug: 124466915
Change-Id: I0b8db6edad7f8527caff76f9419c42a8016a6bda
2019-04-08 13:21:12 -04:00

503 lines
19 KiB
Java

/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui;
import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
import static android.app.StatusBarManager.DISABLE_NONE;
import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.animation.ArgbEvaluator;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.annotation.IntDef;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.StyleRes;
import com.android.settingslib.Utils;
import com.android.settingslib.graph.ThemedBatteryDrawable;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.Utils.DisableStateTracker;
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, 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 ThemedBatteryDrawable mDrawable;
private final String mSlotBattery;
private final ImageView mBatteryIconView;
private final CurrentUserTracker mUserTracker;
private TextView mBatteryPercentView;
private BatteryController mBatteryController;
private SettingObserver mSettingObserver;
private final @StyleRes int mPercentageStyleId;
private int mTextColor;
private int mLevel;
private int mShowPercentMode = MODE_DEFAULT;
private boolean mForceShowPercent;
private boolean mShowPercentAvailable;
// 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 mDarkModeSingleToneColor;
private int mDarkModeBackgroundColor;
private int mDarkModeFillColor;
private int mLightModeSingleToneColor;
private int mLightModeBackgroundColor;
private int mLightModeFillColor;
private int mUser;
/**
* Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings.
*/
private boolean mUseWallpaperTextColors;
private int mNonAdaptedSingleToneColor;
private int mNonAdaptedForegroundColor;
private int mNonAdaptedBackgroundColor;
public BatteryMeterView(Context context) {
this(context, null, 0);
}
public BatteryMeterView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setOrientation(LinearLayout.HORIZONTAL);
setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
defStyle, 0);
final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
context.getColor(R.color.meter_background_color));
mPercentageStyleId = atts.getResourceId(R.styleable.BatteryMeterView_textAppearance, 0);
mDrawable = new ThemedBatteryDrawable(context, frameColor);
atts.recycle();
mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
mShowPercentAvailable = context.getResources().getBoolean(
com.android.internal.R.bool.config_battery_percentage_setting_available);
addOnAttachStateChangeListener(
new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS));
setupLayoutTransition();
mSlotBattery = context.getString(
com.android.internal.R.string.status_bar_battery);
mBatteryIconView = new ImageView(context);
mBatteryIconView.setImageDrawable(mDrawable);
final MarginLayoutParams mlp = new MarginLayoutParams(
getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width),
getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height));
mlp.setMargins(0, 0, 0,
getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom));
addView(mBatteryIconView, mlp);
updateShowPercent();
setColorsFromContext(context);
// Init to not dark at all.
onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
mUserTracker = new CurrentUserTracker(mContext) {
@Override
public void onUserSwitched(int newUserId) {
mUser = newUserId;
getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
getContext().getContentResolver().registerContentObserver(
Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver,
newUserId);
updateShowPercent();
}
};
setClipChildren(false);
setClipToPadding(false);
Dependency.get(ConfigurationController.class).observe(viewAttachLifecycle(this), this);
// Needed for PorderDuff.Mode.CLEAR operations to work properly, but redraws don't happen
// enough to justify a hardware layer.
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
private void setupLayoutTransition() {
LayoutTransition transition = new LayoutTransition();
transition.setDuration(200);
ObjectAnimator appearAnimator = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f);
transition.setAnimator(LayoutTransition.APPEARING, appearAnimator);
transition.setInterpolator(LayoutTransition.APPEARING, Interpolators.ALPHA_IN);
ObjectAnimator disappearAnimator = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
transition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT);
transition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnimator);
setLayoutTransition(transition);
}
public void setForceShowPercent(boolean 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();
}
/**
* Set {@code true} to turn off BatteryMeterView's subscribing to the tuner for updates, and
* thus avoid it controlling its own visibility
*
* @param ignore whether to ignore the tuner or not
*/
public void setIgnoreTunerUpdates(boolean ignore) {
mIgnoreTunerUpdates = ignore;
updateTunerSubscription();
}
private void updateTunerSubscription() {
if (mIgnoreTunerUpdates) {
unsubscribeFromTunerUpdates();
} else {
subscribeForTunerUpdates();
}
}
private void subscribeForTunerUpdates() {
if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) {
return;
}
Dependency.get(TunerService.class)
.addTunable(this, StatusBarIconController.ICON_BLACKLIST);
mIsSubscribedForTunerUpdates = true;
}
private void unsubscribeFromTunerUpdates() {
if (!mIsSubscribedForTunerUpdates) {
return;
}
Dependency.get(TunerService.class).removeTunable(this);
mIsSubscribedForTunerUpdates = false;
}
/**
* Sets whether the battery meter view uses the wallpaperTextColor. If we're not using it, we'll
* revert back to dark-mode-based/tinted colors.
*
* @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for all
* components
*/
public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) {
if (shouldUseWallpaperTextColor == mUseWallpaperTextColors) {
return;
}
mUseWallpaperTextColors = shouldUseWallpaperTextColor;
if (mUseWallpaperTextColors) {
updateColors(
Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor),
Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColorSecondary),
Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor));
} else {
updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
mNonAdaptedSingleToneColor);
}
}
public void setColorsFromContext(Context context) {
if (context == null) {
return;
}
Context dualToneDarkTheme = new ContextThemeWrapper(context,
Utils.getThemeAttr(context, R.attr.darkIconTheme));
Context dualToneLightTheme = new ContextThemeWrapper(context,
Utils.getThemeAttr(context, R.attr.lightIconTheme));
mDarkModeSingleToneColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
R.attr.singleToneColor);
mDarkModeBackgroundColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
R.attr.backgroundColor);
mDarkModeFillColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
R.attr.fillColor);
mLightModeSingleToneColor = Utils.getColorAttrDefaultColor(dualToneLightTheme,
R.attr.singleToneColor);
mLightModeBackgroundColor = Utils.getColorAttrDefaultColor(dualToneLightTheme,
R.attr.backgroundColor);
mLightModeFillColor = Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.fillColor);
}
@Override
public boolean hasOverlappingRendering() {
return false;
}
@Override
public void onTuningChanged(String key, String newValue) {
if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
ArraySet<String> icons = StatusBarIconController.getIconBlacklist(newValue);
}
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mBatteryController = Dependency.get(BatteryController.class);
mBatteryController.addCallback(this);
mUser = ActivityManager.getCurrentUser();
getContext().getContentResolver().registerContentObserver(
Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
updateShowPercent();
subscribeForTunerUpdates();
mUserTracker.startTracking();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mUserTracker.stopTracking();
mBatteryController.removeCallback(this);
getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
unsubscribeFromTunerUpdates();
}
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
mDrawable.setCharging(pluggedIn);
mDrawable.setBatteryLevel(level);
mCharging = pluggedIn;
mLevel = level;
updatePercentText();
setContentDescription(
getContext().getString(charging ? R.string.accessibility_battery_level_charging
: R.string.accessibility_battery_level, level));
}
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
mDrawable.setPowerSaveEnabled(isPowerSave);
}
private TextView loadPercentView() {
return (TextView) LayoutInflater.from(getContext())
.inflate(R.layout.battery_percentage_view, null);
}
/**
* Updates percent view by removing old one and reinflating if necessary
*/
public void updatePercentView() {
if (mBatteryPercentView != null) {
removeView(mBatteryPercentView);
mBatteryPercentView = null;
}
updateShowPercent();
}
private void updatePercentText() {
if (mBatteryController == null) {
return;
}
if (mBatteryPercentView != null) {
if (mShowPercentMode == MODE_ESTIMATE && !mCharging) {
mBatteryController.getEstimatedTimeRemainingString((String estimate) -> {
if (estimate != null) {
mBatteryPercentView.setText(estimate);
} else {
setPercentTextAtCurrentLevel();
}
});
} else {
setPercentTextAtCurrentLevel();
}
}
}
private void setPercentTextAtCurrentLevel() {
mBatteryPercentView.setText(
NumberFormat.getPercentInstance().format(mLevel / 100f));
}
private void updateShowPercent() {
final boolean showing = mBatteryPercentView != null;
final boolean systemSetting = 0 != Settings.System
.getIntForUser(getContext().getContentResolver(),
SHOW_BATTERY_PERCENT, 0, mUser);
if ((mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
|| mShowPercentMode == MODE_ON || mShowPercentMode == MODE_ESTIMATE) {
if (!showing) {
mBatteryPercentView = loadPercentView();
if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
if (mPercentageStyleId != 0) { // Only set if specified as attribute
mBatteryPercentView.setTextAppearance(mPercentageStyleId);
}
updatePercentText();
addView(mBatteryPercentView,
new ViewGroup.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT));
}
} else {
if (showing) {
removeView(mBatteryPercentView);
mBatteryPercentView = null;
}
}
}
@Override
public void onDensityOrFontScaleChanged() {
scaleBatteryMeterViews();
}
/**
* Looks up the scale factor for status bar icons and scales the battery view by that amount.
*/
private void scaleBatteryMeterViews() {
Resources res = getContext().getResources();
TypedValue typedValue = new TypedValue();
res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
float iconScaleFactor = typedValue.getFloat();
int batteryHeight = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_height);
int batteryWidth = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_width);
int marginBottom = res.getDimensionPixelSize(R.dimen.battery_margin_bottom);
LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
(int) (batteryWidth * iconScaleFactor), (int) (batteryHeight * iconScaleFactor));
scaledLayoutParams.setMargins(0, 0, 0, marginBottom);
mBatteryIconView.setLayoutParams(scaledLayoutParams);
}
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
mNonAdaptedSingleToneColor = getColorForDarkIntensity(
intensity, mLightModeSingleToneColor, mDarkModeSingleToneColor);
mNonAdaptedForegroundColor = getColorForDarkIntensity(
intensity, mLightModeFillColor, mDarkModeFillColor);
mNonAdaptedBackgroundColor = getColorForDarkIntensity(
intensity, mLightModeBackgroundColor,mDarkModeBackgroundColor);
if (!mUseWallpaperTextColors) {
updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
mNonAdaptedSingleToneColor);
}
}
private void updateColors(int foregroundColor, int backgroundColor, int singleToneColor) {
mDrawable.setColors(foregroundColor, backgroundColor, singleToneColor);
mTextColor = singleToneColor;
if (mBatteryPercentView != null) {
mBatteryPercentView.setTextColor(singleToneColor);
}
}
private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
String powerSave = mDrawable == null ? null : mDrawable.getPowerSaveEnabled() + "";
CharSequence percent = mBatteryPercentView == null ? null : mBatteryPercentView.getText();
pw.println(" BatteryMeterView:");
pw.println(" mDrawable.getPowerSave: " + powerSave);
pw.println(" mBatteryPercentView.getText(): " + percent);
pw.println(" mTextColor: #" + Integer.toHexString(mTextColor));
pw.println(" mLevel: " + mLevel);
pw.println(" mForceShowPercent: " + mForceShowPercent);
}
private final class SettingObserver extends ContentObserver {
public SettingObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
updateShowPercent();
}
}
}