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 17package com.android.server.wm; 18 19import android.graphics.Region; 20import android.view.DisplayInfo; 21import android.view.MotionEvent; 22import android.view.WindowManagerPolicy.PointerEventListener; 23 24import com.android.server.wm.WindowManagerService.H; 25 26public class StackTapPointerEventListener implements PointerEventListener { 27 private static final int TAP_TIMEOUT_MSEC = 300; 28 private static final float TAP_MOTION_SLOP_INCHES = 0.125f; 29 30 private final int mMotionSlop; 31 private float mDownX; 32 private float mDownY; 33 private int mPointerId; 34 final private Region mTouchExcludeRegion; 35 private final WindowManagerService mService; 36 private final DisplayContent mDisplayContent; 37 38 public StackTapPointerEventListener(WindowManagerService service, 39 DisplayContent displayContent) { 40 mService = service; 41 mDisplayContent = displayContent; 42 mTouchExcludeRegion = displayContent.mTouchExcludeRegion; 43 DisplayInfo info = displayContent.getDisplayInfo(); 44 mMotionSlop = (int)(info.logicalDensityDpi * TAP_MOTION_SLOP_INCHES); 45 } 46 47 @Override 48 public void onPointerEvent(MotionEvent motionEvent) { 49 final int action = motionEvent.getAction(); 50 switch (action & MotionEvent.ACTION_MASK) { 51 case MotionEvent.ACTION_DOWN: 52 mPointerId = motionEvent.getPointerId(0); 53 mDownX = motionEvent.getX(); 54 mDownY = motionEvent.getY(); 55 break; 56 case MotionEvent.ACTION_MOVE: 57 if (mPointerId >= 0) { 58 int index = motionEvent.findPointerIndex(mPointerId); 59 if ((motionEvent.getEventTime() - motionEvent.getDownTime()) > TAP_TIMEOUT_MSEC 60 || index < 0 61 || (motionEvent.getX(index) - mDownX) > mMotionSlop 62 || (motionEvent.getY(index) - mDownY) > mMotionSlop) { 63 mPointerId = -1; 64 } 65 } 66 break; 67 case MotionEvent.ACTION_UP: 68 case MotionEvent.ACTION_POINTER_UP: { 69 int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) 70 >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 71 // Extract the index of the pointer that left the touch sensor 72 if (mPointerId == motionEvent.getPointerId(index)) { 73 final int x = (int)motionEvent.getX(index); 74 final int y = (int)motionEvent.getY(index); 75 if ((motionEvent.getEventTime() - motionEvent.getDownTime()) 76 < TAP_TIMEOUT_MSEC 77 && (x - mDownX) < mMotionSlop && (y - mDownY) < mMotionSlop 78 && !mTouchExcludeRegion.contains(x, y)) { 79 mService.mH.obtainMessage(H.TAP_OUTSIDE_STACK, x, y, 80 mDisplayContent).sendToTarget(); 81 } 82 mPointerId = -1; 83 } 84 break; 85 } 86 } 87 } 88} 89