1135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren/* 2135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * Copyright (C) 2012 The Android Open Source Project 3135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * 4135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * Licensed under the Apache License, Version 2.0 (the "License"); 5135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * you may not use this file except in compliance with the License. 6135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * You may obtain a copy of the License at 7135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * 8135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * http://www.apache.org/licenses/LICENSE-2.0 9135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * 10135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * Unless required by applicable law or agreed to in writing, software 11135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * distributed under the License is distributed on an "AS IS" BASIS, 12135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * See the License for the specific language governing permissions and 14135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * limitations under the License. 15135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren */ 16135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wrenpackage com.android.dreams.phototable; 17135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 18135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wrenimport android.content.Context; 19135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wrenimport android.content.res.Resources; 20135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wrenimport android.util.Log; 21135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wrenimport android.view.MotionEvent; 22135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wrenimport android.view.View; 23135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wrenimport android.view.ViewConfiguration; 24135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wrenimport android.view.ViewPropertyAnimator; 25135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wrenimport android.view.animation.DecelerateInterpolator; 26135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 27135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren/** 28135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren * Touch listener that implements phototable interactions. 29135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren */ 30135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wrenpublic class PhotoTouchListener implements View.OnTouchListener { 31135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private static final String TAG = "PhotoTouchListener"; 32c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren private static final boolean DEBUG = false; 33135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private static final int INVALID_POINTER = -1; 34135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private static final int MAX_POINTER_COUNT = 10; 35135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private final int mTouchSlop; 36135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private final int mTapTimeout; 37d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren private final PhotoTable mTable; 38135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private final float mBeta; 39135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private final float mTableRatio; 40135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private final boolean mEnableFling; 41135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private final boolean mManualImageRotation; 42135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private long mLastEventTime; 43135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float mLastTouchX; 44135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float mLastTouchY; 45135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float mInitialTouchX; 46135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float mInitialTouchY; 47135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float mInitialTouchA; 48135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private long mInitialTouchTime; 49135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float mInitialTargetX; 50135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float mInitialTargetY; 51135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float mInitialTargetA; 52135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float mDX; 53135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float mDY; 54135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private int mA = INVALID_POINTER; 55135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private int mB = INVALID_POINTER; 56135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float[] pts = new float[MAX_POINTER_COUNT]; 57135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float[] tmp = new float[MAX_POINTER_COUNT]; 58135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 59d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren public PhotoTouchListener(Context context, PhotoTable table) { 60135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mTable = table; 61135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final ViewConfiguration configuration = ViewConfiguration.get(context); 62135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mTouchSlop = configuration.getScaledTouchSlop(); 63135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mTapTimeout = configuration.getTapTimeout(); 64135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final Resources resources = context.getResources(); 65135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mBeta = resources.getInteger(R.integer.table_damping) / 1000000f; 66135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mTableRatio = resources.getInteger(R.integer.table_ratio) / 1000000f; 67135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mEnableFling = resources.getBoolean(R.bool.enable_fling); 68135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mManualImageRotation = resources.getBoolean(R.bool.enable_manual_image_rotation); 69135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 70135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 71135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren /** Get angle defined by first two touches, in degrees */ 72135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private float getAngle(View target, MotionEvent ev) { 73135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren float alpha = 0f; 74135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren int a = ev.findPointerIndex(mA); 75135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren int b = ev.findPointerIndex(mB); 76135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (a >=0 && b >=0) { 77135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren alpha = (float) (Math.atan2(pts[2*a + 1] - pts[2*b + 1], 78135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren pts[2*a] - pts[2*b]) * 79135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 180f / Math.PI); 80135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 81135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren return alpha; 82135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 83135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 84135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private void resetTouch(View target) { 85135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTouchX = -1; 86135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTouchY = -1; 87135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTouchA = 0f; 88135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTargetX = (float) target.getX(); 89135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTargetY = (float) target.getY(); 90135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTargetA = (float) target.getRotation(); 91135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 92135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 93135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren public void onFling(View target, float dX, float dY) { 94135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (!mEnableFling) { 95135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren return; 96135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 97f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren log("fling " + dX + ", " + dY); 98135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 99135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren // convert to pixel per frame 100135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren dX /= 60f; 101135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren dY /= 60f; 102135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 103135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren // starting position compionents in global corrdinate frame 104135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float x0 = pts[0]; 105135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float y0 = pts[1]; 106135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 107135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren // velocity 108135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float v = (float) Math.hypot(dX, dY); 109135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 110135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (v == 0f) { 111135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren return; 112135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 113135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 114135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren // number of steps to come to a stop 115135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float n = (float) Math.max(1.0, (- Math.log(v) / Math.log(mBeta))); 116135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren // distance travelled before stopping 117135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float s = (float) Math.max(0.0, (v * (1f - Math.pow(mBeta, n)) / (1f - mBeta))); 118135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 119135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren // ending posiiton after stopping 120135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float x1 = x0 + s * dX / v; 121135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float y1 = y0 + s * dY / v; 122135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 123135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float photoWidth = ((Integer) target.getTag(R.id.photo_width)).floatValue(); 124135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float photoHeight = ((Integer) target.getTag(R.id.photo_height)).floatValue(); 125135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float tableWidth = mTable.getWidth(); 126135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float tableHeight = mTable.getHeight(); 127135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final float halfShortSide = 128135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren Math.min(photoWidth * mTableRatio, photoHeight * mTableRatio) / 2f; 129135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final View photo = target; 130135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren ViewPropertyAnimator animator = photo.animate() 131135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren .xBy(x1 - x0) 132135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren .yBy(y1 - y0) 133135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren .setDuration((int) (1000f * n / 60f)) 134135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren .setInterpolator(new DecelerateInterpolator(2f)); 135135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 136135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (y1 + halfShortSide < 0f || y1 - halfShortSide > tableHeight || 137135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren x1 + halfShortSide < 0f || x1 - halfShortSide > tableWidth) { 138135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren log("fling away"); 139135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren animator.withEndAction(new Runnable() { 140135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren @Override 141135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren public void run() { 142135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mTable.fadeAway(photo, true); 143135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 144135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren }); 145135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 146135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 147135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 148135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren @Override 149135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren public boolean onTouch(View target, MotionEvent ev) { 150135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren final int action = ev.getActionMasked(); 151135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 152135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren // compute raw coordinates 153135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren for(int i = 0; i < 10 && i < ev.getPointerCount(); i++) { 154135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren pts[i*2] = ev.getX(i); 155135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren pts[i*2 + 1] = ev.getY(i); 156135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 157135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren target.getMatrix().mapPoints(pts); 158135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 159135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren switch (action) { 160135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren case MotionEvent.ACTION_DOWN: 161135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mTable.moveToBackOfQueue(target); 162135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTouchTime = ev.getEventTime(); 163135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mA = ev.getPointerId(ev.getActionIndex()); 164135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren resetTouch(target); 165135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren break; 166135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 167135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren case MotionEvent.ACTION_POINTER_DOWN: 168135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (mB == INVALID_POINTER) { 169135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mB = ev.getPointerId(ev.getActionIndex()); 170135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTouchA = getAngle(target, ev); 171135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 172135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren break; 173135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 174135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren case MotionEvent.ACTION_POINTER_UP: 175135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (mB == ev.getPointerId(ev.getActionIndex())) { 176135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mB = INVALID_POINTER; 177135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTargetA = (float) target.getRotation(); 178135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 179135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (mA == ev.getPointerId(ev.getActionIndex())) { 180f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren log("primary went up!"); 181135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mA = mB; 182135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren resetTouch(target); 183135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mB = INVALID_POINTER; 184135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 185135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren break; 186135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 187135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren case MotionEvent.ACTION_MOVE: { 188135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (mA != INVALID_POINTER) { 189135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren int idx = ev.findPointerIndex(mA); 190135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren float x = pts[2 * idx]; 191135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren float y = pts[2 * idx + 1]; 192135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (mInitialTouchX == -1 && mInitialTouchY == -1) { 193135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTouchX = x; 194135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTouchY = y; 195135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } else { 196135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren float dt = (float) (ev.getEventTime() - mLastEventTime) / 1000f; 197f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren float tmpDX = (x - mLastTouchX) / dt; 198f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren float tmpDY = (y - mLastTouchY) / dt; 199f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren if (dt > 0f && (Math.abs(tmpDX) > 5f || Math.abs(tmpDY) > 5f)) { 200f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren // work around odd bug with multi-finger flings 201f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren mDX = tmpDX; 202f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren mDY = tmpDY; 203f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren } 204f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren log("move " + mDX + ", " + mDY); 205f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren 206135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mLastEventTime = ev.getEventTime(); 207135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mLastTouchX = x; 208135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mLastTouchY = y; 209135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 210135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 211135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (mTable.getSelected() != target) { 212135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren target.animate().cancel(); 213135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 214135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren target.setX((int) (mInitialTargetX + x - mInitialTouchX)); 215135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren target.setY((int) (mInitialTargetY + y - mInitialTouchY)); 216135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (mManualImageRotation && mB != INVALID_POINTER) { 217135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren float a = getAngle(target, ev); 218135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren target.setRotation( 219135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren (int) (mInitialTargetA + a - mInitialTouchA)); 220135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 221135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 222135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 223135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 224135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren break; 225135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 226135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren case MotionEvent.ACTION_UP: { 227135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (mA != INVALID_POINTER) { 228135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren int idx = ev.findPointerIndex(mA); 229135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren float x0 = pts[2 * idx]; 230135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren float y0 = pts[2 * idx + 1]; 231135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (mInitialTouchX == -1 && mInitialTouchY == -1) { 232135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTouchX = x0; 233135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mInitialTouchY = y0; 234135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 235135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren double distance = Math.hypot(x0 - mInitialTouchX, 236135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren y0 - mInitialTouchY); 237135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (mTable.getSelected() == target) { 238135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mTable.dropOnTable(target); 239135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mTable.clearSelection(); 240135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } else if ((ev.getEventTime() - mInitialTouchTime) < mTapTimeout && 241135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren distance < mTouchSlop) { 242135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren // tap 243135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren target.animate().cancel(); 244135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mTable.setSelection(target); 245135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } else { 246135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren onFling(target, mDX, mDY); 247135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 248135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mA = INVALID_POINTER; 249135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren mB = INVALID_POINTER; 250135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 251135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 252135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren break; 253135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 254135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren case MotionEvent.ACTION_CANCEL: 255f61019ceb816fed9e5035c3d9b8451f6e4ee1da9Chris Wren log("action cancel!"); 256135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren break; 257135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 258135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 259135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren return true; 260135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 261135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren 262135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren private static void log(String message) { 263135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren if (DEBUG) { 264135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren Log.i(TAG, message); 265135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 266135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren } 267135f525b62eb20c31c593e09f8bdb92215d538a4Chris Wren} 268