Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 332c23fe authored by Selim Cinek's avatar Selim Cinek
Browse files

Added new appear and disappear animations for heads up

The heads up notifications now appear directly out of the
statusbar icon in a smoother way. This also fixes the
landscape presentation, which was completely wrong
before.

Test: runtest systemui
Change-Id: I84e65d5216f74a9eb1717d3e7c111d66c0b43c65
Fixes: 72748440
parent d03518ca
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
    android:layout_width="match_parent"
    android:layout_width="match_parent"
    android:visibility="invisible"
    android:visibility="invisible"
    android:id="@+id/heads_up_status_bar_view"
    android:id="@+id/heads_up_status_bar_view"
    android:alpha="0"
>
>
    <!-- This is a space just used as a layout and it's not actually displaying anything. We're
    <!-- This is a space just used as a layout and it's not actually displaying anything. We're
         repositioning the statusbar icon to the position where this is laid out when showing this
         repositioning the statusbar icon to the position where this is laid out when showing this
+49 −9
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Color;
import android.graphics.RectF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewAnimationUtils;
@@ -178,6 +179,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    private boolean mNeedsDimming;
    private boolean mNeedsDimming;
    private int mDimmedAlpha;
    private int mDimmedAlpha;
    private boolean mBlockNextTouch;
    private boolean mBlockNextTouch;
    private boolean mIsHeadsUpAnimation;
    private int mHeadsUpAddStartLocation;
    private float mHeadsUpLocation;
    private boolean mIsAppearing;


    public ActivatableNotificationView(Context context, AttributeSet attrs) {
    public ActivatableNotificationView(Context context, AttributeSet attrs) {
        super(context, attrs);
        super(context, attrs);
@@ -204,6 +209,18 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
                makeInactive(true /* animate */);
                makeInactive(true /* animate */);
            }
            }
        }, super::performClick, this::handleSlideBack, mFalsingManager::onNotificationDoubleTap);
        }, super::performClick, this::handleSlideBack, mFalsingManager::onNotificationDoubleTap);
        initDimens();
    }

    private void initDimens() {
        mHeadsUpAddStartLocation = getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.notification_content_margin_start);
    }

    @Override
    public void onDensityOrFontScaleChanged() {
        super.onDensityOrFontScaleChanged();
        initDimens();
    }
    }


    @Override
    @Override
@@ -745,27 +762,34 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    }
    }


    @Override
    @Override
    public void performRemoveAnimation(long duration, float translationDirection,
    public void performRemoveAnimation(long duration, long delay,
            Runnable onFinishedRunnable) {
            float translationDirection, boolean isHeadsUpAnimation, float endLocation,
            Runnable onFinishedRunnable, AnimatorListenerAdapter animationListener) {
        enableAppearDrawing(true);
        enableAppearDrawing(true);
        mIsHeadsUpAnimation = isHeadsUpAnimation;
        mHeadsUpLocation = endLocation;
        if (mDrawingAppearAnimation) {
        if (mDrawingAppearAnimation) {
            startAppearAnimation(false /* isAppearing */, translationDirection,
            startAppearAnimation(false /* isAppearing */, translationDirection,
                    0, duration, onFinishedRunnable);
                    delay, duration, onFinishedRunnable, animationListener);
        } else if (onFinishedRunnable != null) {
        } else if (onFinishedRunnable != null) {
            onFinishedRunnable.run();
            onFinishedRunnable.run();
        }
        }
    }
    }


    @Override
    @Override
    public void performAddAnimation(long delay, long duration) {
    public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) {
        enableAppearDrawing(true);
        enableAppearDrawing(true);
        mIsHeadsUpAnimation = isHeadsUpAppear;
        mHeadsUpLocation = mHeadsUpAddStartLocation;
        if (mDrawingAppearAnimation) {
        if (mDrawingAppearAnimation) {
            startAppearAnimation(true /* isAppearing */, -1.0f, delay, duration, null);
            startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay,
                    duration, null, null);
        }
        }
    }
    }


    private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
    private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
            long duration, final Runnable onFinishedRunnable) {
            long duration, final Runnable onFinishedRunnable,
            AnimatorListenerAdapter animationListener) {
        cancelAppearAnimation();
        cancelAppearAnimation();
        mAnimationTranslationY = translationDirection * getActualHeight();
        mAnimationTranslationY = translationDirection * getActualHeight();
        if (mAppearAnimationFraction == -1.0f) {
        if (mAppearAnimationFraction == -1.0f) {
@@ -778,6 +802,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
                mAppearAnimationTranslation = 0;
                mAppearAnimationTranslation = 0;
            }
            }
        }
        }
        mIsAppearing = isAppearing;


        float targetValue;
        float targetValue;
        if (isAppearing) {
        if (isAppearing) {
@@ -803,6 +828,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
                invalidate();
                invalidate();
            }
            }
        });
        });
        if (animationListener != null) {
            mAppearAnimator.addListener(animationListener);
        }
        if (delay > 0) {
        if (delay > 0) {
            // we need to apply the initial state already to avoid drawn frames in the wrong state
            // we need to apply the initial state already to avoid drawn frames in the wrong state
            updateAppearAnimationAlpha();
            updateAppearAnimationAlpha();
@@ -862,9 +890,21 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
                / (HORIZONTAL_ANIMATION_START - HORIZONTAL_ANIMATION_END);
                / (HORIZONTAL_ANIMATION_START - HORIZONTAL_ANIMATION_END);
        widthFraction = Math.min(1.0f, Math.max(0.0f, widthFraction));
        widthFraction = Math.min(1.0f, Math.max(0.0f, widthFraction));
        widthFraction = mCurrentAppearInterpolator.getInterpolation(widthFraction);
        widthFraction = mCurrentAppearInterpolator.getInterpolation(widthFraction);
        float left = (getWidth() * (0.5f - HORIZONTAL_COLLAPSED_REST_PARTIAL / 2.0f) *
        float startWidthFraction = HORIZONTAL_COLLAPSED_REST_PARTIAL;
                widthFraction);
        if (mIsHeadsUpAnimation && !mIsAppearing) {
        float right = getWidth() - left;
            startWidthFraction = 0;
        }
        float width = MathUtils.lerp(startWidthFraction, 1.0f, 1.0f - widthFraction)
                        * getWidth();
        float left;
        float right;
        if (mIsHeadsUpAnimation) {
            left = MathUtils.lerp(mHeadsUpLocation, 0, 1.0f - widthFraction);
            right = left + width;
        } else {
            left = getWidth() * 0.5f - width / 2.0f;
            right = getWidth() - left;
        }


        // handle top animation
        // handle top animation
        float heightFraction = (inverseFraction - (1.0f - VERTICAL_ANIMATION_START)) /
        float heightFraction = (inverseFraction - (1.0f - VERTICAL_ANIMATION_START)) /
+14 −8
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.systemui.statusbar;
package com.android.systemui.statusbar;


import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Rect;
@@ -296,19 +297,24 @@ public abstract class ExpandableView extends FrameLayout {


    /**
    /**
     * Perform a remove animation on this view.
     * Perform a remove animation on this view.
     *
     * @param duration The duration of the remove animation.
     * @param duration The duration of the remove animation.
     * @param delay The delay of the animation
     * @param translationDirection The direction value from [-1 ... 1] indicating in which the
     * @param translationDirection The direction value from [-1 ... 1] indicating in which the
 *                             animation should be performed. A value of -1 means that The
 *                             animation should be performed. A value of -1 means that The
 *                             remove animation should be performed upwards,
 *                             remove animation should be performed upwards,
 *                             such that the  child appears to be going away to the top. 1
 *                             such that the  child appears to be going away to the top. 1
 *                             Should mean the opposite.
 *                             Should mean the opposite.
     * @param isHeadsUpAnimation Is this a headsUp animation.
     * @param endLocation The location where the horizonal heads up disappear animation should end.
     * @param onFinishedRunnable A runnable which should be run when the animation is finished.
     * @param onFinishedRunnable A runnable which should be run when the animation is finished.
     * @param animationListener An animation listener to add to the animation.
     */
     */
    public abstract void performRemoveAnimation(long duration, float translationDirection,
    public abstract void performRemoveAnimation(long duration,
            Runnable onFinishedRunnable);
            long delay, float translationDirection, boolean isHeadsUpAnimation, float endLocation,
            Runnable onFinishedRunnable,
            AnimatorListenerAdapter animationListener);


    public abstract void performAddAnimation(long delay, long duration);
    public abstract void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear);


    /**
    /**
     * Set the notification appearance to be below the speed bump.
     * Set the notification appearance to be below the speed bump.
+66 −6
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
package com.android.systemui.statusbar;


import android.content.Context;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.AttributeSet;
@@ -37,10 +38,15 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
    private View mIconPlaceholder;
    private View mIconPlaceholder;
    private TextView mTextView;
    private TextView mTextView;
    private NotificationData.Entry mShowingEntry;
    private NotificationData.Entry mShowingEntry;
    private Rect mIconRect = new Rect();
    private Rect mLayoutedIconRect = new Rect();
    private int[] mTmpPosition = new int[2];
    private int[] mTmpPosition = new int[2];
    private boolean mFirstLayout = true;
    private boolean mFirstLayout = true;
    private boolean mPublicMode;
    private boolean mPublicMode;
    private int mMaxWidth;
    private View mRootView;
    private int mLeftInset;
    private Rect mIconDrawingRect = new Rect();
    private Runnable mOnDrawingRectChangedListener;


    public HeadsUpStatusBarView(Context context) {
    public HeadsUpStatusBarView(Context context) {
        this(context, null);
        this(context, null);
@@ -64,6 +70,33 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
        mEndMargin = res.getDimensionPixelSize(
        mEndMargin = res.getDimensionPixelSize(
                com.android.internal.R.dimen.notification_content_margin_end);
                com.android.internal.R.dimen.notification_content_margin_end);
        setPaddingRelative(mAbsoluteStartPadding, 0, mEndMargin, 0);
        setPaddingRelative(mAbsoluteStartPadding, 0, mEndMargin, 0);
        updateMaxWidth();
    }

    private void updateMaxWidth() {
        int maxWidth = getResources().getDimensionPixelSize(R.dimen.qs_panel_width);
        if (maxWidth != mMaxWidth) {
            // maxWidth doesn't work with fill_parent, let's manually make it at most as big as the
            // notification panel
            mMaxWidth = maxWidth;
            requestLayout();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mMaxWidth > 0) {
            int newSize = Math.min(MeasureSpec.getSize(widthMeasureSpec), mMaxWidth);
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(newSize,
                    MeasureSpec.getMode(widthMeasureSpec));
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        updateMaxWidth();
    }
    }


    @VisibleForTesting
    @VisibleForTesting
@@ -97,13 +130,15 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        super.onLayout(changed, l, t, r, b);
        mIconPlaceholder.getLocationOnScreen(mTmpPosition);
        mIconPlaceholder.getLocationOnScreen(mTmpPosition);
        int left = mTmpPosition[0];
        int left = (int) (mTmpPosition[0] - getTranslationX());
        int top = mTmpPosition[1];
        int top = mTmpPosition[1];
        int right = left + mIconPlaceholder.getWidth();
        int right = left + mIconPlaceholder.getWidth();
        int bottom = top + mIconPlaceholder.getHeight();
        int bottom = top + mIconPlaceholder.getHeight();
        mIconRect.set(left, top, right, bottom);
        mLayoutedIconRect.set(left, top, right, bottom);
        if (left != mAbsoluteStartPadding) {
        updateDrawingRect();
            int newPadding = mAbsoluteStartPadding - left + getPaddingStart();
        int targetPadding = mAbsoluteStartPadding + mLeftInset;
        if (left != targetPadding) {
            int newPadding = targetPadding - left + getPaddingStart();
            setPaddingRelative(newPadding, 0, mEndMargin, 0);
            setPaddingRelative(newPadding, 0, mEndMargin, 0);
        }
        }
        if (mFirstLayout) {
        if (mFirstLayout) {
@@ -115,12 +150,33 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
        }
        }
    }
    }


    @Override
    public void setTranslationX(float translationX) {
        super.setTranslationX(translationX);
        updateDrawingRect();
    }

    private void updateDrawingRect() {
        float oldLeft = mIconDrawingRect.left;
        mIconDrawingRect.set(mLayoutedIconRect);
        mIconDrawingRect.offset((int) getTranslationX(), 0);
        if (oldLeft != mIconDrawingRect.left && mOnDrawingRectChangedListener != null) {
            mOnDrawingRectChangedListener.run();
        }
    }

    @Override
    protected boolean fitSystemWindows(Rect insets) {
        mLeftInset = insets.left;
        return super.fitSystemWindows(insets);
    }

    public NotificationData.Entry getShowingEntry() {
    public NotificationData.Entry getShowingEntry() {
        return mShowingEntry;
        return mShowingEntry;
    }
    }


    public Rect getIconDrawingRect() {
    public Rect getIconDrawingRect() {
        return mIconRect;
        return mIconDrawingRect;
    }
    }


    public void onDarkChanged(Rect area, float darkIntensity, int tint) {
    public void onDarkChanged(Rect area, float darkIntensity, int tint) {
@@ -130,4 +186,8 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
    public void setPublicMode(boolean publicMode) {
    public void setPublicMode(boolean publicMode) {
        mPublicMode = publicMode;
        mPublicMode = publicMode;
    }
    }

    public void setOnDrawingRectChangedListener(Runnable onDrawingRectChangedListener) {
        mOnDrawingRectChangedListener = onDrawingRectChangedListener;
    }
}
}
+6 −3
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.systemui.statusbar;
package com.android.systemui.statusbar;


import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.Context;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.view.View;
import android.view.View;
@@ -112,14 +113,16 @@ public abstract class StackScrollerDecorView extends ExpandableView {
    }
    }


    @Override
    @Override
    public void performRemoveAnimation(long duration, float translationDirection,
    public void performRemoveAnimation(long duration, long delay,
            Runnable onFinishedRunnable) {
            float translationDirection, boolean isHeadsUpAnimation, float endLocation,
            Runnable onFinishedRunnable,
            AnimatorListenerAdapter animationListener) {
        // TODO: Use duration
        // TODO: Use duration
        performVisibilityAnimation(false);
        performVisibilityAnimation(false);
    }
    }


    @Override
    @Override
    public void performAddAnimation(long delay, long duration) {
    public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) {
        // TODO: use delay and duration
        // TODO: use delay and duration
        performVisibilityAnimation(true);
        performVisibilityAnimation(true);
    }
    }
Loading