diff options
3 files changed, 103 insertions, 77 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java index aeef49689517..eb704c863ebc 100644 --- a/packages/SystemUI/src/com/android/systemui/Interpolators.java +++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java @@ -31,6 +31,13 @@ import com.android.systemui.statusbar.stack.HeadsUpAppearInterpolator; */ public class Interpolators { public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); + + /** + * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t + * goes from 1 to 0 instead of 0 to 1). + */ + public static final Interpolator FAST_OUT_SLOW_IN_REVERSE = + new PathInterpolator(0.8f, 0f, 0.6f, 1f); public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f); public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); @@ -51,4 +58,11 @@ public class Interpolators { */ public static final Interpolator TOUCH_RESPONSE = new PathInterpolator(0.3f, 0f, 0.1f, 1f); + + /** + * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t + * goes from 1 to 0 instead of 0 to 1). + */ + public static final Interpolator TOUCH_RESPONSE_REVERSE = + new PathInterpolator(0.9f, 0f, 0.7f, 1f); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 7bd5fd0430c2..7e6abe95e226 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -47,6 +47,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.view.accessibility.AccessibilityManager; +import android.view.animation.Interpolator; import android.widget.FrameLayout; import com.android.internal.logging.MetricsLogger; @@ -107,17 +108,20 @@ public class NotificationPanelView extends PanelView implements private static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = new AnimationProperties() .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); private static final FloatProperty<NotificationPanelView> SET_DARK_AMOUNT_PROPERTY = - new FloatProperty<NotificationPanelView>("mDarkAmount") { + new FloatProperty<NotificationPanelView>("mInterpolatedDarkAmount") { + @Override public void setValue(NotificationPanelView object, float value) { - object.setDarkAmount(value); + object.setDarkAmount(value, object.mDarkInterpolator.getInterpolation(value)); } @Override public Float get(NotificationPanelView object) { - return object.mDarkAmount; + return object.mLinearDarkAmount; } }; + + private Interpolator mDarkInterpolator; private final PowerManager mPowerManager; private final AccessibilityManager mAccessibilityManager; @@ -237,7 +241,18 @@ public class NotificationPanelView extends PanelView implements private int mIndicationBottomPadding; private int mAmbientIndicationBottomPadding; private boolean mIsFullWidth; - private float mDarkAmount; + + /** + * Current dark amount that follows regular interpolation curve of animation. + */ + private float mInterpolatedDarkAmount; + + /** + * Dark amount that animates from 0 to 1 or vice-versa in linear manner, even if the + * interpolation curve is different. + */ + private float mLinearDarkAmount; + private float mDarkAmountTarget; private boolean mPulsing; private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); @@ -392,7 +407,7 @@ public class NotificationPanelView extends PanelView implements false); addView(mKeyguardBottomArea, index); initBottomArea(); - setDarkAmount(mDarkAmount); + setDarkAmount(mLinearDarkAmount, mInterpolatedDarkAmount); setKeyguardStatusViewVisibility(mStatusBarState, false, false); setKeyguardBottomAreaVisibility(mStatusBarState, false); @@ -506,7 +521,7 @@ public class NotificationPanelView extends PanelView implements getExpandedFraction(), totalHeight, mKeyguardStatusView.getHeight(), - mDarkAmount, + mInterpolatedDarkAmount, mStatusBar.isKeyguardCurrentlySecure(), mPulsing, mBouncerTop); @@ -1917,7 +1932,7 @@ public class NotificationPanelView extends PanelView implements if (view == null && mQsExpanded) { return; } - if (needsAnimation && mDarkAmount == 0) { + if (needsAnimation && mInterpolatedDarkAmount == 0) { mAnimateNextPositionUpdate = true; } ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone(); @@ -2727,20 +2742,28 @@ public class NotificationPanelView extends PanelView implements } mDarkAmountTarget = darkAmount; if (animate) { + if (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f) { + mDarkInterpolator = dozing + ? Interpolators.FAST_OUT_SLOW_IN + : Interpolators.TOUCH_RESPONSE_REVERSE; + } + mNotificationStackScroller.notifyDarkAnimationStart(dozing); mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, darkAmount); - mDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); - mDarkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP); + mDarkAnimator.setInterpolator(Interpolators.LINEAR); + mDarkAnimator.setDuration(mNotificationStackScroller.getDarkAnimationDuration(dozing)); mDarkAnimator.start(); } else { - setDarkAmount(darkAmount); + setDarkAmount(darkAmount, darkAmount); } } - private void setDarkAmount(float amount) { - mDarkAmount = amount; - mKeyguardStatusView.setDarkAmount(mDarkAmount); - mKeyguardBottomArea.setDarkAmount(mDarkAmount); + private void setDarkAmount(float linearAmount, float amount) { + mInterpolatedDarkAmount = amount; + mLinearDarkAmount = linearAmount; + mKeyguardStatusView.setDarkAmount(mInterpolatedDarkAmount); + mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount); positionClockAndNotifications(); + mNotificationStackScroller.setDarkAmount(linearAmount, mInterpolatedDarkAmount); } public void setPulsing(boolean pulsing) { @@ -2765,7 +2788,7 @@ public class NotificationPanelView extends PanelView implements public void dozeTimeTick() { mKeyguardStatusView.dozeTimeTick(); mKeyguardBottomArea.dozeTimeTick(); - if (mDarkAmount > 0) { + if (mInterpolatedDarkAmount > 0) { positionClockAndNotifications(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 9d0d295a26ca..ff4f215b482f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -34,7 +34,6 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.Path; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; @@ -46,11 +45,9 @@ import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; import android.support.v4.graphics.ColorUtils; import android.util.AttributeSet; -import android.util.FloatProperty; import android.util.Log; import android.util.MathUtils; import android.util.Pair; -import android.util.Property; import android.view.ContextThemeWrapper; import android.view.InputDevice; import android.view.MotionEvent; @@ -375,25 +372,22 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mScrollable; private View mForcedScroll; private View mNeedingPulseAnimation; - private float mDarkAmount = 0f; + + /** + * @see #setDarkAmount(float, float) + */ + private float mInterpolatedDarkAmount = 0f; + + /** + * @see #setDarkAmount(float, float) + */ + private float mLinearDarkAmount = 0f; /** * How fast the background scales in the X direction as a factor of the Y expansion. */ private float mBackgroundXFactor = 1f; - private static final Property<NotificationStackScrollLayout, Float> DARK_AMOUNT = - new FloatProperty<NotificationStackScrollLayout>("darkAmount") { - @Override - public void setValue(NotificationStackScrollLayout object, float value) { - object.setDarkAmount(value); - } - @Override - public Float get(NotificationStackScrollLayout object) { - return object.getDarkAmount(); - } - }; - private ObjectAnimator mDarkAmountAnimator; private boolean mUsingLightTheme; private boolean mQsExpanded; private boolean mForwardScrollable; @@ -424,6 +418,8 @@ public class NotificationStackScrollLayout extends ViewGroup private NotificationIconAreaController mIconAreaController; private float mVerticalPanelTranslation; + private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN; + public NotificationStackScrollLayout(Context context) { this(context, null); } @@ -558,16 +554,16 @@ public class NotificationStackScrollLayout extends ViewGroup canvas.drawRect(darkLeft, darkTop, darkRight, darkBottom, mBackgroundPaint); } } else { - float inverseDark = 1 - mDarkAmount; - float yProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(inverseDark); - float xProgress = Interpolators.FAST_OUT_SLOW_IN - .getInterpolation(inverseDark * mBackgroundXFactor); + float yProgress = 1 - mInterpolatedDarkAmount; + float xProgress = mDarkXInterpolator.getInterpolation( + (1 - mLinearDarkAmount) * mBackgroundXFactor); mBackgroundAnimationRect.set( (int) MathUtils.lerp(darkLeft, lockScreenLeft, xProgress), (int) MathUtils.lerp(darkTop, lockScreenTop, yProgress), (int) MathUtils.lerp(darkRight, lockScreenRight, xProgress), (int) MathUtils.lerp(darkBottom, lockScreenBottom, yProgress)); + if (!mAmbientState.isDark() || mFirstVisibleBackgroundChild != null) { canvas.drawRoundRect(mBackgroundAnimationRect.left, mBackgroundAnimationRect.top, mBackgroundAnimationRect.right, mBackgroundAnimationRect.bottom, @@ -585,14 +581,15 @@ public class NotificationStackScrollLayout extends ViewGroup float alpha = BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount); - alpha *= 1f - mDarkAmount; + alpha *= 1f - mInterpolatedDarkAmount; // We need to manually blend in the background color. int scrimColor = mScrimController.getBackgroundColor(); int awakeColor = ColorUtils.blendARGB(scrimColor, mBgColor, alpha); // Interpolate between semi-transparent notification panel background color // and white AOD separator. - float colorInterpolation = Interpolators.DECELERATE_QUINT.getInterpolation(mDarkAmount); + float colorInterpolation = Interpolators.DECELERATE_QUINT.getInterpolation( + mInterpolatedDarkAmount); int color = ColorUtils.blendARGB(awakeColor, Color.WHITE, colorInterpolation); if (mCachedBackgroundColor != color) { @@ -736,7 +733,8 @@ public class NotificationStackScrollLayout extends ViewGroup } private void updateAlgorithmHeightAndPadding() { - mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding, mDarkAmount); + mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding, + mInterpolatedDarkAmount); mAmbientState.setLayoutHeight(getLayoutHeight()); updateAlgorithmLayoutMinHeight(); mAmbientState.setTopPadding(mTopPadding); @@ -961,7 +959,7 @@ public class NotificationStackScrollLayout extends ViewGroup } public void updateClipping() { - boolean animatingClipping = mDarkAmount > 0 && mDarkAmount < 1; + boolean animatingClipping = mInterpolatedDarkAmount > 0 && mInterpolatedDarkAmount < 1; boolean clipped = mRequestedClipBounds != null && !mInHeadsUpPinnedMode && !mHeadsUpAnimatingAway; if (mIsClipped != clipped) { @@ -2421,7 +2419,7 @@ public class NotificationStackScrollLayout extends ViewGroup return; } - final boolean awake = mDarkAmount != 0 || mAmbientState.isDark(); + final boolean awake = mInterpolatedDarkAmount != 0 || mAmbientState.isDark(); mScrimController.setExcludedBackgroundArea( mFadingOut || mParentNotFullyVisible || awake || mIsClipped ? null : mCurrentBounds); @@ -3414,7 +3412,6 @@ public class NotificationStackScrollLayout extends ViewGroup .animateY(mShelf)); ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex; mAnimationEvents.add(ev); - startDarkAmountAnimation(); } mDarkNeedsAnimation = false; } @@ -3990,11 +3987,8 @@ public class NotificationStackScrollLayout extends ViewGroup if (animate && mAnimationsEnabled) { mDarkNeedsAnimation = true; mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation); - mNeedsAnimation = true; + mNeedsAnimation = true; } else { - if (mDarkAmountAnimator != null) { - mDarkAmountAnimator.cancel(); - } setDarkAmount(dark ? 1f : 0f); updateBackground(); } @@ -4005,7 +3999,7 @@ public class NotificationStackScrollLayout extends ViewGroup } private void updatePanelTranslation() { - setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mDarkAmount); + setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount); } public void setVerticalPanelTranslation(float verticalPanelTranslation) { @@ -4024,9 +4018,22 @@ public class NotificationStackScrollLayout extends ViewGroup } private void setDarkAmount(float darkAmount) { - mDarkAmount = darkAmount; + setDarkAmount(darkAmount, darkAmount); + } + + /** + * Sets the current dark amount. + * + * @param linearDarkAmount The dark amount that follows linear interpoloation in the animation, + * i.e. animates from 0 to 1 or vice-versa in a linear manner. + * @param interpolatedDarkAmount The dark amount that follows the actual interpolation of the + * animation curve. + */ + public void setDarkAmount(float linearDarkAmount, float interpolatedDarkAmount) { + mLinearDarkAmount = linearDarkAmount; + mInterpolatedDarkAmount = interpolatedDarkAmount; boolean wasFullyDark = mAmbientState.isFullyDark(); - mAmbientState.setDarkAmount(darkAmount); + mAmbientState.setDarkAmount(interpolatedDarkAmount); boolean nowFullyDark = mAmbientState.isFullyDark(); if (nowFullyDark != wasFullyDark) { updateContentHeight(); @@ -4044,42 +4051,24 @@ public class NotificationStackScrollLayout extends ViewGroup requestChildrenUpdate(); } - public float getDarkAmount() { - return mDarkAmount; - } - - /** - * Cancel any previous dark animations - to avoid race conditions - and creates a new one. - * This function also sets {@code mBackgroundXFactor} based on the current {@code mDarkAmount}. - */ - private void startDarkAmountAnimation() { - boolean dark = mAmbientState.isDark(); - if (mDarkAmountAnimator != null) { - mDarkAmountAnimator.cancel(); + public void notifyDarkAnimationStart(boolean dark) { + // We only swap the scaling factor if we're fully dark or fully awake to avoid + // interpolation issues when playing with the power button. + if (mInterpolatedDarkAmount == 0 || mInterpolatedDarkAmount == 1) { + mBackgroundXFactor = dark ? 1.8f : 1.5f; + mDarkXInterpolator = dark + ? Interpolators.FAST_OUT_SLOW_IN_REVERSE + : Interpolators.FAST_OUT_SLOW_IN; } + } + public long getDarkAnimationDuration(boolean dark) { long duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP; // Longer animation when sleeping with more than 1 notification if (dark && getNotGoneChildCount() > 2) { duration *= 1.2f; } - - mDarkAmountAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount, - dark ? 1f : 0); - // We only swap the scaling factor if we're fully dark or fully awake to avoid - // interpolation issues when playing with the power button. - if (mDarkAmount == 0 || mDarkAmount == 1) { - mBackgroundXFactor = dark ? 2.5f : 1.5f; - } - mDarkAmountAnimator.setDuration(duration); - mDarkAmountAnimator.setInterpolator(Interpolators.LINEAR); - mDarkAmountAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mDarkAmountAnimator = null; - } - }); - mDarkAmountAnimator.start(); + return duration; } private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) { |