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

Commit 671e8f91 authored by Winson's avatar Winson
Browse files

Removing custom swipe helper.

Change-Id: Ic28ab343f86ab6f80d8c0409a3218513bd8880af
parent 5500390a
Loading
Loading
Loading
Loading
+18 −7
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ public class SwipeHelper implements Gefingerpoken {
    final private int[] mTmpPos = new int[2];
    private int mFalsingThreshold;
    private boolean mTouchAboveFalsingThreshold;
    private boolean mDisableHwLayers;

    public SwipeHelper(int swipeDirection, Callback callback, Context context) {
        mCallback = callback;
@@ -115,6 +116,10 @@ public class SwipeHelper implements Gefingerpoken {
        mPagingTouchSlop = pagingTouchSlop;
    }

    public void setDisableHardwareLayers(boolean disableHwLayers) {
        mDisableHwLayers = disableHwLayers;
    }

    private float getPos(MotionEvent ev) {
        return mSwipeDirection == X ? ev.getX() : ev.getY();
    }
@@ -147,7 +152,7 @@ public class SwipeHelper implements Gefingerpoken {
        }
    }

    private float getSize(View v) {
    protected float getSize(View v) {
        return mSwipeDirection == X ? v.getMeasuredWidth() :
                v.getMeasuredHeight();
    }
@@ -178,11 +183,13 @@ public class SwipeHelper implements Gefingerpoken {
        if (!mCallback.updateSwipeProgress(animView, dismissable, swipeProgress)) {
            if (FADE_OUT_DURING_SWIPE && dismissable) {
                float alpha = swipeProgress;
                if (!mDisableHwLayers) {
                    if (alpha != 0f && alpha != 1f) {
                        animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
                    } else {
                        animView.setLayerType(View.LAYER_TYPE_NONE, null);
                    }
                }
                animView.setAlpha(getSwipeProgressForOffset(animView));
            }
        }
@@ -345,7 +352,9 @@ public class SwipeHelper implements Gefingerpoken {
            duration = fixedDuration;
        }

        if (!mDisableHwLayers) {
            animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        }
        ObjectAnimator anim = createTranslationAnimation(animView, newPos);
        if (useAccelerateInterpolator) {
            anim.setInterpolator(mFastOutLinearInInterpolator);
@@ -362,8 +371,10 @@ public class SwipeHelper implements Gefingerpoken {
                if (endAction != null) {
                    endAction.run();
                }
                if (!mDisableHwLayers) {
                    animView.setLayerType(View.LAYER_TYPE_NONE, null);
                }
            }
        });
        anim.addUpdateListener(new AnimatorUpdateListener() {
            public void onAnimationUpdate(ValueAnimator animation) {
+0 −403
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.recents.views;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;

/**
 * This class facilitates swipe to dismiss. It defines an interface to be implemented by the
 * by the class hosting the views that need to swiped, and, using this interface, handles touch
 * events and translates / fades / animates the view as it is dismissed.
 */
public class SwipeHelper {
    static final String TAG = "SwipeHelper";
    private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
    private static final boolean CONSTRAIN_SWIPE = true;
    private static final boolean FADE_OUT_DURING_SWIPE = true;
    private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;

    public static final int X = 0;
    public static final int Y = 1;

    private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
    private Interpolator mLinearOutSlowInInterpolator;

    private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
    private int DEFAULT_ESCAPE_ANIMATION_DURATION = 75; // ms
    private int MAX_ESCAPE_ANIMATION_DURATION = 150; // ms
    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms

    public static float ALPHA_FADE_START = 0.15f; // fraction of thumbnail width
                                                 // where fade starts
    static final float ALPHA_FADE_END = 0.65f; // fraction of thumbnail width
                                              // beyond which alpha->0
    private float mMinAlpha = 0f;

    private float mPagingTouchSlop;
    Callback mCallback;
    private int mSwipeDirection;
    private VelocityTracker mVelocityTracker;

    private float mInitialTouchPos;
    private boolean mDragging;
    private float mSnapBackTranslationX;

    private View mCurrView;
    private boolean mCanCurrViewBeDimissed;
    private float mDensityScale;

    public boolean mAllowSwipeTowardsStart = true;
    public boolean mAllowSwipeTowardsEnd = true;
    private boolean mRtl;

    public SwipeHelper(Context context, int swipeDirection, Callback callback, float densityScale,
            float pagingTouchSlop) {
        mCallback = callback;
        mSwipeDirection = swipeDirection;
        mVelocityTracker = VelocityTracker.obtain();
        mDensityScale = densityScale;
        mPagingTouchSlop = pagingTouchSlop;
        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                com.android.internal.R.interpolator.linear_out_slow_in);
    }

    public void setDensityScale(float densityScale) {
        mDensityScale = densityScale;
    }

    public void setSnapBackTranslationX(float translationX) {
        mSnapBackTranslationX = translationX;
    }

    public void setPagingTouchSlop(float pagingTouchSlop) {
        mPagingTouchSlop = pagingTouchSlop;
    }

    public void cancelOngoingDrag() {
        if (mDragging) {
            if (mCurrView != null) {
                mCallback.onDragCancelled(mCurrView);
                setTranslation(mCurrView, 0);
                mCallback.onSnapBackCompleted(mCurrView);
                mCurrView = null;
            }
            mDragging = false;
        }
    }

    public void resetTranslation(View v) {
        setTranslation(v, 0);
    }

    private float getPos(MotionEvent ev) {
        return mSwipeDirection == X ? ev.getX() : ev.getY();
    }

    private float getTranslation(View v) {
        return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
    }

    private float getVelocity(VelocityTracker vt) {
        return mSwipeDirection == X ? vt.getXVelocity() :
                vt.getYVelocity();
    }

    private ObjectAnimator createTranslationAnimation(View v, float newPos) {
        ObjectAnimator anim = ObjectAnimator.ofFloat(v,
                mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
        return anim;
    }

    private float getPerpendicularVelocity(VelocityTracker vt) {
        return mSwipeDirection == X ? vt.getYVelocity() :
                vt.getXVelocity();
    }

    private void setTranslation(View v, float translate) {
        if (mSwipeDirection == X) {
            v.setTranslationX(translate);
        } else {
            v.setTranslationY(translate);
        }
    }

    private float getSize(View v) {
        final DisplayMetrics dm = v.getContext().getResources().getDisplayMetrics();
        return mSwipeDirection == X ? dm.widthPixels : dm.heightPixels;
    }

    public void setMinAlpha(float minAlpha) {
        mMinAlpha = minAlpha;
    }

    float getAlphaForOffset(View view) {
        float viewSize = getSize(view);
        final float fadeSize = ALPHA_FADE_END * viewSize;
        float result = 1.0f;
        float pos = getTranslation(view);
        if (pos >= viewSize * ALPHA_FADE_START) {
            result = 1.0f - (pos - viewSize * ALPHA_FADE_START) / fadeSize;
        } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) {
            result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
        }
        result = Math.min(result, 1.0f);
        result = Math.max(result, 0f);
        return Math.max(mMinAlpha, result);
    }

    /**
     * Determines whether the given view has RTL layout.
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    public static boolean isLayoutRtl(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return View.LAYOUT_DIRECTION_RTL == view.getLayoutDirection();
        } else {
            return false;
        }
    }

    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mDragging = false;
                mCurrView = mCallback.getChildAtPosition(ev);
                mVelocityTracker.clear();
                if (mCurrView != null) {
                    mRtl = isLayoutRtl(mCurrView);
                    mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
                    mVelocityTracker.addMovement(ev);
                    mInitialTouchPos = getPos(ev);
                } else {
                    mCanCurrViewBeDimissed = false;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (mCurrView != null) {
                    mVelocityTracker.addMovement(ev);
                    float pos = getPos(ev);
                    float delta = pos - mInitialTouchPos;
                    if (Math.abs(delta) > mPagingTouchSlop) {
                        mCallback.onBeginDrag(mCurrView);
                        mDragging = true;
                        mInitialTouchPos = pos - getTranslation(mCurrView);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mDragging = false;
                mCurrView = null;
                break;
        }
        return mDragging;
    }

    /**
     * @param view The view to be dismissed
     * @param velocity The desired pixels/second speed at which the view should move
     */
    private void dismissChild(final View view, float velocity) {
        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
        float newPos;
        if (velocity < 0
                || (velocity == 0 && getTranslation(view) < 0)
                // if we use the Menu to dismiss an item in landscape, animate up
                || (velocity == 0 && getTranslation(view) == 0 && mSwipeDirection == Y)) {
            newPos = -getSize(view);
        } else {
            newPos = getSize(view);
        }
        int duration = MAX_ESCAPE_ANIMATION_DURATION;
        if (velocity != 0) {
            duration = Math.min(duration,
                                (int) (Math.abs(newPos - getTranslation(view)) *
                                        1000f / Math.abs(velocity)));
        } else {
            duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
        }

        ValueAnimator anim = createTranslationAnimation(view, newPos);
        anim.setInterpolator(sLinearInterpolator);
        anim.setDuration(duration);
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mCallback.onChildDismissed(view);
                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
                    view.setAlpha(1.f);
                }
            }
        });
        anim.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
                    view.setAlpha(getAlphaForOffset(view));
                }
            }
        });
        anim.start();
    }

    private void snapChild(final View view, float velocity) {
        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
        ValueAnimator anim = createTranslationAnimation(view, mSnapBackTranslationX);
        int duration = SNAP_ANIM_LEN;
        anim.setDuration(duration);
        anim.setInterpolator(mLinearOutSlowInInterpolator);
        anim.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
                    view.setAlpha(getAlphaForOffset(view));
                }
                mCallback.onSwipeChanged(mCurrView, view.getTranslationX());
            }
        });
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
                    view.setAlpha(1.0f);
                }
                mCallback.onSnapBackCompleted(view);
            }
        });
        anim.start();
    }

    public boolean onTouchEvent(MotionEvent ev) {
        if (!mDragging) {
            if (!onInterceptTouchEvent(ev)) {
                return mCanCurrViewBeDimissed;
            }
        }

        mVelocityTracker.addMovement(ev);
        final int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_OUTSIDE:
            case MotionEvent.ACTION_MOVE:
                if (mCurrView != null) {
                    float delta = getPos(ev) - mInitialTouchPos;
                    setSwipeAmount(delta);
                    mCallback.onSwipeChanged(mCurrView, delta);
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (mCurrView != null) {
                    endSwipe(mVelocityTracker);
                }
                break;
        }
        return true;
    }

    private void setSwipeAmount(float amount) {
        // don't let items that can't be dismissed be dragged more than
        // maxScrollDistance
        if (CONSTRAIN_SWIPE
                && (!isValidSwipeDirection(amount) || !mCallback.canChildBeDismissed(mCurrView))) {
            float size = getSize(mCurrView);
            float maxScrollDistance = 0.15f * size;
            if (Math.abs(amount) >= size) {
                amount = amount > 0 ? maxScrollDistance : -maxScrollDistance;
            } else {
                amount = maxScrollDistance * (float) Math.sin((amount/size)*(Math.PI/2));
            }
        }
        setTranslation(mCurrView, amount);
        if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) {
            float alpha = getAlphaForOffset(mCurrView);
            mCurrView.setAlpha(alpha);
        }
    }

    private boolean isValidSwipeDirection(float amount) {
        if (mSwipeDirection == X) {
            if (mRtl) {
                return (amount <= 0) ? mAllowSwipeTowardsEnd : mAllowSwipeTowardsStart;
            } else {
                return (amount <= 0) ? mAllowSwipeTowardsStart : mAllowSwipeTowardsEnd;
            }
        }

        // Vertical swipes are always valid.
        return true;
    }

    private void endSwipe(VelocityTracker velocityTracker) {
        velocityTracker.computeCurrentVelocity(1000 /* px/sec */);
        float velocity = getVelocity(velocityTracker);
        float perpendicularVelocity = getPerpendicularVelocity(velocityTracker);
        float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale;
        float translation = getTranslation(mCurrView);
        // Decide whether to dismiss the current view
        boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
                Math.abs(translation) > 0.6 * getSize(mCurrView);
        boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
                (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
                (velocity > 0) == (translation > 0);

        boolean dismissChild = mCallback.canChildBeDismissed(mCurrView)
                && isValidSwipeDirection(translation)
                && (childSwipedFastEnough || childSwipedFarEnough);

        if (dismissChild) {
            // flingadingy
            dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f);
        } else {
            // snappity
            mCallback.onDragCancelled(mCurrView);
            snapChild(mCurrView, velocity);
        }
    }

    public interface Callback {
        View getChildAtPosition(MotionEvent ev);

        boolean canChildBeDismissed(View v);

        void onBeginDrag(View v);

        void onSwipeChanged(View v, float delta);

        void onChildDismissed(View v);

        void onSnapBackCompleted(View v);

        void onDragCancelled(View v);
    }
}
+3 −8
Original line number Diff line number Diff line
@@ -1115,14 +1115,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        }
    }

    public boolean isTransformedTouchPointInView(float x, float y, TaskView tv) {
        final float[] point = new float[2];
        point[0] = x;
        point[1] = y;
        transformPointToViewLocal(point, tv);
        x = point[0];
        y = point[1];
        return (0 <= x) && (x < tv.getWidth()) && (0 <= y) && (y < tv.getHeight());
    public boolean isTouchPointInView(float x, float y, TaskView tv) {
        return (tv.getLeft() <= x && x <= tv.getRight()) &&
                (tv.getTop() <= y && y <= tv.getBottom());
    }

    @Override
+32 −12
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
@@ -29,6 +30,7 @@ import android.view.ViewConfiguration;
import android.view.ViewParent;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
@@ -80,19 +82,21 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
        Resources res = context.getResources();
        ViewConfiguration configuration = ViewConfiguration.get(context);
        mContext = context;
        mSv = sv;
        mScroller = scroller;
        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
        mScrollTouchSlop = configuration.getScaledTouchSlop();
        mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
        mSv = sv;
        mScroller = scroller;
        mFlingAnimUtils = new FlingAnimationUtils(context, 0.2f);

        float densityScale = res.getDisplayMetrics().density;
        mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_stack_overscroll);
        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale,
                configuration.getScaledPagingTouchSlop());
        mSwipeHelper.setMinAlpha(1f);
        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context) {
            @Override
            protected float getSize(View v) {
                return mSv.getWidth();
            }
        };
        mSwipeHelper.setDisableHardwareLayers(true);
    }

    /** Velocity tracker helpers */
@@ -117,7 +121,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
        for (int i = taskViewCount - 1; i >= 0; i--) {
            TaskView tv = taskViews.get(i);
            if (tv.getVisibility() == View.VISIBLE) {
                if (mSv.isTransformedTouchPointInView(x, y, tv)) {
                if (mSv.isTouchPointInView(x, y, tv)) {
                    return tv;
                }
            }
@@ -345,7 +349,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
    @Override
    public void onBeginDrag(View v) {
        TaskView tv = (TaskView) v;
        mSwipeHelper.setSnapBackTranslationX(tv.getTranslationX());

        // Disable clipping with the stack while we are swiping
        tv.setClipViewInStack(false);
        // Disallow touch events from this task view
@@ -358,8 +362,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
    }

    @Override
    public void onSwipeChanged(View v, float delta) {
        // Do nothing
    public boolean updateSwipeProgress(View v, boolean dismissable, float swipeProgress) {
        return true;
    }

    @Override
@@ -377,7 +381,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
    }

    @Override
    public void onSnapBackCompleted(View v) {
    public void onChildSnappedBack(View v) {
        TaskView tv = (TaskView) v;
        // Re-enable clipping with the stack
        tv.setClipViewInStack(true);
@@ -389,4 +393,20 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
    public void onDragCancelled(View v) {
        // Do nothing
    }

    @Override
    public View getChildContentView(View v) {
        return v;
    }

    @Override
    public boolean isAntiFalsingNeeded() {
        return false;
    }

    @Override
    public float getFalsingThresholdFactor() {
        return 0;
    }

}