Home | History | Annotate | Download | only in touchexample
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.example.android.touchexample;
     17 
     18 import android.content.Context;
     19 import android.os.Build;
     20 import android.util.Log;
     21 import android.view.MotionEvent;
     22 import android.view.ScaleGestureDetector;
     23 
     24 public abstract class VersionedGestureDetector {
     25     private static final String TAG = "VersionedGestureDetector";
     26 
     27     OnGestureListener mListener;
     28 
     29     public static VersionedGestureDetector newInstance(Context context,
     30             OnGestureListener listener) {
     31         final int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
     32         VersionedGestureDetector detector = null;
     33         if (sdkVersion < Build.VERSION_CODES.ECLAIR) {
     34             detector = new CupcakeDetector();
     35         } else if (sdkVersion < Build.VERSION_CODES.FROYO) {
     36             detector = new EclairDetector();
     37         } else {
     38             detector = new FroyoDetector(context);
     39         }
     40 
     41         Log.d(TAG, "Created new " + detector.getClass());
     42         detector.mListener = listener;
     43 
     44         return detector;
     45     }
     46 
     47     public abstract boolean onTouchEvent(MotionEvent ev);
     48 
     49     public interface OnGestureListener {
     50         public void onDrag(float dx, float dy);
     51         public void onScale(float scaleFactor);
     52     }
     53 
     54     private static class CupcakeDetector extends VersionedGestureDetector {
     55         float mLastTouchX;
     56         float mLastTouchY;
     57 
     58         float getActiveX(MotionEvent ev) {
     59             return ev.getX();
     60         }
     61 
     62         float getActiveY(MotionEvent ev) {
     63             return ev.getY();
     64         }
     65 
     66         boolean shouldDrag() {
     67             return true;
     68         }
     69 
     70         @Override
     71         public boolean onTouchEvent(MotionEvent ev) {
     72             switch (ev.getAction()) {
     73             case MotionEvent.ACTION_DOWN: {
     74                 mLastTouchX = getActiveX(ev);
     75                 mLastTouchY = getActiveY(ev);
     76                 break;
     77             }
     78             case MotionEvent.ACTION_MOVE: {
     79                 final float x = getActiveX(ev);
     80                 final float y = getActiveY(ev);
     81 
     82                 if (shouldDrag()) {
     83                     mListener.onDrag(x - mLastTouchX, y - mLastTouchY);
     84                 }
     85 
     86                 mLastTouchX = x;
     87                 mLastTouchY = y;
     88                 break;
     89             }
     90             }
     91             return true;
     92         }
     93     }
     94 
     95     private static class EclairDetector extends CupcakeDetector {
     96         private static final int INVALID_POINTER_ID = -1;
     97         private int mActivePointerId = INVALID_POINTER_ID;
     98         private int mActivePointerIndex = 0;
     99 
    100         @Override
    101         float getActiveX(MotionEvent ev) {
    102             return ev.getX(mActivePointerIndex);
    103         }
    104 
    105         @Override
    106         float getActiveY(MotionEvent ev) {
    107             return ev.getY(mActivePointerIndex);
    108         }
    109 
    110         @Override
    111         public boolean onTouchEvent(MotionEvent ev) {
    112             final int action = ev.getAction();
    113             switch (action & MotionEvent.ACTION_MASK) {
    114             case MotionEvent.ACTION_DOWN:
    115                 mActivePointerId = ev.getPointerId(0);
    116                 break;
    117             case MotionEvent.ACTION_CANCEL:
    118             case MotionEvent.ACTION_UP:
    119                 mActivePointerId = INVALID_POINTER_ID;
    120                 break;
    121             case MotionEvent.ACTION_POINTER_UP:
    122                 final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
    123                         >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
    124                 final int pointerId = ev.getPointerId(pointerIndex);
    125                 if (pointerId == mActivePointerId) {
    126                     // This was our active pointer going up. Choose a new
    127                     // active pointer and adjust accordingly.
    128                     final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
    129                     mActivePointerId = ev.getPointerId(newPointerIndex);
    130                     mLastTouchX = ev.getX(newPointerIndex);
    131                     mLastTouchY = ev.getY(newPointerIndex);
    132                 }
    133                 break;
    134             }
    135 
    136             mActivePointerIndex = ev.findPointerIndex(mActivePointerId);
    137             return super.onTouchEvent(ev);
    138         }
    139     }
    140 
    141     private static class FroyoDetector extends EclairDetector {
    142         private ScaleGestureDetector mDetector;
    143 
    144         public FroyoDetector(Context context) {
    145             mDetector = new ScaleGestureDetector(context,
    146                     new ScaleGestureDetector.SimpleOnScaleGestureListener() {
    147                 @Override public boolean onScale(ScaleGestureDetector detector) {
    148                     mListener.onScale(detector.getScaleFactor());
    149                     return true;
    150                 }
    151             });
    152         }
    153 
    154         @Override
    155         boolean shouldDrag() {
    156             return !mDetector.isInProgress();
    157         }
    158 
    159         @Override
    160         public boolean onTouchEvent(MotionEvent ev) {
    161             mDetector.onTouchEvent(ev);
    162             return super.onTouchEvent(ev);
    163         }
    164     }
    165 }
    166