16a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang/* 26a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * Copyright (C) 2010 The Android Open Source Project 36a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * 46a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * Licensed under the Apache License, Version 2.0 (the "License"); 56a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * you may not use this file except in compliance with the License. 66a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * You may obtain a copy of the License at 76a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * 86a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * http://www.apache.org/licenses/LICENSE-2.0 96a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * 106a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * Unless required by applicable law or agreed to in writing, software 116a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * distributed under the License is distributed on an "AS IS" BASIS, 126a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * See the License for the specific language governing permissions and 146a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * limitations under the License. 156a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang */ 166a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 176a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huangpackage com.android.gallery3d.photoeditor.actions; 186a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 196a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huangimport android.content.Context; 206a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huangimport android.graphics.PointF; 216a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huangimport android.util.AttributeSet; 226a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huangimport android.view.GestureDetector; 236a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huangimport android.view.MotionEvent; 246a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 256a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang/** 266a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * A view that detects user gestures and touch motions. 276a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang */ 286a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huangclass TouchView extends FullscreenToolView { 296a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 306a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang /** 316a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * Listener of swipes. 326a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang */ 336a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang public interface SwipeListener { 346a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 356a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang void onSwipeLeft(); 366a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 376a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang void onSwipeRight(); 386a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 396a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang void onSwipeUp(); 406a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 416a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang void onSwipeDown(); 426a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 436a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 446a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang /** 456a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang * Listener of single tap on a point (relative to photo coordinates). 466a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang */ 476a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang public interface SingleTapListener { 486a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 496a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang void onSingleTap(PointF point); 506a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 516a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 526a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang private final GestureDetector gestureDetector; 536a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 546a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang private SwipeListener swipeListener; 556a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang private SingleTapListener singleTapListener; 566a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 576a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang public TouchView(Context context, AttributeSet attrs) { 586a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang super(context, attrs); 596a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 606a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang final int swipeThreshold = (int) (500 * getResources().getDisplayMetrics().density); 616a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang gestureDetector = new GestureDetector( 626a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang context, new GestureDetector.SimpleOnGestureListener() { 636a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 646a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang @Override 656a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang public boolean onDown(MotionEvent e) { 666a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang // GestureDetector onTouchEvent returns true for fling events only when their 676a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang // preceding down events are consumed. 686a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang return true; 696a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 706a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 716a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang @Override 726a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang public boolean onSingleTapUp(MotionEvent e) { 736a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang if (singleTapListener != null) { 746a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang PointF point = new PointF(); 756a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang mapPhotoPoint(e.getX(), e.getY(), point); 766a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang singleTapListener.onSingleTap(point); 776a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 786a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang return true; 796a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 806a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 816a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang @Override 826a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang public boolean onFling( 836a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) { 846a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang if (swipeListener != null) { 856a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang float absX = Math.abs(velocityX); 866a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang float absY = Math.abs(velocityY); 876a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang float deltaX = me2.getX() - me1.getX(); 886a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang float deltaY = me2.getY() - me1.getY(); 896a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang int travelX = getWidth() / 4; 906a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang int travelY = getHeight() / 4; 916a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang if (velocityX > swipeThreshold && absY < absX && deltaX > travelX) { 926a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang swipeListener.onSwipeRight(); 936a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } else if (velocityX < -swipeThreshold && absY < absX && deltaX < -travelX) { 946a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang swipeListener.onSwipeLeft(); 956a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } else if (velocityY < -swipeThreshold && absX < absY && deltaY < -travelY) { 966a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang swipeListener.onSwipeUp(); 976a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } else if (velocityY > swipeThreshold && absX < absY / 2 && deltaY > travelY) { 986a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang swipeListener.onSwipeDown(); 996a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 1006a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 1016a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang return true; 1026a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 1036a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang }); 1046a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang gestureDetector.setIsLongpressEnabled(false); 1056a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 1066a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 1076a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang public void setSwipeListener(SwipeListener listener) { 1086a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang swipeListener = listener; 1096a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 1106a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 1116a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang public void setSingleTapListener(SingleTapListener listener) { 1126a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang singleTapListener = listener; 1136a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 1146a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang 1156a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang @Override 1166a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang public boolean onTouchEvent(MotionEvent event) { 1176a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang return isEnabled() && gestureDetector.onTouchEvent(event); 1186a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang } 1196a12ad70df5da5052a8381e2cdda79e6a314cee9Yuli Huang} 120