Modify WirelessChargingLayout for reverse charging
- add Tx battery level and Tx icon
- new LifecycleRegistry in StatusBar for BatteryStateChangeCallback
Bug: 153272360
Test: atest SystemUITests:StatusBarTest
Change-Id: Ibb719e45799f20a93875dc85ae60af75ed79cf14
diff --git a/packages/SystemUI/res/drawable/ic_reverse_charging.xml b/packages/SystemUI/res/drawable/ic_reverse_charging.xml
new file mode 100644
index 0000000..2268d86
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_reverse_charging.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="?attr/chargingAnimColor"
+ android:pathData="M18,16.5v4.17C18,21.4,17.4,22,16.66,22H7.33C6.6,22,6,21.4,6,20.67V15V5.33C6,4.6,6.6,4,7.33,4H9.5V2h5v2h2.17 C17.4,4,18,4.6,18,5.33V7.5h-2V6H8v9v5h8v-3.5H18z M13,15.5h-2V14c0-1.65,1.35-3,3-3h4V9l3,3l-3,3v-2h-4c-0.55,0-1,0.45-1,1V15.5z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/wireless_charging_layout.xml b/packages/SystemUI/res/layout/wireless_charging_layout.xml
index 4610409..730f24f 100644
--- a/packages/SystemUI/res/layout/wireless_charging_layout.xml
+++ b/packages/SystemUI/res/layout/wireless_charging_layout.xml
@@ -36,14 +36,26 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:orientation="vertical">
+ android:orientation="horizontal">
<TextView
+ android:id="@+id/reverse_wireless_charging_percentage"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="gone"/>
+ <ImageView
+ android:id="@+id/reverse_wireless_charging_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:src="@drawable/ic_reverse_charging"
+ android:visibility="gone"/>
+ <TextView
android:id="@+id/wireless_charging_percentage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:textSize="24sp"/>
+ android:layout_gravity="center"/>
</LinearLayout>
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
index d5b54f9..2569f7c 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -54,25 +54,28 @@
* before calling {@link #show} - can be done through {@link #makeWirelessChargingAnimation}.
* @hide
*/
- public WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper, int
- batteryLevel, Callback callback, boolean isDozing) {
+ public WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper,
+ int transmittingBatteryLevel, int batteryLevel, Callback callback, boolean isDozing) {
mCurrentWirelessChargingView = new WirelessChargingView(context, looper,
- batteryLevel, callback, isDozing);
+ transmittingBatteryLevel, batteryLevel, callback, isDozing);
}
/**
* Creates a wireless charging animation object populated with next view.
+ *
* @hide
*/
public static WirelessChargingAnimation makeWirelessChargingAnimation(@NonNull Context context,
- @Nullable Looper looper, int batteryLevel, Callback callback, boolean isDozing) {
- return new WirelessChargingAnimation(context, looper, batteryLevel, callback, isDozing);
+ @Nullable Looper looper, int transmittingBatteryLevel, int batteryLevel,
+ Callback callback, boolean isDozing) {
+ return new WirelessChargingAnimation(context, looper, transmittingBatteryLevel,
+ batteryLevel, callback, isDozing);
}
/**
* Show the view for the specified duration.
*/
- public void show() {
+ public void show(long delay) {
if (mCurrentWirelessChargingView == null ||
mCurrentWirelessChargingView.mNextView == null) {
throw new RuntimeException("setView must have been called");
@@ -83,8 +86,8 @@
}
mPreviousWirelessChargingView = mCurrentWirelessChargingView;
- mCurrentWirelessChargingView.show();
- mCurrentWirelessChargingView.hide(DURATION);
+ mCurrentWirelessChargingView.show(delay);
+ mCurrentWirelessChargingView.hide(delay + DURATION);
}
private static class WirelessChargingView {
@@ -100,10 +103,12 @@
private WindowManager mWM;
private Callback mCallback;
- public WirelessChargingView(Context context, @Nullable Looper looper, int batteryLevel,
- Callback callback, boolean isDozing) {
+ public WirelessChargingView(Context context, @Nullable Looper looper,
+ int transmittingBatteryLevel, int batteryLevel, Callback callback,
+ boolean isDozing) {
mCallback = callback;
- mNextView = new WirelessChargingLayout(context, batteryLevel, isDozing);
+ mNextView = new WirelessChargingLayout(context, transmittingBatteryLevel, batteryLevel,
+ isDozing);
mGravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER;
final WindowManager.LayoutParams params = mParams;
@@ -149,9 +154,9 @@
};
}
- public void show() {
+ public void show(long delay) {
if (DEBUG) Slog.d(TAG, "SHOW: " + this);
- mHandler.obtainMessage(SHOW).sendToTarget();
+ mHandler.sendMessageDelayed(Message.obtain(mHandler, SHOW), delay);
}
public void hide(long duration) {
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index ec150873..e8407f0 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.graphics.drawable.Animatable;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
@@ -37,16 +38,17 @@
* @hide
*/
public class WirelessChargingLayout extends FrameLayout {
- private final static int UNKNOWN_BATTERY_LEVEL = -1;
+ public final static int UNKNOWN_BATTERY_LEVEL = -1;
public WirelessChargingLayout(Context context) {
super(context);
init(context, null, false);
}
- public WirelessChargingLayout(Context context, int batteryLevel, boolean isDozing) {
+ public WirelessChargingLayout(Context context, int transmittingBatteryLevel, int batteryLevel,
+ boolean isDozing) {
super(context);
- init(context, null, batteryLevel, isDozing);
+ init(context, null, transmittingBatteryLevel, batteryLevel, isDozing);
}
public WirelessChargingLayout(Context context, AttributeSet attrs) {
@@ -55,11 +57,13 @@
}
private void init(Context c, AttributeSet attrs, boolean isDozing) {
- init(c, attrs, -1, false);
+ init(c, attrs, -1, -1, false);
}
- private void init(Context context, AttributeSet attrs, int batteryLevel, boolean isDozing) {
- final int mBatteryLevel = batteryLevel;
+ private void init(Context context, AttributeSet attrs, int transmittingBatteryLevel,
+ int batteryLevel, boolean isDozing) {
+ final boolean showTransmittingBatteryLevel =
+ (transmittingBatteryLevel != UNKNOWN_BATTERY_LEVEL);
// set style based on background
int style = R.style.ChargingAnim_WallpaperBackground;
@@ -74,39 +78,40 @@
final Animatable chargingAnimation = (Animatable) chargingView.getDrawable();
// amount of battery:
- final TextView mPercentage = findViewById(R.id.wireless_charging_percentage);
+ final TextView percentage = findViewById(R.id.wireless_charging_percentage);
if (batteryLevel != UNKNOWN_BATTERY_LEVEL) {
- mPercentage.setText(NumberFormat.getPercentInstance().format(mBatteryLevel / 100f));
- mPercentage.setAlpha(0);
+ percentage.setText(NumberFormat.getPercentInstance().format(batteryLevel / 100f));
+ percentage.setAlpha(0);
}
- final long chargingAnimationFadeStartOffset = (long) context.getResources().getInteger(
+ final long chargingAnimationFadeStartOffset = context.getResources().getInteger(
R.integer.wireless_charging_fade_offset);
- final long chargingAnimationFadeDuration = (long) context.getResources().getInteger(
+ final long chargingAnimationFadeDuration = context.getResources().getInteger(
R.integer.wireless_charging_fade_duration);
final float batteryLevelTextSizeStart = context.getResources().getFloat(
R.dimen.wireless_charging_anim_battery_level_text_size_start);
final float batteryLevelTextSizeEnd = context.getResources().getFloat(
- R.dimen.wireless_charging_anim_battery_level_text_size_end);
+ R.dimen.wireless_charging_anim_battery_level_text_size_end) * (
+ showTransmittingBatteryLevel ? 0.75f : 1.0f);
// Animation Scale: battery percentage text scales from 0% to 100%
- ValueAnimator textSizeAnimator = ObjectAnimator.ofFloat(mPercentage, "textSize",
+ ValueAnimator textSizeAnimator = ObjectAnimator.ofFloat(percentage, "textSize",
batteryLevelTextSizeStart, batteryLevelTextSizeEnd);
textSizeAnimator.setInterpolator(new PathInterpolator(0, 0, 0, 1));
- textSizeAnimator.setDuration((long) context.getResources().getInteger(
+ textSizeAnimator.setDuration(context.getResources().getInteger(
R.integer.wireless_charging_battery_level_text_scale_animation_duration));
// Animation Opacity: battery percentage text transitions from 0 to 1 opacity
- ValueAnimator textOpacityAnimator = ObjectAnimator.ofFloat(mPercentage, "alpha", 0, 1);
+ ValueAnimator textOpacityAnimator = ObjectAnimator.ofFloat(percentage, "alpha", 0, 1);
textOpacityAnimator.setInterpolator(Interpolators.LINEAR);
- textOpacityAnimator.setDuration((long) context.getResources().getInteger(
+ textOpacityAnimator.setDuration(context.getResources().getInteger(
R.integer.wireless_charging_battery_level_text_opacity_duration));
- textOpacityAnimator.setStartDelay((long) context.getResources().getInteger(
+ textOpacityAnimator.setStartDelay(context.getResources().getInteger(
R.integer.wireless_charging_anim_opacity_offset));
// Animation Opacity: battery percentage text fades from 1 to 0 opacity
- ValueAnimator textFadeAnimator = ObjectAnimator.ofFloat(mPercentage, "alpha", 1, 0);
+ ValueAnimator textFadeAnimator = ObjectAnimator.ofFloat(percentage, "alpha", 1, 0);
textFadeAnimator.setDuration(chargingAnimationFadeDuration);
textFadeAnimator.setInterpolator(Interpolators.LINEAR);
textFadeAnimator.setStartDelay(chargingAnimationFadeStartOffset);
@@ -114,7 +119,80 @@
// play all animations together
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(textSizeAnimator, textOpacityAnimator, textFadeAnimator);
+
+ if (!showTransmittingBatteryLevel) {
+ chargingAnimation.start();
+ animatorSet.start();
+ return;
+ }
+
+ // amount of transmitting battery:
+ final TextView transmittingPercentage = findViewById(
+ R.id.reverse_wireless_charging_percentage);
+ transmittingPercentage.setVisibility(VISIBLE);
+ transmittingPercentage.setText(
+ NumberFormat.getPercentInstance().format(transmittingBatteryLevel / 100f));
+ transmittingPercentage.setAlpha(0);
+
+ // Animation Scale: transmitting battery percentage text scales from 0% to 100%
+ ValueAnimator textSizeAnimatorTransmitting = ObjectAnimator.ofFloat(transmittingPercentage,
+ "textSize", batteryLevelTextSizeStart, batteryLevelTextSizeEnd);
+ textSizeAnimatorTransmitting.setInterpolator(new PathInterpolator(0, 0, 0, 1));
+ textSizeAnimatorTransmitting.setDuration(context.getResources().getInteger(
+ R.integer.wireless_charging_battery_level_text_scale_animation_duration));
+
+ // Animation Opacity: transmitting battery percentage text transitions from 0 to 1 opacity
+ ValueAnimator textOpacityAnimatorTransmitting = ObjectAnimator.ofFloat(
+ transmittingPercentage, "alpha", 0, 1);
+ textOpacityAnimatorTransmitting.setInterpolator(Interpolators.LINEAR);
+ textOpacityAnimatorTransmitting.setDuration(context.getResources().getInteger(
+ R.integer.wireless_charging_battery_level_text_opacity_duration));
+ textOpacityAnimatorTransmitting.setStartDelay(
+ context.getResources().getInteger(R.integer.wireless_charging_anim_opacity_offset));
+
+ // Animation Opacity: transmitting battery percentage text fades from 1 to 0 opacity
+ ValueAnimator textFadeAnimatorTransmitting = ObjectAnimator.ofFloat(transmittingPercentage,
+ "alpha", 1, 0);
+ textFadeAnimatorTransmitting.setDuration(chargingAnimationFadeDuration);
+ textFadeAnimatorTransmitting.setInterpolator(Interpolators.LINEAR);
+ textFadeAnimatorTransmitting.setStartDelay(chargingAnimationFadeStartOffset);
+
+ // play all animations together
+ AnimatorSet animatorSetTransmitting = new AnimatorSet();
+ animatorSetTransmitting.playTogether(textSizeAnimatorTransmitting,
+ textOpacityAnimatorTransmitting, textFadeAnimatorTransmitting);
+
+ // transmitting battery icon
+ final ImageView chargingViewIcon = findViewById(R.id.reverse_wireless_charging_icon);
+ chargingViewIcon.setVisibility(VISIBLE);
+ final int padding = Math.round(
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, batteryLevelTextSizeEnd,
+ getResources().getDisplayMetrics()));
+ chargingViewIcon.setPadding(padding, 0, padding, 0);
+
+ // Animation Opacity: transmitting battery icon transitions from 0 to 1 opacity
+ ValueAnimator textOpacityAnimatorIcon = ObjectAnimator.ofFloat(chargingViewIcon, "alpha", 0,
+ 1);
+ textOpacityAnimatorIcon.setInterpolator(Interpolators.LINEAR);
+ textOpacityAnimatorIcon.setDuration(context.getResources().getInteger(
+ R.integer.wireless_charging_battery_level_text_opacity_duration));
+ textOpacityAnimatorIcon.setStartDelay(
+ context.getResources().getInteger(R.integer.wireless_charging_anim_opacity_offset));
+
+ // Animation Opacity: transmitting battery icon fades from 1 to 0 opacity
+ ValueAnimator textFadeAnimatorIcon = ObjectAnimator.ofFloat(chargingViewIcon, "alpha", 1,
+ 0);
+ textFadeAnimatorIcon.setDuration(chargingAnimationFadeDuration);
+ textFadeAnimatorIcon.setInterpolator(Interpolators.LINEAR);
+ textFadeAnimatorIcon.setStartDelay(chargingAnimationFadeStartOffset);
+
+ // play all animations together
+ AnimatorSet animatorSetIcon = new AnimatorSet();
+ animatorSetIcon.playTogether(textOpacityAnimatorIcon, textFadeAnimatorIcon);
+
chargingAnimation.start();
animatorSet.start();
+ animatorSetTransmitting.start();
+ animatorSetIcon.start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 1bc42d1..e2f9018 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -29,7 +29,10 @@
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
+import static androidx.lifecycle.Lifecycle.State.RESUMED;
+
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
+import static com.android.systemui.charging.WirelessChargingLayout.UNKNOWN_BATTERY_LEVEL;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
@@ -45,6 +48,7 @@
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -113,6 +117,10 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.DateTimeView;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.logging.MetricsLogger;
@@ -236,7 +244,8 @@
ActivityStarter, KeyguardStateController.Callback,
OnHeadsUpChangedListener, CommandQueue.Callbacks,
ColorExtractor.OnColorsChangedListener, ConfigurationListener,
- StatusBarStateController.StateListener, ActivityLaunchAnimator.Callback {
+ StatusBarStateController.StateListener, ActivityLaunchAnimator.Callback,
+ LifecycleOwner, BatteryController.BatteryStateChangeCallback {
public static final boolean MULTIUSER_DEBUG = false;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -585,7 +594,8 @@
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private final UserSwitcherController mUserSwitcherController;
private final NetworkController mNetworkController;
- private final BatteryController mBatteryController;
+ private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
+ protected final BatteryController mBatteryController;
protected boolean mPanelExpanded;
private UiModeManager mUiModeManager;
protected boolean mIsKeyguard;
@@ -934,6 +944,9 @@
mConfigurationController.addCallback(this);
+ mBatteryController.observe(mLifecycle, this);
+ mLifecycle.setCurrentState(RESUMED);
+
// set the initial view visibility
int disabledFlags1 = result.mDisabledFlags1;
int disabledFlags2 = result.mDisabledFlags2;
@@ -1100,22 +1113,6 @@
mAmbientIndicationContainer = mNotificationShadeWindowView.findViewById(
R.id.ambient_indication_container);
- // TODO: Find better place for this callback.
- mBatteryController.addCallback(new BatteryStateChangeCallback() {
- @Override
- public void onPowerSaveChanged(boolean isPowerSave) {
- mHandler.post(mCheckBarModes);
- if (mDozeServiceHost != null) {
- mDozeServiceHost.firePowerSaveChanged(isPowerSave);
- }
- }
-
- @Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- // noop
- }
- });
-
mAutoHideController.setStatusBar(new AutoHideUiElement() {
@Override
public void synchronizeState() {
@@ -1257,6 +1254,25 @@
ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
}
+ @NonNull
+ @Override
+ public Lifecycle getLifecycle() {
+ return mLifecycle;
+ }
+
+ @Override
+ public void onPowerSaveChanged(boolean isPowerSave) {
+ mHandler.post(mCheckBarModes);
+ if (mDozeServiceHost != null) {
+ mDozeServiceHost.firePowerSaveChanged(isPowerSave);
+ }
+ }
+
+ @Override
+ public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ // noop
+ }
+
@VisibleForTesting
protected void registerBroadcastReceiver() {
IntentFilter filter = new IntentFilter();
@@ -2356,10 +2372,16 @@
@Override
public void showWirelessChargingAnimation(int batteryLevel) {
+ showChargingAnimation(batteryLevel, UNKNOWN_BATTERY_LEVEL, 0);
+ }
+
+ protected void showChargingAnimation(int batteryLevel, int transmittingBatteryLevel,
+ long animationDelay) {
if (mDozing || mKeyguardManager.isKeyguardLocked()) {
// on ambient or lockscreen, hide notification panel
WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
- batteryLevel, new WirelessChargingAnimation.Callback() {
+ transmittingBatteryLevel, batteryLevel,
+ new WirelessChargingAnimation.Callback() {
@Override
public void onAnimationStarting() {
CrossFadeHelper.fadeOut(mNotificationPanelViewController.getView(), 1);
@@ -2369,11 +2391,11 @@
public void onAnimationEnded() {
CrossFadeHelper.fadeIn(mNotificationPanelViewController.getView());
}
- }, mDozing).show();
+ }, mDozing).show(animationDelay);
} else {
// workspace
WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
- batteryLevel, null, false).show();
+ transmittingBatteryLevel, batteryLevel, null, false).show(animationDelay);
}
}