From 1dc94b55d59f5c4dbf86788d0c32b7ac4449909a Mon Sep 17 00:00:00 2001 From: Chris Wren Date: Thu, 21 Mar 2013 15:35:16 -0400 Subject: add two-finger move gesture. Bug: 8387448 Change-Id: Ib8a54ee3e978df3c5d15058d4fe82b9e7d6a524b --- res/values/config.xml | 3 + .../dreams/phototable/DragGestureDetector.java | 115 +++++++++++++++++++++ src/com/android/dreams/phototable/PhotoTable.java | 42 ++++++-- .../dreams/phototable/PhotoTouchListener.java | 12 +-- 4 files changed, 155 insertions(+), 17 deletions(-) create mode 100644 src/com/android/dreams/phototable/DragGestureDetector.java diff --git a/res/values/config.xml b/res/values/config.xml index b871820..1c9de4a 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -94,5 +94,8 @@ touch area width, in parts per million from 0 to 1. --> 100000 + + 2000000 + diff --git a/src/com/android/dreams/phototable/DragGestureDetector.java b/src/com/android/dreams/phototable/DragGestureDetector.java new file mode 100644 index 0000000..739163d --- /dev/null +++ b/src/com/android/dreams/phototable/DragGestureDetector.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2013 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.dreams.phototable; + +import android.content.Context; +import android.content.res.Resources; +import android.util.Log; +import android.view.MotionEvent; + +/** + * Detect and dispatch edge events. + */ +public class DragGestureDetector { + private static final String TAG = "DragGestureDetector"; + + private final PhotoTable mTable; + private final float mTouchGain; + + private int mPointer; + private float[] mLast; + private float[] mCurrent; + private boolean mDrag; + + public DragGestureDetector(Context context, PhotoTable table) { + Resources res = context.getResources(); + mTouchGain = res.getInteger(R.integer.generalized_touch_gain) / 1000000f; + mTable = table; + mLast = new float[2]; + mCurrent = new float[2]; + } + + private void computeAveragePosition(MotionEvent event, float[] position) { + computeAveragePosition(event, position, -1); + } + + private void computeAveragePosition(MotionEvent event, float[] position, int ignore) { + final int pointerCount = event.getPointerCount(); + position[0] = 0f; + position[1] = 0f; + float count = 0f; + for (int p = 0; p < pointerCount; p++) { + if (p != ignore) { + position[0] += event.getX(p); + position[1] += event.getY(p); + count += 1f; + } + } + position[0] /= count; + position[1] /= count; + } + + public boolean onTouchEvent(MotionEvent event) { + int index = event.getActionIndex(); + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + mPointer = event.getPointerId(index); + computeAveragePosition(event, mLast); + mDrag = false; + break; + + case MotionEvent.ACTION_POINTER_DOWN: + mDrag = mTable.hasFocus(); + computeAveragePosition(event, mLast); + break; + + case MotionEvent.ACTION_POINTER_UP: + computeAveragePosition(event, mLast, index); + break; + + case MotionEvent.ACTION_MOVE: + computeAveragePosition(event, mCurrent); + if (mDrag) { + move(event, false); + } + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + if (mDrag) { + move(event, true); + } + mDrag = false; + break; + } + + if (mDrag) { + mTable.refreshFocus(); + } + + return mDrag; + } + + private void move(MotionEvent event, boolean drop) { + mTable.move(mTable.getFocused(), + mTouchGain * (mCurrent[0] - mLast[0]), + mTouchGain * (mCurrent[1] - mLast[1]), + drop); + mLast[0] = mCurrent[0]; + mLast[1] = mCurrent[1]; + } +} + diff --git a/src/com/android/dreams/phototable/PhotoTable.java b/src/com/android/dreams/phototable/PhotoTable.java index a6d5bd7..4cf278c 100644 --- a/src/com/android/dreams/phototable/PhotoTable.java +++ b/src/com/android/dreams/phototable/PhotoTable.java @@ -24,6 +24,7 @@ import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.PointF; import android.graphics.PorterDuff; +import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; @@ -90,6 +91,8 @@ public class PhotoTable extends FrameLayout { private final Resources mResources; private final Interpolator mThrowInterpolator; private final Interpolator mDropInterpolator; + final private EdgeSwipeDetector mEdgeSwipeDetector; + final private DragGestureDetector mDragGestureDetector; private DreamService mDream; private PhotoLaunchTask mPhotoLaunchTask; private boolean mStarted; @@ -103,7 +106,6 @@ public class PhotoTable extends FrameLayout { private View mFocused; private long mFocusedTime; private int mHighlightColor; - private EdgeSwipeDetector mEdgeSwipeDetector; public PhotoTable(Context context, AttributeSet as) { super(context, as); @@ -132,6 +134,7 @@ public class PhotoTable extends FrameLayout { mLauncher = new Launcher(); mFocusReaper = new FocusReaper(); mEdgeSwipeDetector = new EdgeSwipeDetector(context, this); + mDragGestureDetector = new DragGestureDetector(context, this); mStarted = false; } @@ -365,7 +368,7 @@ public class PhotoTable extends FrameLayout { @Override public boolean onGenericMotionEvent(MotionEvent event) { - return mEdgeSwipeDetector.onTouchEvent(event); + return mEdgeSwipeDetector.onTouchEvent(event) || mDragGestureDetector.onTouchEvent(event); } @Override @@ -544,6 +547,19 @@ public class PhotoTable extends FrameLayout { dropOnTable(photo, mThrowInterpolator); } + public void move(final View photo, float dx, float dy, boolean drop) { + if (photo != null) { + final float x = photo.getX() + dx; + final float y = photo.getY() + dy; + photo.setX(x); + photo.setY(y); + Log.d(TAG, "[" + photo.getX() + ", " + photo.getY() + "] + (" + dx + "," + dy + ")"); + if (drop && photoOffTable(photo)) { + fadeAway(photo, true); + } + } + } + public void fling(final View photo) { final float[] o = { mWidth + mLongSide / 2f, mHeight + mLongSide / 2f }; @@ -561,11 +577,10 @@ public class PhotoTable extends FrameLayout { final float dist = (float) Math.hypot(delta[0], delta[1]); final int duration = (int) (1000f * dist / mThrowSpeed); - fling(photo, delta[0], delta[1], duration, true, true); + fling(photo, delta[0], delta[1], duration, true); } - public void fling(final View photo, float dx, float dy, int duration, - boolean flingAway, boolean spin) { + public void fling(final View photo, float dx, float dy, int duration, boolean spin) { if (photo == getFocused()) { if (moveFocus(photo, 0f) == null) { moveFocus(photo, 180f); @@ -581,7 +596,7 @@ public class PhotoTable extends FrameLayout { animator.rotation(mThrowRotation); } - if (flingAway) { + if (photoOffTable(photo, (int) dx, (int) dy)) { log("fling away"); animator.withEndAction(new Runnable() { @Override @@ -591,6 +606,17 @@ public class PhotoTable extends FrameLayout { }); } } + public boolean photoOffTable(final View photo) { + return photoOffTable(photo, 0, 0); + } + + public boolean photoOffTable(final View photo, final int dx, final int dy) { + Rect hit = new Rect(); + photo.getHitRect(hit); + hit.offset(dx, dy); + return (hit.bottom < 0f || hit.top > getHeight() || + hit.right < 0f || hit.left > getWidth()); + } public void dropOnTable(final View photo) { dropOnTable(photo, mDropInterpolator); @@ -707,6 +733,10 @@ public class PhotoTable extends FrameLayout { } } + public void refreshFocus() { + scheduleFocusReaper(MAX_FOCUS_TIME); + } + public void scheduleFocusReaper(int delay) { removeCallbacks(mFocusReaper); postDelayed(mFocusReaper, delay); diff --git a/src/com/android/dreams/phototable/PhotoTouchListener.java b/src/com/android/dreams/phototable/PhotoTouchListener.java index fd52749..190dc3d 100644 --- a/src/com/android/dreams/phototable/PhotoTouchListener.java +++ b/src/com/android/dreams/phototable/PhotoTouchListener.java @@ -118,17 +118,7 @@ public class PhotoTouchListener implements View.OnTouchListener { final float x1 = x0 + s * dX / v; final float y1 = y0 + s * dY / v; - final float photoWidth = ((Integer) target.getTag(R.id.photo_width)).floatValue(); - final float photoHeight = ((Integer) target.getTag(R.id.photo_height)).floatValue(); - final float tableWidth = mTable.getWidth(); - final float tableHeight = mTable.getHeight(); - final float halfShortSide = - Math.min(photoWidth * mTableRatio, photoHeight * mTableRatio) / 2f; - final View photo = target; - boolean flingAway = y1 + halfShortSide < 0f || y1 - halfShortSide > tableHeight || - x1 + halfShortSide < 0f || x1 - halfShortSide > tableWidth; - - mTable.fling(photo, x1 - x0, y1 - y0, (int) (1000f * n / 60f), flingAway, false); + mTable.fling(target, x1 - x0, y1 - y0, (int) (1000f * n / 60f), false); } @Override -- cgit v1.2.3