summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java')
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java356
1 files changed, 0 insertions, 356 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java b/mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java
deleted file mode 100644
index 8267fe8a3..000000000
--- a/mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright 2012 Roman Nurik
- *
- * 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 org.mozilla.gecko.widget;
-
-import android.graphics.Rect;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.AbsListView.RecyclerListener;
-import android.widget.ListView;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.view.ViewPropertyAnimator;
-
-import org.mozilla.gecko.R;
-
-/**
- * This code is based off of Jake Wharton's NOA port (https://github.com/JakeWharton/SwipeToDismissNOA)
- * of Roman Nurik's SwipeToDismiss library. It has been modified for better support with async
- * adapters.
- *
- * A {@link android.view.View.OnTouchListener} that makes the list items in a {@link ListView}
- * dismissable. {@link ListView} is given special treatment because by default it handles touches
- * for its list items... i.e. it's in charge of drawing the pressed state (the list selector),
- * handling list item clicks, etc.
- *
- * <p>After creating the listener, the caller should also call
- * {@link ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener)}, passing
- * in the scroll listener returned by {@link #makeScrollListener()}. If a scroll listener is
- * already assigned, the caller should still pass scroll changes through to this listener. This will
- * ensure that this {@link SwipeDismissListViewTouchListener} is paused during list view
- * scrolling.</p>
- *
- * <p>Example usage:</p>
- *
- * <pre>
- * SwipeDismissListViewTouchListener touchListener =
- * new SwipeDismissListViewTouchListener(
- * listView,
- * new SwipeDismissListViewTouchListener.OnDismissCallback() {
- * public void onDismiss(ListView listView, int[] reverseSortedPositions) {
- * for (int position : reverseSortedPositions) {
- * adapter.remove(adapter.getItem(position));
- * }
- * adapter.notifyDataSetChanged();
- * }
- * });
- * listView.setOnTouchListener(touchListener);
- * listView.setOnScrollListener(touchListener.makeScrollListener());
- * </pre>
- *
- * <p>For a generalized {@link android.view.View.OnTouchListener} that makes any view dismissable,
- * see {@link SwipeDismissTouchListener}.</p>
- *
- * @see SwipeDismissTouchListener
- */
-public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
- // Cached ViewConfiguration and system-wide constant values
- private final int mSlop;
- private final int mMinFlingVelocity;
- private final int mMaxFlingVelocity;
- private final long mAnimationTime;
-
- // Fixed properties
- private final ListView mListView;
- private final OnDismissCallback mCallback;
- private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
-
- // Transient properties
- private float mDownX;
- private boolean mSwiping;
- private VelocityTracker mVelocityTracker;
- private int mDownPosition;
- private View mDownView;
- private boolean mPaused;
- private boolean mDismissing;
-
- /**
- * The callback interface used by {@link SwipeDismissListViewTouchListener} to inform its client
- * about a successful dismissal of a list item.
- */
- public interface OnDismissCallback {
- /**
- * Called when the user has indicated they she would like to dismiss one or more list item
- * positions.
- *
- * @param listView The originating {@link ListView}.
- * @param position The position being dismissed.
- */
- void onDismiss(ListView listView, int position);
- }
-
- /**
- * Constructs a new swipe-to-dismiss touch listener for the given list view.
- *
- * @param listView The list view whose items should be dismissable.
- * @param callback The callback to trigger when the user has indicated that she would like to
- * dismiss one or more list items.
- */
- public SwipeDismissListViewTouchListener(ListView listView, OnDismissCallback callback) {
- ViewConfiguration vc = ViewConfiguration.get(listView.getContext());
- mSlop = vc.getScaledTouchSlop();
- mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
- mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
- mAnimationTime = listView.getContext().getResources().getInteger(
- android.R.integer.config_shortAnimTime);
- mListView = listView;
- mCallback = callback;
- }
-
- /**
- * Enables or disables (pauses or resumes) watching for swipe-to-dismiss gestures.
- *
- * @param enabled Whether or not to watch for gestures.
- */
- public void setEnabled(boolean enabled) {
- mPaused = !enabled;
- }
-
- /**
- * Returns an {@link android.widget.AbsListView.OnScrollListener} to be added to the
- * {@link ListView} using
- * {@link ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener)}.
- * If a scroll listener is already assigned, the caller should still pass scroll changes
- * through to this listener. This will ensure that this
- * {@link SwipeDismissListViewTouchListener} is paused during list view scrolling.</p>
- *
- * @see {@link SwipeDismissListViewTouchListener}
- */
- public AbsListView.OnScrollListener makeScrollListener() {
- return new AbsListView.OnScrollListener() {
- @Override
- public void onScrollStateChanged(AbsListView absListView, int scrollState) {
- setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
- }
-
- @Override
- public void onScroll(AbsListView absListView, int i, int i1, int i2) {
- }
- };
- }
-
- /**
- * Returns a {@link android.widget.AbsListView.RecyclerListener} to be added to the
- * {@link ListView} using {@link ListView#setRecyclerListener(RecyclerListener)}.
- */
- public AbsListView.RecyclerListener makeRecyclerListener() {
- return new AbsListView.RecyclerListener() {
- @Override
- public void onMovedToScrapHeap(View view) {
- final Object tag = view.getTag(R.id.original_height);
-
- // To reset the view to the correct height after its animation, the view's height
- // is stored in its tag. Reset the view here.
- if (tag instanceof Integer) {
- view.setAlpha(1f);
- view.setTranslationX(0);
- final ViewGroup.LayoutParams lp = view.getLayoutParams();
- lp.height = (int) tag;
- view.setLayoutParams(lp);
- view.setTag(R.id.original_height, null);
- }
- }
- };
- }
-
- @Override
- public boolean onTouch(View view, MotionEvent motionEvent) {
- if (mViewWidth < 2) {
- mViewWidth = mListView.getWidth();
- }
-
- switch (motionEvent.getActionMasked()) {
- case MotionEvent.ACTION_DOWN: {
- if (mPaused) {
- return false;
- }
-
- if (mDismissing) {
- return true;
- }
-
- // TODO: ensure this is a finger, and set a flag
-
- // Find the child view that was touched (perform a hit test)
- Rect rect = new Rect();
- int childCount = mListView.getChildCount();
- int[] listViewCoords = new int[2];
- mListView.getLocationOnScreen(listViewCoords);
- int x = (int) motionEvent.getRawX() - listViewCoords[0];
- int y = (int) motionEvent.getRawY() - listViewCoords[1];
- View child;
- for (int i = 0; i < childCount; i++) {
- child = mListView.getChildAt(i);
- child.getHitRect(rect);
- if (rect.contains(x, y)) {
- mDownView = child;
- break;
- }
- }
-
- if (mDownView != null) {
- mDownX = motionEvent.getRawX();
- mDownPosition = mListView.getPositionForView(mDownView);
-
- mVelocityTracker = VelocityTracker.obtain();
- mVelocityTracker.addMovement(motionEvent);
- }
- view.onTouchEvent(motionEvent);
- return true;
- }
-
- case MotionEvent.ACTION_UP: {
- if (mVelocityTracker == null) {
- break;
- }
-
- float deltaX = motionEvent.getRawX() - mDownX;
- mVelocityTracker.addMovement(motionEvent);
- mVelocityTracker.computeCurrentVelocity(1000);
- float velocityX = Math.abs(mVelocityTracker.getXVelocity());
- float velocityY = Math.abs(mVelocityTracker.getYVelocity());
- boolean dismiss = false;
- boolean dismissRight = false;
- if (Math.abs(deltaX) > mViewWidth / 2) {
- dismiss = true;
- dismissRight = deltaX > 0;
- } else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity
- && velocityY < velocityX) {
- dismiss = true;
- dismissRight = mVelocityTracker.getXVelocity() > 0;
- }
- if (dismiss) {
- // dismiss
- mDismissing = true;
- final View downView = mDownView; // mDownView gets null'd before animation ends
- final int downPosition = mDownPosition;
- mDownView.animate()
- .translationX(dismissRight ? mViewWidth : -mViewWidth)
- .alpha(0)
- .setDuration(mAnimationTime)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- performDismiss(downView, downPosition);
- }
- });
- } else {
- // cancel
- mDownView.animate()
- .translationX(0)
- .alpha(1)
- .setDuration(mAnimationTime)
- .setListener(null);
- }
-
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
-
- mDownX = 0;
- mDownView = null;
- mDownPosition = ListView.INVALID_POSITION;
- mSwiping = false;
- break;
- }
-
- case MotionEvent.ACTION_MOVE: {
- if (mVelocityTracker == null || mPaused) {
- break;
- }
-
- mVelocityTracker.addMovement(motionEvent);
- float deltaX = motionEvent.getRawX() - mDownX;
- if (Math.abs(deltaX) > mSlop) {
- mSwiping = true;
- mListView.requestDisallowInterceptTouchEvent(true);
-
- // Cancel ListView's touch (un-highlighting the item)
- MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
- cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
- (motionEvent.getActionIndex()
- << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
- mListView.onTouchEvent(cancelEvent);
- cancelEvent.recycle();
- }
-
- if (mSwiping) {
- mDownView.setTranslationX(deltaX);
- mDownView.setAlpha(Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX) / mViewWidth)));
- return true;
- }
- break;
- }
- }
- return false;
- }
-
- /**
- * Animate the dismissed list item to zero-height and fire the dismiss callback when it finishes.
- *
- * @param dismissView ListView item to dismiss
- * @param dismissPosition Position of dismissed item
- */
- private void performDismiss(final View dismissView, final int dismissPosition) {
- final ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
- final int originalHeight = lp.height;
-
- ValueAnimator animator = ValueAnimator.ofInt(dismissView.getHeight(), 1).setDuration(mAnimationTime);
-
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Since the view is still a part of the ListView, we can't reset the animated
- // properties yet; otherwise, the view would briefly reappear. Store the original
- // height in the view's tag to flag it for the recycler. This is racy since the user
- // could scroll the dismissed view off the screen, then back on the screen, before
- // it's removed from the adapter, causing the dismissed view to briefly reappear.
- dismissView.setTag(R.id.original_height, originalHeight);
-
- mCallback.onDismiss(mListView, dismissPosition);
- mDismissing = false;
- }
- });
-
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- lp.height = (Integer) valueAnimator.getAnimatedValue();
- dismissView.setLayoutParams(lp);
- }
- });
-
- animator.start();
- }
-}