Merge "Wireless charging on aod and lockscreen"

This commit is contained in:
TreeHugger Robot
2018-02-08 23:46:15 +00:00
committed by Android (Google) Code Review
10 changed files with 205 additions and 105 deletions

View File

@@ -323,4 +323,16 @@ public class BatteryManager {
public long getLongProperty(int id) {
return queryProperty(id);
}
/**
* Return true if the plugType given is wired
* @param plugType {@link #BATTERY_PLUGGED_AC}, {@link #BATTERY_PLUGGED_USB},
* or {@link #BATTERY_PLUGGED_WIRELESS}
*
* @return true if plugType is wired
* @hide
*/
public static boolean isPlugWired(int plugType) {
return plugType == BATTERY_PLUGGED_USB || plugType == BATTERY_PLUGGED_AC;
}
}

View File

@@ -35,7 +35,7 @@ oneway interface IStatusBar
void animateCollapsePanels();
void togglePanel();
void showChargingAnimation(int batteryLevel);
void showWirelessChargingAnimation(int batteryLevel);
/**
* Notifies the status bar of a System UI visibility flag change.

View File

@@ -901,13 +901,28 @@
<dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen>
<dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
<!-- WirelessCharging Animation values -->
<!-- Starting text size of batteryLevel for wireless charging animation -->
<dimen name="config_batteryLevelTextSizeStart" format="float">5.0</dimen>
<!-- Ending text size of batteryLevel for wireless charging animation -->
<dimen name="config_batteryLevelTextSizeEnd" format="float">32.0</dimen>
<!-- Wireless Charging battery level text animation duration -->
<integer name="config_batteryLevelTextAnimationDuration">400</integer>
<!-- Wireless Charging Animation values -->
<dimen name="wireless_charging_dots_radius_start">0dp</dimen>
<dimen name="wireless_charging_dots_radius_end">4dp</dimen>
<dimen name="wireless_charging_circle_radius_start">28dp</dimen>
<dimen name="wireless_charging_circle_radius_end">92dp</dimen>
<integer name="wireless_charging_angle_offset">20</integer>
<integer name="wireless_charging_scale_dots_duration">83</integer>
<integer name="wireless_charging_num_dots">20</integer>
<!-- Starting text size in dp of batteryLevel for wireless charging animation -->
<dimen name="wireless_charging_anim_battery_level_text_size_start">0dp</dimen>
<!-- Ending text size in dp of batteryLevel for wireless charging animation -->
<dimen name="wireless_charging_anim_battery_level_text_size_end">14dp</dimen>
<!-- time until battery info is at full opacity-->
<integer name="wireless_charging_anim_opacity_offset">80</integer>
<!-- duration batteryLevel opacity goes from 0 to 1 duration -->
<integer name="wireless_charging_battery_level_text_opacity_duration">117</integer>
<!-- battery text scale animation duration -->
<integer name="wireless_charging_battery_level_text_scale_animation_duration">367</integer>
<!--time until wireless charging animation starts to fade-->
<integer name="wireless_charging_fade_offset">920</integer>
<!-- duration wireless charging animation takes to full fade to 0 opacity -->
<integer name="wireless_charging_fade_duration">200</integer>
<!-- Wired charging on AOD, text animation duration -->
<integer name="wired_charging_aod_text_animation_duration_down">500</integer>

View File

@@ -19,7 +19,6 @@ package com.android.systemui.charging;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
@@ -36,13 +35,18 @@ import android.view.WindowManager;
*/
public class WirelessChargingAnimation {
public static final long DURATION = 1400;
public static final long DURATION = 1133;
private static final String TAG = "WirelessChargingView";
private static final boolean LOCAL_LOGV = false;
private final WirelessChargingView mCurrentWirelessChargingView;
private static WirelessChargingView mPreviousWirelessChargingView;
public interface Callback {
void onAnimationStarting();
void onAnimationEnded();
}
/**
* Constructs an empty WirelessChargingAnimation object. If looper is null,
* Looper.myLooper() is used. Must set
@@ -51,9 +55,9 @@ public class WirelessChargingAnimation {
* @hide
*/
public WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper, int
batteryLevel) {
batteryLevel, Callback callback) {
mCurrentWirelessChargingView = new WirelessChargingView(context, looper,
batteryLevel);
batteryLevel, callback);
}
/**
@@ -61,8 +65,8 @@ public class WirelessChargingAnimation {
* @hide
*/
public static WirelessChargingAnimation makeWirelessChargingAnimation(@NonNull Context context,
@Nullable Looper looper, int batteryLevel) {
return new WirelessChargingAnimation(context, looper, batteryLevel);
@Nullable Looper looper, int batteryLevel, Callback callback) {
return new WirelessChargingAnimation(context, looper, batteryLevel, callback);
}
/**
@@ -95,8 +99,11 @@ public class WirelessChargingAnimation {
private View mView;
private View mNextView;
private WindowManager mWM;
private Callback mCallback;
public WirelessChargingView(Context context, @Nullable Looper looper, int batteryLevel) {
public WirelessChargingView(Context context, @Nullable Looper looper, int batteryLevel,
Callback callback) {
mCallback = callback;
mNextView = new WirelessChargingLayout(context, batteryLevel);
mGravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER;
@@ -149,6 +156,8 @@ public class WirelessChargingAnimation {
}
public void hide(long duration) {
mHandler.removeMessages(HIDE);
if (LOCAL_LOGV) Log.v(TAG, "HIDE: " + this);
mHandler.sendMessageDelayed(Message.obtain(mHandler, HIDE), duration);
}
@@ -169,18 +178,6 @@ public class WirelessChargingAnimation {
context = mView.getContext();
}
mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
// We can resolve the Gravity here by using the Locale for getting
// the layout direction
final Configuration config = mView.getContext().getResources().getConfiguration();
final int gravity = Gravity.getAbsoluteGravity(mGravity,
config.getLayoutDirection());
mParams.gravity = gravity;
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
mParams.horizontalWeight = 1.0f;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
mParams.verticalWeight = 1.0f;
}
mParams.packageName = packageName;
mParams.hideTimeoutMilliseconds = DURATION;
@@ -191,6 +188,9 @@ public class WirelessChargingAnimation {
if (LOCAL_LOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
try {
if (mCallback != null) {
mCallback.onAnimationStarting();
}
mWM.addView(mView, mParams);
} catch (WindowManager.BadTokenException e) {
Slog.d(TAG, "Unable to add wireless charging view. " + e);
@@ -203,6 +203,9 @@ public class WirelessChargingAnimation {
if (mView != null) {
if (mView.getParent() != null) {
if (LOCAL_LOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
if (mCallback != null) {
mCallback.onAnimationEnded();
}
mWM.removeViewImmediate(mView);
}

View File

@@ -16,13 +16,16 @@
package com.android.systemui.charging;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import java.text.NumberFormat;
@@ -52,10 +55,9 @@ public class WirelessChargingLayout extends FrameLayout {
init(c, attrs, -1);
}
private void init(Context c, AttributeSet attrs, int batteryLevel) {
private void init(Context context, AttributeSet attrs, int batteryLevel) {
final int mBatteryLevel = batteryLevel;
inflate(c, R.layout.wireless_charging_layout, this);
inflate(context, R.layout.wireless_charging_layout, this);
// where the circle animation occurs:
final WirelessChargingView mChargingView = findViewById(R.id.wireless_charging_view);
@@ -68,14 +70,57 @@ public class WirelessChargingLayout extends FrameLayout {
if (batteryLevel != UNKNOWN_BATTERY_LEVEL) {
mPercentage.setText(NumberFormat.getPercentInstance().format(mBatteryLevel / 100f));
ValueAnimator animator = ObjectAnimator.ofFloat(mPercentage, "textSize",
getContext().getResources().getFloat(R.dimen.config_batteryLevelTextSizeStart),
getContext().getResources().getFloat(R.dimen.config_batteryLevelTextSizeEnd));
animator.setDuration((long) getContext().getResources().getInteger(
R.integer.config_batteryLevelTextAnimationDuration));
animator.start();
mPercentage.setAlpha(0);
}
final long chargingAnimationFadeStartOffset = (long) context.getResources().getInteger(
R.integer.wireless_charging_fade_offset);
final long chargingAnimationFadeDuration = (long) context.getResources().getInteger(
R.integer.wireless_charging_fade_duration);
final int batteryLevelTextSizeStart = context.getResources().getDimensionPixelSize(
R.dimen.wireless_charging_anim_battery_level_text_size_start);
final int batteryLevelTextSizeEnd = context.getResources().getDimensionPixelSize(
R.dimen.wireless_charging_anim_battery_level_text_size_end);
// Animation Scale: battery percentage text scales from 0% to 100%
ValueAnimator textSizeAnimator = ObjectAnimator.ofFloat(mPercentage, "textSize",
batteryLevelTextSizeStart, batteryLevelTextSizeEnd);
textSizeAnimator.setInterpolator(new PathInterpolator(0, 0, 0, 1));
textSizeAnimator.setDuration((long) 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);
textOpacityAnimator.setInterpolator(Interpolators.LINEAR);
textOpacityAnimator.setDuration((long) context.getResources().getInteger(
R.integer.wireless_charging_battery_level_text_opacity_duration));
textOpacityAnimator.setStartDelay((long) 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);
textFadeAnimator.setDuration(chargingAnimationFadeDuration);
textFadeAnimator.setInterpolator(Interpolators.LINEAR);
textFadeAnimator.setStartDelay(chargingAnimationFadeStartOffset);
// Animation Opacity: wireless charging circle animation fades from 1 to 0 opacity
ValueAnimator circleFadeAnimator = ObjectAnimator.ofFloat(mChargingView, "alpha",
1, 0);
circleFadeAnimator.setDuration(chargingAnimationFadeDuration);
circleFadeAnimator.setInterpolator(Interpolators.LINEAR);
circleFadeAnimator.setStartDelay(chargingAnimationFadeStartOffset);
// Animation Opacity: secondary text animation fades from 1 to 0 opacity
ValueAnimator secondaryTextFadeAnimator = ObjectAnimator.ofFloat(mSecondaryText, "alpha",
1, 0);
circleFadeAnimator.setDuration(chargingAnimationFadeDuration);
secondaryTextFadeAnimator.setInterpolator(Interpolators.LINEAR);
secondaryTextFadeAnimator.setStartDelay(chargingAnimationFadeStartOffset);
// play all animations together
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(textSizeAnimator, textOpacityAnimator, textFadeAnimator,
circleFadeAnimator, secondaryTextFadeAnimator);
animatorSet.start();
}
}
}

View File

@@ -21,10 +21,10 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
final class WirelessChargingView extends View {
@@ -33,21 +33,21 @@ final class WirelessChargingView extends View {
private float mPathGone;
private float mInterpolatedPathGone;
private long mAnimationStartTime;
private long mStartSpinCircleAnimationTime;
private long mAnimationOffset = 500;
private long mTotalAnimationDuration = WirelessChargingAnimation.DURATION - mAnimationOffset;
private long mExpandingCircle = (long) (mTotalAnimationDuration * .9);
private long mSpinCircleAnimationTime = mTotalAnimationDuration - mExpandingCircle;
private long mScaleDotsDuration;
private boolean mFinishedAnimatingSpinningCircles = false;
private boolean mFinishedAnimatingDots = false;
private int mNumDots;
private int mStartAngle = -90;
private int mNumSmallCircles = 20;
private int mSmallCircleRadius = 10;
private double mAngleOffset;
private double mCurrAngleOffset;
private int mMainCircleStartRadius = 100;
private int mMainCircleEndRadius = 230;
private int mMainCircleCurrentRadius = mMainCircleStartRadius;
private int mDotsRadiusStart;
private int mDotsRadiusEnd;
private int mCurrDotRadius;
private int mMainCircleStartRadius;
private int mMainCircleEndRadius;
private int mMainCircleCurrentRadius;
private int mCenterX;
private int mCenterY;
@@ -72,8 +72,25 @@ final class WirelessChargingView extends View {
public void init(Context context, AttributeSet attr) {
mContext = context;
mDotsRadiusStart = context.getResources().getDimensionPixelSize(
R.dimen.wireless_charging_dots_radius_start);
mDotsRadiusEnd = context.getResources().getDimensionPixelSize(
R.dimen.wireless_charging_dots_radius_end);
mMainCircleStartRadius = context.getResources().getDimensionPixelSize(
R.dimen.wireless_charging_circle_radius_start);
mMainCircleEndRadius = context.getResources().getDimensionPixelSize(
R.dimen.wireless_charging_circle_radius_end);
mMainCircleCurrentRadius = mMainCircleStartRadius;
mAngleOffset = context.getResources().getInteger(R.integer.wireless_charging_angle_offset);
mScaleDotsDuration = (long) context.getResources().getInteger(
R.integer.wireless_charging_scale_dots_duration);
mNumDots = context.getResources().getInteger(R.integer.wireless_charging_num_dots);
setupPaint();
mInterpolator = new DecelerateInterpolator();
mInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
}
private void setupPaint() {
@@ -92,64 +109,62 @@ final class WirelessChargingView extends View {
updateDrawingParameters();
drawCircles(canvas);
if (!mFinishedAnimatingSpinningCircles) {
if (!mFinishedAnimatingDots) {
invalidate();
}
}
/**
* Draws a larger circle of radius {@link WirelessChargingView#mMainCircleEndRadius} composed of
* {@link WirelessChargingView#mNumSmallCircles} smaller circles
* {@link WirelessChargingView#mNumDots} smaller circles
* @param canvas
*/
private void drawCircles(Canvas canvas) {
mCenterX = canvas.getWidth() / 2;
mCenterY = canvas.getHeight() / 2;
// angleOffset makes small circles look like they're moving around the main circle
float angleOffset = mPathGone * 10;
// draws mNumSmallCircles to compose a larger, main circle
for (int circle = 0; circle < mNumSmallCircles; circle++) {
double angle = ((mStartAngle + angleOffset) * Math.PI / 180) + (circle * ((2 * Math.PI)
/ mNumSmallCircles));
// draws mNumDots to compose a larger, main circle
for (int circle = 0; circle < mNumDots; circle++) {
double angle = ((mCurrAngleOffset) * Math.PI / 180) + (circle * ((2 * Math.PI)
/ mNumDots));
int x = (int) (mCenterX + Math.cos(angle) * (mMainCircleCurrentRadius +
mSmallCircleRadius));
mCurrDotRadius));
int y = (int) (mCenterY + Math.sin(angle) * (mMainCircleCurrentRadius +
mSmallCircleRadius));
mCurrDotRadius));
canvas.drawCircle(x, y, mSmallCircleRadius, mPaint);
canvas.drawCircle(x, y, mCurrDotRadius, mPaint);
}
if (mMainCircleCurrentRadius >= mMainCircleEndRadius && !isSpinCircleAnimationStarted()) {
mStartSpinCircleAnimationTime = System.currentTimeMillis();
if (mMainCircleCurrentRadius >= mMainCircleEndRadius) {
mFinishedAnimatingDots = true;
}
if (isSpinAnimationFinished()) {
mFinishedAnimatingSpinningCircles = true;
}
}
private boolean isSpinCircleAnimationStarted() {
return mStartSpinCircleAnimationTime != 0;
}
private boolean isSpinAnimationFinished() {
return isSpinCircleAnimationStarted() && System.currentTimeMillis() -
mStartSpinCircleAnimationTime > mSpinCircleAnimationTime;
}
private void updateDrawingParameters() {
mPathGone = getPathGone(System.currentTimeMillis());
long now = System.currentTimeMillis();
long timeSinceStart = now - mAnimationStartTime;
mPathGone = getPathGone(now);
mInterpolatedPathGone = mInterpolator.getInterpolation(mPathGone);
// Position Dots: update main circle radius (that the dots compose)
if (mPathGone < 1.0f) {
mMainCircleCurrentRadius = mMainCircleStartRadius + (int) (mInterpolatedPathGone *
(mMainCircleEndRadius - mMainCircleStartRadius));
} else {
mMainCircleCurrentRadius = mMainCircleEndRadius;
}
// Scale Dots: update dot radius
if (timeSinceStart < mScaleDotsDuration) {
mCurrDotRadius = mDotsRadiusStart + (int) (mInterpolator.getInterpolation((float)
timeSinceStart / mScaleDotsDuration) * (mDotsRadiusEnd - mDotsRadiusStart));
} else {
mCurrDotRadius = mDotsRadiusEnd;
}
// Rotation Dot Group: dots rotate from 0 to 20 degrees
mCurrAngleOffset = mAngleOffset * mPathGone;
}
/**
@@ -158,6 +173,6 @@ final class WirelessChargingView extends View {
* For values > 1.0 the larger circle has been drawn and further animation can occur
*/
private float getPathGone(long now) {
return (float) (now - mAnimationStartTime) / (mExpandingCircle);
return (float) (now - mAnimationStartTime) / (WirelessChargingAnimation.DURATION);
}
}

View File

@@ -156,7 +156,7 @@ public class CommandQueue extends IStatusBar.Stub {
default void handleShowGlobalActionsMenu() { }
default void handleShowShutdownUi(boolean isReboot, String reason) { }
default void showChargingAnimation(int batteryLevel) { }
default void showWirelessChargingAnimation(int batteryLevel) { }
default void onRotationProposal(int rotation, boolean isValid) { }
@@ -497,7 +497,7 @@ public class CommandQueue extends IStatusBar.Stub {
}
@Override
public void showChargingAnimation(int batteryLevel) {
public void showWirelessChargingAnimation(int batteryLevel) {
mHandler.removeMessages(MSG_SHOW_CHARGING_ANIMATION);
mHandler.obtainMessage(MSG_SHOW_CHARGING_ANIMATION, batteryLevel, 0)
.sendToTarget();
@@ -784,7 +784,7 @@ public class CommandQueue extends IStatusBar.Stub {
break;
case MSG_SHOW_CHARGING_ANIMATION:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).showChargingAnimation(msg.arg1);
mCallbacks.get(i).showWirelessChargingAnimation(msg.arg1);
}
break;
case MSG_SHOW_PINNING_TOAST_ENTER_EXIT:

View File

@@ -140,7 +140,6 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.ActivityStarterDelegate;
import com.android.systemui.AutoReinflateContainer;
import com.android.systemui.charging.WirelessChargingAnimation;
import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
import com.android.systemui.EventLogTags;
@@ -152,6 +151,7 @@ import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.charging.WirelessChargingAnimation;
import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -181,6 +181,7 @@ import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.DismissView;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.EmptyShadeView;
@@ -2460,14 +2461,25 @@ public class StatusBar extends SystemUI implements DemoMode,
}
@Override
public void showChargingAnimation(int batteryLevel) {
if (mDozing) {
// ambient
} else if (mKeyguardManager.isKeyguardLocked()) {
// lockscreen
} else {
public void showWirelessChargingAnimation(int batteryLevel) {
if (mDozing || mKeyguardManager.isKeyguardLocked()) {
// on ambient or lockscreen, hide notification panel
WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
batteryLevel).show();
batteryLevel, new WirelessChargingAnimation.Callback() {
@Override
public void onAnimationStarting() {
CrossFadeHelper.fadeOut(mNotificationPanel, 1);
}
@Override
public void onAnimationEnded() {
CrossFadeHelper.fadeIn(mNotificationPanel);
}
}).show();
} else {
// workspace
WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
batteryLevel, null).show();
}
}

View File

@@ -120,9 +120,6 @@ public final class PowerManagerService extends SystemService
private static final boolean DEBUG = false;
private static final boolean DEBUG_SPEW = DEBUG && true;
// if DEBUG_WIRELESS=true, plays wireless charging animation w/ sound on every plug + unplug
private static final boolean DEBUG_WIRELESS = false;
// Message: Sent when a user activity timeout occurs to update the power state.
private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
// Message: Sent when the device enters or exits a dreaming or dozing state.
@@ -1743,14 +1740,15 @@ public final class PowerManagerService extends SystemService
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
// Tell the notifier whether wireless charging has started so that
// it can provide feedback to the user.
if (dockedOnWirelessCharger || DEBUG_WIRELESS) {
mNotifier.onWirelessChargingStarted(mBatteryLevel);
} else if (mIsPowered && !wasPowered
&& (mPlugType == BatteryManager.BATTERY_PLUGGED_AC
|| mPlugType == BatteryManager.BATTERY_PLUGGED_USB)) {
mNotifier.onWiredChargingStarted();
// only play charging sounds if boot is completed so charging sounds don't play
// with potential notification sounds
if (mBootCompleted) {
if (mIsPowered && !BatteryManager.isPlugWired(oldPlugType)
&& BatteryManager.isPlugWired(mPlugType)) {
mNotifier.onWiredChargingStarted();
} else if (dockedOnWirelessCharger) {
mNotifier.onWirelessChargingStarted(mBatteryLevel);
}
}
}

View File

@@ -321,7 +321,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
public void showChargingAnimation(int batteryLevel) {
if (mBar != null) {
try {
mBar.showChargingAnimation(batteryLevel);
mBar.showWirelessChargingAnimation(batteryLevel);
} catch (RemoteException ex){
}
}