Home | History | Annotate | Download | only in camera
      1 /*
      2  * Copyright (C) 2013 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 
     17 package com.android.camera;
     18 
     19 import android.view.GestureDetector;
     20 import android.view.MotionEvent;
     21 import android.view.ScaleGestureDetector;
     22 import android.view.View;
     23 
     24 import com.android.camera.ui.PieRenderer;
     25 import com.android.camera.ui.RenderOverlay;
     26 import com.android.camera.ui.ZoomRenderer;
     27 
     28 /* PreviewGestures disambiguates touch events received on RenderOverlay
     29  * and dispatch them to the proper recipient (i.e. zoom renderer or pie renderer).
     30  * Touch events on CameraControls will be handled by framework.
     31  * */
     32 public class PreviewGestures
     33         implements ScaleGestureDetector.OnScaleGestureListener {
     34 
     35     private static final String TAG = "CAM_gestures";
     36 
     37     private static final int MODE_NONE = 0;
     38     private static final int MODE_ZOOM = 2;
     39 
     40     public static final int DIR_UP = 0;
     41     public static final int DIR_DOWN = 1;
     42     public static final int DIR_LEFT = 2;
     43     public static final int DIR_RIGHT = 3;
     44 
     45     private SingleTapListener mTapListener;
     46     private RenderOverlay mOverlay;
     47     private PieRenderer mPie;
     48     private ZoomRenderer mZoom;
     49     private MotionEvent mDown;
     50     private MotionEvent mCurrent;
     51     private ScaleGestureDetector mScale;
     52     private int mMode;
     53     private boolean mZoomEnabled;
     54     private boolean mEnabled;
     55     private boolean mZoomOnly;
     56     private GestureDetector mGestureDetector;
     57 
     58     private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
     59         @Override
     60         public void onLongPress (MotionEvent e) {
     61             // Open pie
     62             if (!mZoomOnly && mPie != null && !mPie.showsItems()) {
     63                 openPie();
     64             }
     65         }
     66 
     67         @Override
     68         public boolean onSingleTapUp (MotionEvent e) {
     69             // Tap to focus when pie is not open
     70             if (mPie == null || !mPie.showsItems()) {
     71                 mTapListener.onSingleTapUp(null, (int) e.getX(), (int) e.getY());
     72                 return true;
     73             }
     74             return false;
     75         }
     76 
     77         @Override
     78         public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
     79             if (e1 == null) {
     80                 // e1 can be null if for some cases.
     81                 return false;
     82             }
     83             if (mZoomOnly || mMode == MODE_ZOOM) return false;
     84             int deltaX = (int) (e1.getX() - e2.getX());
     85             int deltaY = (int) (e1.getY() - e2.getY());
     86             if (deltaY > 2 * deltaX && deltaY > -2 * deltaX) {
     87                 // Open pie on swipe up
     88                 if (mPie != null && !mPie.showsItems()) {
     89                     openPie();
     90                     return true;
     91                 }
     92             }
     93             return false;
     94         }
     95     };
     96 
     97     public interface SingleTapListener {
     98         public void onSingleTapUp(View v, int x, int y);
     99     }
    100 
    101     public PreviewGestures(CameraActivity ctx, SingleTapListener tapListener,
    102             ZoomRenderer zoom, PieRenderer pie) {
    103         mTapListener = tapListener;
    104         mPie = pie;
    105         mZoom = zoom;
    106         mMode = MODE_NONE;
    107         mScale = new ScaleGestureDetector(ctx, this);
    108         mEnabled = true;
    109         mGestureDetector = new GestureDetector(mGestureListener);
    110     }
    111 
    112     public void setRenderOverlay(RenderOverlay overlay) {
    113         mOverlay = overlay;
    114     }
    115 
    116     public void setEnabled(boolean enabled) {
    117         mEnabled = enabled;
    118     }
    119 
    120     public void setZoomEnabled(boolean enable) {
    121         mZoomEnabled = enable;
    122     }
    123 
    124     public void setZoomOnly(boolean zoom) {
    125         mZoomOnly = zoom;
    126     }
    127 
    128     public boolean isEnabled() {
    129         return mEnabled;
    130     }
    131 
    132     public boolean dispatchTouch(MotionEvent m) {
    133         if (!mEnabled) {
    134             return false;
    135         }
    136         mCurrent = m;
    137         if (MotionEvent.ACTION_DOWN == m.getActionMasked()) {
    138             mMode = MODE_NONE;
    139             mDown = MotionEvent.obtain(m);
    140         }
    141 
    142         // If pie is open, redirects all the touch events to pie.
    143         if (mPie != null && mPie.isOpen()) {
    144             return sendToPie(m);
    145         }
    146 
    147         // If pie is not open, send touch events to gesture detector and scale
    148         // listener to recognize the gesture.
    149         mGestureDetector.onTouchEvent(m);
    150         if (mZoom != null) {
    151             mScale.onTouchEvent(m);
    152             if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
    153                 mMode = MODE_ZOOM;
    154                 if (mZoomEnabled) {
    155                     // Start showing zoom UI as soon as there is a second finger down
    156                     mZoom.onScaleBegin(mScale);
    157                 }
    158             } else if (MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
    159                 mZoom.onScaleEnd(mScale);
    160             }
    161         }
    162         return true;
    163     }
    164 
    165     private MotionEvent makeCancelEvent(MotionEvent m) {
    166         MotionEvent c = MotionEvent.obtain(m);
    167         c.setAction(MotionEvent.ACTION_CANCEL);
    168         return c;
    169     }
    170 
    171     private void openPie() {
    172         mGestureDetector.onTouchEvent(makeCancelEvent(mDown));
    173         mScale.onTouchEvent(makeCancelEvent(mDown));
    174         mOverlay.directDispatchTouch(mDown, mPie);
    175     }
    176 
    177     private boolean sendToPie(MotionEvent m) {
    178         return mOverlay.directDispatchTouch(m, mPie);
    179     }
    180 
    181     // OnScaleGestureListener implementation
    182     @Override
    183     public boolean onScale(ScaleGestureDetector detector) {
    184         return mZoom.onScale(detector);
    185     }
    186 
    187     @Override
    188     public boolean onScaleBegin(ScaleGestureDetector detector) {
    189         if (mPie == null || !mPie.isOpen()) {
    190             mMode = MODE_ZOOM;
    191             mGestureDetector.onTouchEvent(makeCancelEvent(mCurrent));
    192             if (!mZoomEnabled) return false;
    193             return mZoom.onScaleBegin(detector);
    194         }
    195         return false;
    196     }
    197 
    198     @Override
    199     public void onScaleEnd(ScaleGestureDetector detector) {
    200         mZoom.onScaleEnd(detector);
    201     }
    202 }
    203 
    204