1037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner/* 2037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * Copyright (C) 2013 The Android Open Source Project 3037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * 4037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * Licensed under the Apache License, Version 2.0 (the "License"); 5037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * you may not use this file except in compliance with the License. 6037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * You may obtain a copy of the License at 7037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * 8037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * http://www.apache.org/licenses/LICENSE-2.0 9037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * 10037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * Unless required by applicable law or agreed to in writing, software 11037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * distributed under the License is distributed on an "AS IS" BASIS, 12037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * See the License for the specific language governing permissions and 14037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner * limitations under the License. 15037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner */ 16037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner 17037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerpackage com.android.server.wm; 18037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner 1941aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukaiimport android.graphics.Rect; 20037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerimport android.graphics.Region; 21037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerimport android.view.DisplayInfo; 22b15758ab7a6481717d0d29612e870d7241061c31Chong Zhangimport android.view.GestureDetector; 23caca1114b2cf78551b2008156986a644d15317efJun Mukaiimport android.view.InputDevice; 24037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerimport android.view.MotionEvent; 25037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerimport android.view.WindowManagerPolicy.PointerEventListener; 26037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner 27037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerimport com.android.server.wm.WindowManagerService.H; 28037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner 29f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wrightimport static android.view.PointerIcon.TYPE_NOT_SPECIFIED; 30f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wrightimport static android.view.PointerIcon.TYPE_DEFAULT; 31f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wrightimport static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW; 32f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wrightimport static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW; 33f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wrightimport static android.view.PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW; 34f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wrightimport static android.view.PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW; 3541aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai 36e4a0c5722b1d8db95dfc842d716452dbbf02c86dWale Ogunwalepublic class TaskTapPointerEventListener implements PointerEventListener { 37037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner 3833d8e739206b7a5ed99cf9bf73d63f9b6c0d2a4etingna_sung final private Region mTouchExcludeRegion = new Region(); 39037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner private final WindowManagerService mService; 40037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner private final DisplayContent mDisplayContent; 4141aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai private final Rect mTmpRect = new Rect(); 42b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang private final Region mNonResizeableRegion = new Region(); 43b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang private boolean mTwoFingerScrolling; 44b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang private boolean mInGestureDetection; 45b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang private GestureDetector mGestureDetector; 46f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright private int mPointerIconType = TYPE_NOT_SPECIFIED; 47037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner 48e4a0c5722b1d8db95dfc842d716452dbbf02c86dWale Ogunwale public TaskTapPointerEventListener(WindowManagerService service, 49037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner DisplayContent displayContent) { 50037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner mService = service; 51037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner mDisplayContent = displayContent; 52037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner } 53037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner 54b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang // initialize the object, note this must be done outside WindowManagerService 55b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang // ctor, otherwise it may cause recursion as some code in GestureDetector ctor 56b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang // depends on WMS being already created. 57b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang void init() { 58b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang mGestureDetector = new GestureDetector( 59b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang mService.mContext, new TwoFingerScrollListener(), mService.mH); 60b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 61b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang 62037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner @Override 63037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner public void onPointerEvent(MotionEvent motionEvent) { 64b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang doGestureDetection(motionEvent); 65b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang 66037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner final int action = motionEvent.getAction(); 67037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner switch (action & MotionEvent.ACTION_MASK) { 688e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang case MotionEvent.ACTION_DOWN: { 699817dd098dcb4e37e1bec8b1e44ddb25a89cf8ecChong Zhang final int x = (int) motionEvent.getX(); 709817dd098dcb4e37e1bec8b1e44ddb25a89cf8ecChong Zhang final int y = (int) motionEvent.getY(); 718e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang 728e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang synchronized (this) { 738e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang if (!mTouchExcludeRegion.contains(x, y)) { 749817dd098dcb4e37e1bec8b1e44ddb25a89cf8ecChong Zhang mService.mH.obtainMessage(H.TAP_OUTSIDE_TASK, 759817dd098dcb4e37e1bec8b1e44ddb25a89cf8ecChong Zhang x, y, mDisplayContent).sendToTarget(); 768e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang } 778e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang } 78037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner break; 798e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang } 808e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang 818e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang case MotionEvent.ACTION_MOVE: { 82b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang if (motionEvent.getPointerCount() != 2) { 83b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang stopTwoFingerScroll(); 84b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 85037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner break; 868e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang } 878e89b31a62fb9ec5ad33908c5e8e9c7ab2fd949fChong Zhang 8841aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai case MotionEvent.ACTION_HOVER_MOVE: { 8941aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai final int x = (int) motionEvent.getX(); 9041aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai final int y = (int) motionEvent.getY(); 91d8ceb85512f8dc2dac6ef07fc72f89a75095e3d7Chong Zhang final Task task = mDisplayContent.findTaskForControlPoint(x, y); 92caca1114b2cf78551b2008156986a644d15317efJun Mukai InputDevice inputDevice = motionEvent.getDevice(); 93caca1114b2cf78551b2008156986a644d15317efJun Mukai if (task == null || inputDevice == null) { 94f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright mPointerIconType = TYPE_NOT_SPECIFIED; 9541aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai break; 9641aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai } 97d8ceb85512f8dc2dac6ef07fc72f89a75095e3d7Chong Zhang task.getDimBounds(mTmpRect); 9841aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai if (!mTmpRect.isEmpty() && !mTmpRect.contains(x, y)) { 99f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright int iconType = TYPE_DEFAULT; 10041aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai if (x < mTmpRect.left) { 101f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright iconType = 102f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright (y < mTmpRect.top) ? TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW : 103f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright (y > mTmpRect.bottom) ? TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW : 104f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright TYPE_HORIZONTAL_DOUBLE_ARROW; 10541aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai } else if (x > mTmpRect.right) { 106f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright iconType = 107f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright (y < mTmpRect.top) ? TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW : 108f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright (y > mTmpRect.bottom) ? TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW : 109f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright TYPE_HORIZONTAL_DOUBLE_ARROW; 11041aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai } else if (y < mTmpRect.top || y > mTmpRect.bottom) { 111f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright iconType = TYPE_VERTICAL_DOUBLE_ARROW; 11241aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai } 113f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright if (mPointerIconType != iconType) { 114f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright mPointerIconType = iconType; 115f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright inputDevice.setPointerType(iconType); 11641aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai } 11741aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai } else { 118f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright mPointerIconType = TYPE_NOT_SPECIFIED; 11941aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai } 12041aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai } break; 12141aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai 12241aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai case MotionEvent.ACTION_HOVER_EXIT: 123f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright mPointerIconType = TYPE_NOT_SPECIFIED; 124caca1114b2cf78551b2008156986a644d15317efJun Mukai InputDevice inputDevice = motionEvent.getDevice(); 125caca1114b2cf78551b2008156986a644d15317efJun Mukai if (inputDevice != null) { 126f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright inputDevice.setPointerType(TYPE_DEFAULT); 127caca1114b2cf78551b2008156986a644d15317efJun Mukai } 12841aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai break; 12941aab00c3e762c6b648483ee7b45b162e4da7f7fJun Mukai 130037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner case MotionEvent.ACTION_UP: 131037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner case MotionEvent.ACTION_POINTER_UP: { 132b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang stopTwoFingerScroll(); 133037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner break; 134037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner } 135037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner } 136037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner } 13733d8e739206b7a5ed99cf9bf73d63f9b6c0d2a4etingna_sung 138b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang private void doGestureDetection(MotionEvent motionEvent) { 139b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang if (mGestureDetector == null || mNonResizeableRegion.isEmpty()) { 140b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang return; 141b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 142b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang final int action = motionEvent.getAction() & MotionEvent.ACTION_MASK; 143b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang final int x = (int) motionEvent.getX(); 144b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang final int y = (int) motionEvent.getY(); 145b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang final boolean isTouchInside = mNonResizeableRegion.contains(x, y); 146b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang if (mInGestureDetection || action == MotionEvent.ACTION_DOWN && isTouchInside) { 147b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang // If we receive the following actions, or the pointer goes out of the area 148b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang // we're interested in, stop detecting and cancel the current detection. 149b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang mInGestureDetection = isTouchInside 150b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang && action != MotionEvent.ACTION_UP 151b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang && action != MotionEvent.ACTION_POINTER_UP 152b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang && action != MotionEvent.ACTION_CANCEL; 153b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang if (mInGestureDetection) { 154b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang mGestureDetector.onTouchEvent(motionEvent); 155b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } else { 156b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang MotionEvent cancelEvent = motionEvent.copy(); 157b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang cancelEvent.cancel(); 158b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang mGestureDetector.onTouchEvent(cancelEvent); 159b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang stopTwoFingerScroll(); 160b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 161b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 162b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 163b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang 164b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang private void onTwoFingerScroll(MotionEvent e) { 165b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang final int x = (int)e.getX(0); 166b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang final int y = (int)e.getY(0); 167b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang if (!mTwoFingerScrolling) { 168b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang mTwoFingerScrolling = true; 169b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang mService.mH.obtainMessage( 170b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang H.TWO_FINGER_SCROLL_START, x, y, mDisplayContent).sendToTarget(); 171b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 172b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 173b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang 174b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang private void stopTwoFingerScroll() { 175b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang if (mTwoFingerScrolling) { 176b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang mTwoFingerScrolling = false; 177b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang mService.mH.obtainMessage(H.FINISH_TASK_POSITIONING).sendToTarget(); 178b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 179b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 180b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang 181b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang private final class TwoFingerScrollListener extends GestureDetector.SimpleOnGestureListener { 182b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang @Override 183b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang public boolean onScroll(MotionEvent e1, MotionEvent e2, 184b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang float distanceX, float distanceY) { 185b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang if (e2.getPointerCount() == 2) { 186b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang onTwoFingerScroll(e2); 187b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang return true; 188b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 189b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang stopTwoFingerScroll(); 190b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang return false; 191b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 192b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang } 193b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang 194b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang void setTouchExcludeRegion(Region newRegion, Region nonResizeableRegion) { 19533d8e739206b7a5ed99cf9bf73d63f9b6c0d2a4etingna_sung synchronized (this) { 19633d8e739206b7a5ed99cf9bf73d63f9b6c0d2a4etingna_sung mTouchExcludeRegion.set(newRegion); 197b15758ab7a6481717d0d29612e870d7241061c31Chong Zhang mNonResizeableRegion.set(nonResizeableRegion); 19833d8e739206b7a5ed99cf9bf73d63f9b6c0d2a4etingna_sung } 19933d8e739206b7a5ed99cf9bf73d63f9b6c0d2a4etingna_sung } 200037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner} 201