RecentsViewTouchHandler.java revision 3e8747414520ee348cf4b9c4a6afd9ff80b5a8f8
1be7607af8875236b9cf7bdb5f5aa089c207529afWinson/* 2be7607af8875236b9cf7bdb5f5aa089c207529afWinson * Copyright (C) 2014 The Android Open Source Project 3be7607af8875236b9cf7bdb5f5aa089c207529afWinson * 4be7607af8875236b9cf7bdb5f5aa089c207529afWinson * Licensed under the Apache License, Version 2.0 (the "License"); 5be7607af8875236b9cf7bdb5f5aa089c207529afWinson * you may not use this file except in compliance with the License. 6be7607af8875236b9cf7bdb5f5aa089c207529afWinson * You may obtain a copy of the License at 7be7607af8875236b9cf7bdb5f5aa089c207529afWinson * 8be7607af8875236b9cf7bdb5f5aa089c207529afWinson * http://www.apache.org/licenses/LICENSE-2.0 9be7607af8875236b9cf7bdb5f5aa089c207529afWinson * 10be7607af8875236b9cf7bdb5f5aa089c207529afWinson * Unless required by applicable law or agreed to in writing, software 11be7607af8875236b9cf7bdb5f5aa089c207529afWinson * distributed under the License is distributed on an "AS IS" BASIS, 12be7607af8875236b9cf7bdb5f5aa089c207529afWinson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13be7607af8875236b9cf7bdb5f5aa089c207529afWinson * See the License for the specific language governing permissions and 14be7607af8875236b9cf7bdb5f5aa089c207529afWinson * limitations under the License. 15be7607af8875236b9cf7bdb5f5aa089c207529afWinson */ 16be7607af8875236b9cf7bdb5f5aa089c207529afWinson 17be7607af8875236b9cf7bdb5f5aa089c207529afWinsonpackage com.android.systemui.recents.views; 18be7607af8875236b9cf7bdb5f5aa089c207529afWinson 19be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport android.content.res.Configuration; 20be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport android.graphics.Point; 21be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport android.view.MotionEvent; 223e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport android.view.ViewConfiguration; 2353ec42cb17693b2d631746e1e5d31021a3359163Winsonimport com.android.systemui.recents.Recents; 24882072baacaee4ecd43f0209b691a9af746462f2Winsonimport com.android.systemui.recents.RecentsConfiguration; 25be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport com.android.systemui.recents.events.EventBus; 26eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent; 27be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; 28be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; 29eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent; 30d759a7123a7cacf431399b310421c59a6c818e53Winsonimport com.android.systemui.recents.misc.SystemServicesProxy; 31be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport com.android.systemui.recents.model.Task; 32be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport com.android.systemui.recents.model.TaskStack; 33be7607af8875236b9cf7bdb5f5aa089c207529afWinson 34eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport java.util.ArrayList; 35eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson 36be7607af8875236b9cf7bdb5f5aa089c207529afWinson 37be7607af8875236b9cf7bdb5f5aa089c207529afWinson/** 38be7607af8875236b9cf7bdb5f5aa089c207529afWinson * Represents the dock regions for each orientation. 39be7607af8875236b9cf7bdb5f5aa089c207529afWinson */ 40be7607af8875236b9cf7bdb5f5aa089c207529afWinsonclass DockRegion { 41882072baacaee4ecd43f0209b691a9af746462f2Winson public static TaskStack.DockState[] PHONE_LANDSCAPE = { 42e92440ee5fad343c680d889136f9a9847a80a418Winson // We only allow docking to the left for now on small devices 432364f26dc24191e5bfbab45bc1bdf9babe13af80Winson TaskStack.DockState.LEFT 44be7607af8875236b9cf7bdb5f5aa089c207529afWinson }; 45882072baacaee4ecd43f0209b691a9af746462f2Winson public static TaskStack.DockState[] PHONE_PORTRAIT = { 46e92440ee5fad343c680d889136f9a9847a80a418Winson // We only allow docking to the top for now on small devices 474165d336b6cd69715eda7fbdfd272a878097170eWinson TaskStack.DockState.TOP 48be7607af8875236b9cf7bdb5f5aa089c207529afWinson }; 49882072baacaee4ecd43f0209b691a9af746462f2Winson public static TaskStack.DockState[] TABLET_LANDSCAPE = { 50e92440ee5fad343c680d889136f9a9847a80a418Winson TaskStack.DockState.LEFT, 51e92440ee5fad343c680d889136f9a9847a80a418Winson TaskStack.DockState.RIGHT 52882072baacaee4ecd43f0209b691a9af746462f2Winson }; 53882072baacaee4ecd43f0209b691a9af746462f2Winson public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT; 54be7607af8875236b9cf7bdb5f5aa089c207529afWinson} 55be7607af8875236b9cf7bdb5f5aa089c207529afWinson 56be7607af8875236b9cf7bdb5f5aa089c207529afWinson/** 57be7607af8875236b9cf7bdb5f5aa089c207529afWinson * Handles touch events for a RecentsView. 58be7607af8875236b9cf7bdb5f5aa089c207529afWinson */ 59eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonpublic class RecentsViewTouchHandler { 60eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson 61be7607af8875236b9cf7bdb5f5aa089c207529afWinson private RecentsView mRv; 62be7607af8875236b9cf7bdb5f5aa089c207529afWinson 63be7607af8875236b9cf7bdb5f5aa089c207529afWinson private Task mDragTask; 64be7607af8875236b9cf7bdb5f5aa089c207529afWinson private TaskView mTaskView; 65be7607af8875236b9cf7bdb5f5aa089c207529afWinson 66479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson private Point mTaskViewOffset = new Point(); 67be7607af8875236b9cf7bdb5f5aa089c207529afWinson private Point mDownPos = new Point(); 683e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson private boolean mDragRequested; 693e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson private boolean mIsDragging; 703e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson private float mDragSlop; 71eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson 72eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson private DropTarget mLastDropTarget; 73eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson private ArrayList<DropTarget> mDropTargets = new ArrayList<>(); 74be7607af8875236b9cf7bdb5f5aa089c207529afWinson 75be7607af8875236b9cf7bdb5f5aa089c207529afWinson public RecentsViewTouchHandler(RecentsView rv) { 76be7607af8875236b9cf7bdb5f5aa089c207529afWinson mRv = rv; 773e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson mDragSlop = ViewConfiguration.get(rv.getContext()).getScaledTouchSlop(); 78be7607af8875236b9cf7bdb5f5aa089c207529afWinson } 79be7607af8875236b9cf7bdb5f5aa089c207529afWinson 80882072baacaee4ecd43f0209b691a9af746462f2Winson /** 81eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson * Registers a new drop target for the current drag only. 82eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson */ 83eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson public void registerDropTargetForCurrentDrag(DropTarget target) { 84eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson mDropTargets.add(target); 85eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson } 86eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson 87eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson /** 88882072baacaee4ecd43f0209b691a9af746462f2Winson * Returns the preferred dock states for the current orientation. 89882072baacaee4ecd43f0209b691a9af746462f2Winson */ 90882072baacaee4ecd43f0209b691a9af746462f2Winson public TaskStack.DockState[] getDockStatesForCurrentOrientation() { 914165d336b6cd69715eda7fbdfd272a878097170eWinson boolean isLandscape = mRv.getResources().getConfiguration().orientation == 924165d336b6cd69715eda7fbdfd272a878097170eWinson Configuration.ORIENTATION_LANDSCAPE; 9353ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsConfiguration config = Recents.getConfiguration(); 944165d336b6cd69715eda7fbdfd272a878097170eWinson TaskStack.DockState[] dockStates = isLandscape ? 95882072baacaee4ecd43f0209b691a9af746462f2Winson (config.isLargeScreen ? DockRegion.TABLET_LANDSCAPE : DockRegion.PHONE_LANDSCAPE) : 96882072baacaee4ecd43f0209b691a9af746462f2Winson (config.isLargeScreen ? DockRegion.TABLET_PORTRAIT : DockRegion.PHONE_PORTRAIT); 97882072baacaee4ecd43f0209b691a9af746462f2Winson return dockStates; 984165d336b6cd69715eda7fbdfd272a878097170eWinson } 994165d336b6cd69715eda7fbdfd272a878097170eWinson 100be7607af8875236b9cf7bdb5f5aa089c207529afWinson /** Touch preprocessing for handling below */ 101be7607af8875236b9cf7bdb5f5aa089c207529afWinson public boolean onInterceptTouchEvent(MotionEvent ev) { 1024165d336b6cd69715eda7fbdfd272a878097170eWinson handleTouchEvent(ev); 1033e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson return mDragRequested; 104be7607af8875236b9cf7bdb5f5aa089c207529afWinson } 105be7607af8875236b9cf7bdb5f5aa089c207529afWinson 106be7607af8875236b9cf7bdb5f5aa089c207529afWinson /** Handles touch events once we have intercepted them */ 107be7607af8875236b9cf7bdb5f5aa089c207529afWinson public boolean onTouchEvent(MotionEvent ev) { 1084165d336b6cd69715eda7fbdfd272a878097170eWinson handleTouchEvent(ev); 1093e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson return mDragRequested; 1104165d336b6cd69715eda7fbdfd272a878097170eWinson } 1114165d336b6cd69715eda7fbdfd272a878097170eWinson 1124165d336b6cd69715eda7fbdfd272a878097170eWinson /**** Events ****/ 1134165d336b6cd69715eda7fbdfd272a878097170eWinson 1144165d336b6cd69715eda7fbdfd272a878097170eWinson public final void onBusEvent(DragStartEvent event) { 115d759a7123a7cacf431399b310421c59a6c818e53Winson SystemServicesProxy ssp = Recents.getSystemServices(); 1164165d336b6cd69715eda7fbdfd272a878097170eWinson mRv.getParent().requestDisallowInterceptTouchEvent(true); 1173e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson mDragRequested = true; 1183e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson // We defer starting the actual drag handling until the user moves past the drag slop 1193e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson mIsDragging = false; 1204165d336b6cd69715eda7fbdfd272a878097170eWinson mDragTask = event.task; 1214165d336b6cd69715eda7fbdfd272a878097170eWinson mTaskView = event.taskView; 122eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson mDropTargets.clear(); 1234165d336b6cd69715eda7fbdfd272a878097170eWinson 124479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson int[] recentsViewLocation = new int[2]; 125479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson mRv.getLocationInWindow(recentsViewLocation); 126479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson mTaskViewOffset.set(mTaskView.getLeft() - recentsViewLocation[0] + event.tlOffset.x, 127479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson mTaskView.getTop() - recentsViewLocation[1] + event.tlOffset.y); 128479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson float x = mDownPos.x - mTaskViewOffset.x; 129479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson float y = mDownPos.y - mTaskViewOffset.y; 130479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson mTaskView.setTranslationX(x); 131479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson mTaskView.setTranslationY(y); 132eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson 133d759a7123a7cacf431399b310421c59a6c818e53Winson if (!ssp.hasDockedTask()) { 134eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson // Add the dock state drop targets (these take priority) 135eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation(); 136eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson for (TaskStack.DockState dockState : dockStates) { 137eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson registerDropTargetForCurrentDrag(dockState); 138eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson } 139eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson } 140eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson 141eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson // Request other drop targets to register themselves 142eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson EventBus.getDefault().send(new DragStartInitializeDropTargetsEvent(event.task, this)); 1434165d336b6cd69715eda7fbdfd272a878097170eWinson } 1444165d336b6cd69715eda7fbdfd272a878097170eWinson 1454165d336b6cd69715eda7fbdfd272a878097170eWinson public final void onBusEvent(DragEndEvent event) { 1463e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson mDragRequested = false; 1474165d336b6cd69715eda7fbdfd272a878097170eWinson mDragTask = null; 1484165d336b6cd69715eda7fbdfd272a878097170eWinson mTaskView = null; 149eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson mLastDropTarget = null; 1504165d336b6cd69715eda7fbdfd272a878097170eWinson } 151be7607af8875236b9cf7bdb5f5aa089c207529afWinson 1524165d336b6cd69715eda7fbdfd272a878097170eWinson /** 1534165d336b6cd69715eda7fbdfd272a878097170eWinson * Handles dragging touch events 1544165d336b6cd69715eda7fbdfd272a878097170eWinson */ 1554165d336b6cd69715eda7fbdfd272a878097170eWinson private void handleTouchEvent(MotionEvent ev) { 156be7607af8875236b9cf7bdb5f5aa089c207529afWinson int action = ev.getAction(); 157be7607af8875236b9cf7bdb5f5aa089c207529afWinson switch (action & MotionEvent.ACTION_MASK) { 158be7607af8875236b9cf7bdb5f5aa089c207529afWinson case MotionEvent.ACTION_DOWN: 159be7607af8875236b9cf7bdb5f5aa089c207529afWinson mDownPos.set((int) ev.getX(), (int) ev.getY()); 160be7607af8875236b9cf7bdb5f5aa089c207529afWinson break; 161be7607af8875236b9cf7bdb5f5aa089c207529afWinson case MotionEvent.ACTION_MOVE: { 1623e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson float evX = ev.getX(); 1633e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson float evY = ev.getY(); 1643e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson float x = evX - mTaskViewOffset.x; 1653e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson float y = evY - mTaskViewOffset.y; 1663e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson 1673e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson if (mDragRequested) { 1683e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson if (!mIsDragging) { 1693e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson mIsDragging = Math.hypot(evX - mDownPos.x, evY - mDownPos.y) > mDragSlop; 1704165d336b6cd69715eda7fbdfd272a878097170eWinson } 1713e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson if (mIsDragging) { 1723e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson int width = mRv.getMeasuredWidth(); 1733e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson int height = mRv.getMeasuredHeight(); 1743e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson 1753e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson DropTarget currentDropTarget = null; 1763e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson 1773e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson // Give priority to the current drop target to retain the touch handling 1783e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson if (mLastDropTarget != null) { 1793e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson if (mLastDropTarget.acceptsDrop((int) evX, (int) evY, width, height, 1803e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson true /* isCurrentTarget */)) { 1813e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson currentDropTarget = mLastDropTarget; 1823e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson } 1833e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson } 1843e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson 1853e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson // Otherwise, find the next target to handle this event 1863e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson if (currentDropTarget == null) { 1873e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson for (DropTarget target : mDropTargets) { 1883e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson if (target.acceptsDrop((int) evX, (int) evY, width, height, 1893e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson false /* isCurrentTarget */)) { 1903e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson currentDropTarget = target; 1913e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson break; 1923e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson } 1933e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson } 1943e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson } 1953e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson if (mLastDropTarget != currentDropTarget) { 1963e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson mLastDropTarget = currentDropTarget; 1973e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask, 1983e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson currentDropTarget)); 1993e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson } 2003e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson 201be7607af8875236b9cf7bdb5f5aa089c207529afWinson } 202be7607af8875236b9cf7bdb5f5aa089c207529afWinson 203479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson mTaskView.setTranslationX(x); 204479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson mTaskView.setTranslationY(y); 2054165d336b6cd69715eda7fbdfd272a878097170eWinson } 206be7607af8875236b9cf7bdb5f5aa089c207529afWinson break; 207be7607af8875236b9cf7bdb5f5aa089c207529afWinson } 208be7607af8875236b9cf7bdb5f5aa089c207529afWinson case MotionEvent.ACTION_UP: 209be7607af8875236b9cf7bdb5f5aa089c207529afWinson case MotionEvent.ACTION_CANCEL: { 2103e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson if (mDragRequested) { 211479f7446cf489fb99c91b3fc2bf96b1dc184f5baWinson EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView, 212aaeaac17831090594e4927b1531c4658d239a3eaWinson Chung mLastDropTarget)); 21309d8a184c6d9d996663da1756ab4ac7d54c04b45Winson break; 21409d8a184c6d9d996663da1756ab4ac7d54c04b45Winson } 215be7607af8875236b9cf7bdb5f5aa089c207529afWinson } 216be7607af8875236b9cf7bdb5f5aa089c207529afWinson } 217be7607af8875236b9cf7bdb5f5aa089c207529afWinson } 218be7607af8875236b9cf7bdb5f5aa089c207529afWinson} 219