diff options
6 files changed, 141 insertions, 33 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java index bddd3e6158c1..758fb7a9971e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java @@ -23,6 +23,7 @@ import android.view.animation.Interpolator;  import android.view.animation.PathInterpolator;  import com.android.systemui.Interpolators; +import com.android.systemui.statusbar.notification.NotificationUtils;  /**   * Utility class to calculate general fling animation when the finger is released. @@ -30,28 +31,63 @@ import com.android.systemui.Interpolators;  public class FlingAnimationUtils {      private static final float LINEAR_OUT_SLOW_IN_X2 = 0.35f; +    private static final float LINEAR_OUT_SLOW_IN_X2_MAX = 0.68f;      private static final float LINEAR_OUT_FASTER_IN_X2 = 0.5f;      private static final float LINEAR_OUT_FASTER_IN_Y2_MIN = 0.4f;      private static final float LINEAR_OUT_FASTER_IN_Y2_MAX = 0.5f;      private static final float MIN_VELOCITY_DP_PER_SECOND = 250;      private static final float HIGH_VELOCITY_DP_PER_SECOND = 3000; -    /** -     * Crazy math. http://en.wikipedia.org/wiki/B%C3%A9zier_curve -     */ -    private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 1.0f / LINEAR_OUT_SLOW_IN_X2; - -    private Interpolator mLinearOutSlowIn; +    private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 0.75f; +    private final float mSpeedUpFactor; +    private final float mY2;      private float mMinVelocityPxPerSecond;      private float mMaxLengthSeconds;      private float mHighVelocityPxPerSecond; +    private float mLinearOutSlowInX2;      private AnimatorProperties mAnimatorProperties = new AnimatorProperties(); +    private PathInterpolator mInterpolator; +    private float mCachedStartGradient = -1; +    private float mCachedVelocityFactor = -1;      public FlingAnimationUtils(Context ctx, float maxLengthSeconds) { +        this(ctx, maxLengthSeconds, 0.0f); +    } + +    /** +     * @param maxLengthSeconds the longest duration an animation can become in seconds +     * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards +     *                      the end of the animation. 0 means it's at the beginning and no +     *                      acceleration will take place. +     */ +    public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor) { +        this(ctx, maxLengthSeconds, speedUpFactor, -1.0f, 1.0f); +    } + +    /** +     * @param maxLengthSeconds the longest duration an animation can become in seconds +     * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards +     *                      the end of the animation. 0 means it's at the beginning and no +     *                      acceleration will take place. +     * @param x2 the x value to take for the second point of the bezier spline. If a value below 0 +     *           is provided, the value is automatically calculated. +     * @param y2 the y value to take for the second point of the bezier spline +     */ +    public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor, float x2, +            float y2) {          mMaxLengthSeconds = maxLengthSeconds; -        mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_X2, 1); +        mSpeedUpFactor = speedUpFactor; +        if (x2 < 0) { +            mLinearOutSlowInX2 = NotificationUtils.interpolate(LINEAR_OUT_SLOW_IN_X2, +                    LINEAR_OUT_SLOW_IN_X2_MAX, +                    mSpeedUpFactor); +        } else { +            mLinearOutSlowInX2 = x2; +        } +        mY2 = y2; +          mMinVelocityPxPerSecond                  = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;          mHighVelocityPxPerSecond @@ -129,9 +165,14 @@ public class FlingAnimationUtils {                  * Math.sqrt(Math.abs(endValue - currValue) / maxDistance));          float diff = Math.abs(endValue - currValue);          float velAbs = Math.abs(velocity); -        float durationSeconds = LINEAR_OUT_SLOW_IN_START_GRADIENT * diff / velAbs; +        float velocityFactor = mSpeedUpFactor == 0.0f +                ? 1.0f : Math.min(velAbs / HIGH_VELOCITY_DP_PER_SECOND, 1.0f); +        float startGradient = NotificationUtils.interpolate(LINEAR_OUT_SLOW_IN_START_GRADIENT, +                mY2 / mLinearOutSlowInX2, velocityFactor); +        float durationSeconds = startGradient * diff / velAbs; +        Interpolator slowInInterpolator = getInterpolator(startGradient, velocityFactor);          if (durationSeconds <= maxLengthSeconds) { -            mAnimatorProperties.interpolator = mLinearOutSlowIn; +            mAnimatorProperties.interpolator = slowInInterpolator;          } else if (velAbs >= mMinVelocityPxPerSecond) {              // Cross fade between fast-out-slow-in and linear interpolator with current velocity. @@ -139,7 +180,7 @@ public class FlingAnimationUtils {              VelocityInterpolator velocityInterpolator                      = new VelocityInterpolator(durationSeconds, velAbs, diff);              InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator( -                    velocityInterpolator, mLinearOutSlowIn, mLinearOutSlowIn); +                    velocityInterpolator, slowInInterpolator, Interpolators.LINEAR_OUT_SLOW_IN);              mAnimatorProperties.interpolator = superInterpolator;          } else { @@ -151,6 +192,19 @@ public class FlingAnimationUtils {          return mAnimatorProperties;      } +    private Interpolator getInterpolator(float startGradient, float velocityFactor) { +        if (startGradient != mCachedStartGradient +                || velocityFactor != mCachedVelocityFactor) { +            float speedup = mSpeedUpFactor * (1.0f - velocityFactor); +            mInterpolator = new PathInterpolator(speedup, +                    speedup * startGradient, +                    mLinearOutSlowInX2, mY2); +            mCachedStartGradient = startGradient; +            mCachedVelocityFactor = velocityFactor; +        } +        return mInterpolator; +    } +      /**       * Applies the interpolator and length to the animator, such that the fling animation is       * consistent with the finger motion for the case when the animation is making something @@ -212,7 +266,7 @@ public class FlingAnimationUtils {              VelocityInterpolator velocityInterpolator                      = new VelocityInterpolator(durationSeconds, velAbs, diff);              InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator( -                    velocityInterpolator, mLinearOutFasterIn, mLinearOutSlowIn); +                    velocityInterpolator, mLinearOutFasterIn, Interpolators.LINEAR_OUT_SLOW_IN);              mAnimatorProperties.interpolator = superInterpolator;          } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 296c788b13d5..bc1b9fb89270 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -66,6 +66,7 @@ public class NotificationShelf extends ActivatableNotificationView {      private int mScrollFastThreshold;      private int mStatusBarState;      private float mMaxShelfEnd; +    private int mRelativeOffset;      public NotificationShelf(Context context, AttributeSet attrs) {          super(context, attrs); @@ -475,9 +476,21 @@ public class NotificationShelf extends ActivatableNotificationView {          return super.shouldHideBackground() || mHideBackground;      } -    private void setOpenedAmount(float openedAmount) { +    @Override +    protected void onLayout(boolean changed, int left, int top, int right, int bottom) { +        super.onLayout(changed, left, top, right, bottom);          mCollapsedIcons.getLocationOnScreen(mTmp); -        int start = mTmp[0]; +        mRelativeOffset = mTmp[0]; +        getLocationOnScreen(mTmp); +        mRelativeOffset -= mTmp[0]; +    } + +    private void setOpenedAmount(float openedAmount) { +        if (!mAmbientState.isPanelFullWidth()) { +            // We don't do a transformation at all, lets just assume we are fully opened +            openedAmount = 1.0f; +        } +        int start = mRelativeOffset;          if (isLayoutRtl()) {              start = getWidth() - start - mCollapsedIcons.getWidth();          } 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 7f6322ae058f..82a5cc2bf415 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -210,6 +210,7 @@ public class NotificationPanelView extends PanelView implements      private NotificationGroupManager mGroupManager;      private boolean mOpening;      private int mIndicationBottomPadding; +    private boolean mIsFullWidth;      public NotificationPanelView(Context context, AttributeSet attrs) {          super(context, attrs); @@ -302,6 +303,7 @@ public class NotificationPanelView extends PanelView implements      @Override      protected void onLayout(boolean changed, int left, int top, int right, int bottom) {          super.onLayout(changed, left, top, right, bottom); +        setIsFullWidth(mNotificationStackScroller.getWidth() == getWidth());          // Update Clock Pivot          mKeyguardStatusView.setPivotX(getWidth() / 2); @@ -340,6 +342,11 @@ public class NotificationPanelView extends PanelView implements          updateMaxHeadsUpTranslation();      } +    private void setIsFullWidth(boolean isFullWidth) { +        mIsFullWidth = isFullWidth; +        mNotificationStackScroller.setIsFullWidth(isFullWidth); +    } +      private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {          if (mQsSizeChangeAnimator != null) {              oldHeight = (int) mQsSizeChangeAnimator.getAnimatedValue(); @@ -736,7 +743,7 @@ public class NotificationPanelView extends PanelView implements      @Override      protected float getOpeningHeight() { -        return mNotificationStackScroller.getMinExpansionHeight(); +        return mNotificationStackScroller.getOpeningHeight();      }      @Override @@ -2000,12 +2007,9 @@ public class NotificationPanelView extends PanelView implements      }      @Override -    protected float getCannedFlingDurationFactor() { -        if (mQsExpanded) { -            return 0.9f; -        } else { -            return 0.8f; -        } +    protected boolean shouldUseDismissingAnimation() { +        return mStatusBarState != StatusBarState.SHADE +                && !mStatusBar.isKeyguardCurrentlySecure();      }      @Override @@ -2288,7 +2292,15 @@ public class NotificationPanelView extends PanelView implements          }          mNotificationStackScroller.setExpandedHeight(expandedHeight);          updateKeyguardBottomAreaAlpha(); -        setOpening(expandedHeight <= getOpeningHeight()); +        setOpening(isFullWidth() && expandedHeight < getOpeningHeight()); +    } + +    /** +     * @return whether the notifications are displayed full width and don't have any margins on +     *         the side. +     */ +    public boolean isFullWidth() { +        return mIsFullWidth;      }      private void setOpening(boolean opening) { @@ -2401,12 +2413,11 @@ public class NotificationPanelView extends PanelView implements      }      public boolean shouldHideNotificationIcons() { -        return !mOpening && !isFullyCollapsed(); +        return !isFullWidth() || (!mOpening && !isFullyCollapsed());      }      public boolean shouldAnimateIconHiding() { -        // TODO: handle this correctly, not completely working yet -        return mNotificationStackScroller.getTranslationX() != 0; +        return !isFullWidth();      }      private final FragmentListener mFragmentListener = new FragmentListener() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 7bb075b716b7..18e394e2836a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -94,6 +94,7 @@ public abstract class PanelView extends FrameLayout {      private VelocityTrackerInterface mVelocityTracker;      private FlingAnimationUtils mFlingAnimationUtils;      private FlingAnimationUtils mFlingAnimationUtilsClosing; +    private FlingAnimationUtils mFlingAnimationUtilsDismissing;      private FalsingManager mFalsingManager;      /** @@ -180,8 +181,13 @@ public abstract class PanelView extends FrameLayout {      public PanelView(Context context, AttributeSet attrs) {          super(context, attrs); -        mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f); -        mFlingAnimationUtilsClosing = new FlingAnimationUtils(context, 0.4f); +        mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f /* maxLengthSeconds */, +                0.6f /* speedUpFactor */); +        mFlingAnimationUtilsClosing = new FlingAnimationUtils(context, 0.5f /* maxLengthSeconds */, +                0.6f /* speedUpFactor */); +        mFlingAnimationUtilsDismissing = new FlingAnimationUtils(context, +                0.5f /* maxLengthSeconds */, 0.2f /* speedUpFactor */, 0.6f /* x2 */, +                0.84f /* y2 */);          mBounceInterpolator = new BounceInterpolator();          mFalsingManager = FalsingManager.getInstance(context);      } @@ -700,13 +706,17 @@ public abstract class PanelView extends FrameLayout {                  animator.setDuration(350);              }          } else { -            mFlingAnimationUtilsClosing.apply(animator, mExpandedHeight, target, vel, getHeight()); +            if (shouldUseDismissingAnimation()) { +                mFlingAnimationUtilsDismissing.apply(animator, mExpandedHeight, target, vel, +                        getHeight()); +            } else { +                mFlingAnimationUtilsClosing +                        .apply(animator, mExpandedHeight, target, vel, getHeight()); +            }              // Make it shorter if we run a canned animation              if (vel == 0) { -                animator.setDuration((long) -                        (animator.getDuration() * getCannedFlingDurationFactor() -                                / collapseSpeedUpFactor)); +                animator.setDuration((long) (animator.getDuration() / collapseSpeedUpFactor));              }          }          animator.addListener(new AnimatorListenerAdapter() { @@ -733,6 +743,8 @@ public abstract class PanelView extends FrameLayout {          animator.start();      } +    protected abstract boolean shouldUseDismissingAnimation(); +      @Override      protected void onAttachedToWindow() {          super.onAttachedToWindow(); @@ -1114,9 +1126,6 @@ public abstract class PanelView extends FrameLayout {      public abstract void resetViews();      protected abstract float getPeekHeight(); - -    protected abstract float getCannedFlingDurationFactor(); -      /**       * @return whether "Clear all" button will be visible when the panel is fully expanded       */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java index e1ff29703da7..fe83dc47649e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java @@ -58,6 +58,7 @@ public class AmbientState {      private float mExpandingVelocity;      private boolean mPanelTracking;      private boolean mExpansionChanging; +    private boolean mPanelFullWidth;      public AmbientState(Context context) {          reload(context); @@ -287,4 +288,12 @@ public class AmbientState {      public boolean isPanelTracking() {          return mPanelTracking;      } + +    public boolean isPanelFullWidth() { +        return mPanelFullWidth; +    } + +    public void setPanelFullWidth(boolean panelFullWidth) { +        mPanelFullWidth = panelFullWidth; +    }  } 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 e7c2507dbf18..06cd769ed73d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -4012,6 +4012,18 @@ public class NotificationStackScrollLayout extends ViewGroup          mAmbientState.setExpandingVelocity(expandingVelocity);      } +    public float getOpeningHeight() { +        if (mEmptyShadeView.getVisibility() == GONE) { +            return getMinExpansionHeight(); +        } else { +            return getAppearEndPosition(); +        } +    } + +    public void setIsFullWidth(boolean isFullWidth) { +        mAmbientState.setPanelFullWidth(isFullWidth); +    } +      /**       * A listener that is notified when some child locations might have changed.       */  |