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

Commit af4cec33 authored by Daniel Sandler's avatar Daniel Sandler Committed by Android (Google) Code Review
Browse files

Merge "Swipe to veto in notifications."

parents 0656bc32 ad6352be
Loading
Loading
Loading
Loading
+131 −15
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
@@ -30,6 +31,8 @@ import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Slog;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
@@ -45,10 +48,15 @@ import com.android.systemui.R;
public class NotificationRowLayout extends ViewGroup {
    private static final String TAG = "NotificationRowLayout";
    private static final boolean DEBUG = false;
    private static final boolean SLOW_ANIMATIONS = false; // DEBUG;

    private static final boolean ANIMATE_LAYOUT = true;

    private static final int ANIM_LEN = DEBUG ? 5000 : 250;
    private static final int APPEAR_ANIM_LEN = SLOW_ANIMATIONS ? 5000 : 250;
    private static final int DISAPPEAR_ANIM_LEN = APPEAR_ANIM_LEN;
    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250;

    private static final float SWIPE_ESCAPE_VELOCITY = 1500f;

    Rect mTmpRect = new Rect();
    int mNumRows = 0;
@@ -58,6 +66,11 @@ public class NotificationRowLayout extends ViewGroup {
    HashSet<View> mAppearingViews = new HashSet<View>();
    HashSet<View> mDisappearingViews = new HashSet<View>();

    VelocityTracker mVT;
    float mInitialTouchX, mInitialTouchY;
    View mSlidingChild = null;
    float mLiftoffVelocity;

    public NotificationRowLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
@@ -65,6 +78,8 @@ public class NotificationRowLayout extends ViewGroup {
    public NotificationRowLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mVT = VelocityTracker.obtain();

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NotificationRowLayout,
                defStyle, 0);
        mRowHeight = a.getDimensionPixelSize(R.styleable.NotificationRowLayout_rowHeight, 0);
@@ -89,6 +104,92 @@ public class NotificationRowLayout extends ViewGroup {

    }

    // Swipey code
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
//        if (DEBUG) Slog.d(TAG, "intercepting touch event: " + ev);
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mVT.clear();
                mVT.addMovement(ev);
                mInitialTouchX = ev.getX();
                mInitialTouchY = ev.getY();
                mSlidingChild = null;
                break;
            case MotionEvent.ACTION_MOVE:
                mVT.addMovement(ev);
                if (mSlidingChild == null) {
                    if (Math.abs(ev.getX() - mInitialTouchX) > 4) { // slide slop

                        // find the view under the pointer, accounting for GONE views
                        final int count = getChildCount();
                        int y = 0;
                        int childIdx = 0;
                        for (; childIdx < count; childIdx++) {
                            mSlidingChild = getChildAt(childIdx);
                            if (mSlidingChild.getVisibility() == GONE) {
                                continue;
                            }
                            y += mRowHeight;
                            if (mInitialTouchY < y) break;
                        }

                        mInitialTouchX -= mSlidingChild.getTranslationX();
                        mSlidingChild.animate().cancel();

                        if (DEBUG) {
                            Slog.d(TAG, String.format(
                                "now sliding child %d: %s (touchY=%.1f, rowHeight=%d, count=%d)",
                                childIdx, mSlidingChild, mInitialTouchY, mRowHeight, count));
                        }
                    }
                }
                break;
        }
        return mSlidingChild != null;
    }
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
//        if (DEBUG) Slog.d(TAG, "touch event: " + ev + " sliding: " + mSlidingChild);
        if (mSlidingChild != null) {
            switch (action) {
                case MotionEvent.ACTION_OUTSIDE:
                case MotionEvent.ACTION_MOVE:
                    mVT.addMovement(ev);

                    mSlidingChild.setTranslationX(ev.getX() - mInitialTouchX);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    mVT.addMovement(ev);
                    mVT.computeCurrentVelocity(1000 /* px/sec */);
                    if (DEBUG) Slog.d(TAG, "exit velocity: " + mVT.getXVelocity());
                    boolean restore = true;
                    mLiftoffVelocity = mVT.getXVelocity();
                    if (Math.abs(mLiftoffVelocity) > SWIPE_ESCAPE_VELOCITY) {
                        // flingadingy

                        View veto = mSlidingChild.findViewById(R.id.veto);
                        if (veto != null && veto.getVisibility() == View.VISIBLE) {
                            veto.performClick();
                            restore = false;
                        }
                    }
                    if (restore) {
                        // snappity
                        mSlidingChild.animate().translationX(0)
                            .setDuration(SNAP_ANIM_LEN)
                            .start();
                    }
                    break;
            }
            return true;
        }
        return false;
    }

    //**
    @Override
    public void addView(View child, int index, LayoutParams params) {
@@ -105,7 +206,7 @@ public class NotificationRowLayout extends ViewGroup {
                    ObjectAnimator.ofFloat(child, "alpha", 0f, 1f)
//                    ,ObjectAnimator.ofFloat(child, "scaleY", 0f, 1f)
            );
            a.setDuration(ANIM_LEN);
            a.setDuration(APPEAR_ANIM_LEN);
            a.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
@@ -127,21 +228,36 @@ public class NotificationRowLayout extends ViewGroup {
            mDisappearingViews.add(child);

            child.setPivotY(0);
            AnimatorSet a = new AnimatorSet();
            a.playTogether(
                    ObjectAnimator.ofFloat(child, "alpha", 0f)
//                    ,ObjectAnimator.ofFloat(child, "scaleY", 0f)
                    ,ObjectAnimator.ofFloat(child, "translationX", 300f)
            );
            a.setDuration(ANIM_LEN);
            a.addListener(new AnimatorListenerAdapter() {

            final float velocity = (mSlidingChild == child) 
                    ? mLiftoffVelocity : SWIPE_ESCAPE_VELOCITY;
            final TimeAnimator zoom = new TimeAnimator();
            zoom.setTimeListener(new TimeAnimator.TimeListener() {
                @Override
                public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
                    childF.setTranslationX(childF.getTranslationX() + deltaTime / 1000f * velocity);
                }
            });

            final ObjectAnimator alphaFade = ObjectAnimator.ofFloat(child, "alpha", 0f);
            alphaFade.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    zoom.cancel(); // it won't end on its own
                    if (DEBUG) Slog.d(TAG, "actually removing child: " + childF);
                    NotificationRowLayout.super.removeView(childF);
                    childF.setAlpha(1f);
                    mDisappearingViews.remove(childF);
                }
            });

            AnimatorSet a = new AnimatorSet();
            a.playTogether(alphaFade, zoom);
                    
//                    ,ObjectAnimator.ofFloat(child, "scaleY", 0f)
//                    ,ObjectAnimator.ofFloat(child, "translationX", child.getTranslationX() + 300f)

            a.setDuration(DISAPPEAR_ANIM_LEN);
            a.start();
            requestLayout(); // start the container animation
        } else {
@@ -160,8 +276,8 @@ public class NotificationRowLayout extends ViewGroup {
    public void onDraw(android.graphics.Canvas c) {
        super.onDraw(c);
        if (DEBUG) {
            Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
                    + getMeasuredHeight() + "px");
            //Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
            //        + getMeasuredHeight() + "px");
            c.save();
            c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
                    android.graphics.Region.Op.DIFFERENCE);
@@ -199,7 +315,7 @@ public class NotificationRowLayout extends ViewGroup {

            if (ANIMATE_LAYOUT && isShown()) {
                ObjectAnimator.ofInt(this, "forcedHeight", computedHeight)
                    .setDuration(ANIM_LEN)
                    .setDuration(APPEAR_ANIM_LEN)
                    .start();
            } else {
                setForcedHeight(computedHeight);
@@ -230,7 +346,7 @@ public class NotificationRowLayout extends ViewGroup {
        final int width = right - left;
        final int height = bottom - top;

        if (DEBUG) Slog.d(TAG, "onLayout: height=" + height);
        //if (DEBUG) Slog.d(TAG, "onLayout: height=" + height);

        final int count = getChildCount();
        int y = 0;
@@ -252,7 +368,7 @@ public class NotificationRowLayout extends ViewGroup {
    }

    public void setForcedHeight(int h) {
        if (DEBUG) Slog.d(TAG, "forcedHeight: " + h);
        //if (DEBUG) Slog.d(TAG, "forcedHeight: " + h);
        if (h != mHeight) {
            mHeight = h;
            requestLayout();