RecentsViewTouchHandler.java revision 479f7446cf489fb99c91b3fc2bf96b1dc184f5ba
1/* 2 * Copyright (C) 2014 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.systemui.recents.views; 18 19import android.content.res.Configuration; 20import android.graphics.Point; 21import android.view.MotionEvent; 22import com.android.systemui.recents.Recents; 23import com.android.systemui.recents.RecentsConfiguration; 24import com.android.systemui.recents.events.EventBus; 25import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent; 26import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; 27import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; 28import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent; 29import com.android.systemui.recents.misc.ReferenceCountedTrigger; 30import com.android.systemui.recents.model.Task; 31import com.android.systemui.recents.model.TaskStack; 32 33import java.util.ArrayList; 34 35 36/** 37 * Represents the dock regions for each orientation. 38 */ 39class DockRegion { 40 public static TaskStack.DockState[] PHONE_LANDSCAPE = { 41 // We only allow docking to the left for now on small devices 42 TaskStack.DockState.LEFT 43 }; 44 public static TaskStack.DockState[] PHONE_PORTRAIT = { 45 // We only allow docking to the top for now on small devices 46 TaskStack.DockState.TOP 47 }; 48 public static TaskStack.DockState[] TABLET_LANDSCAPE = { 49 TaskStack.DockState.LEFT, 50 TaskStack.DockState.RIGHT 51 }; 52 public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT; 53} 54 55/** 56 * Handles touch events for a RecentsView. 57 */ 58public class RecentsViewTouchHandler { 59 60 private static final String TAG = "RecentsViewTouchHandler"; 61 private static final boolean DEBUG = false; 62 63 private RecentsView mRv; 64 65 private Task mDragTask; 66 private TaskView mTaskView; 67 68 private Point mTaskViewOffset = new Point(); 69 private Point mDownPos = new Point(); 70 private boolean mDragging; 71 72 private DropTarget mLastDropTarget; 73 private ArrayList<DropTarget> mDropTargets = new ArrayList<>(); 74 75 public RecentsViewTouchHandler(RecentsView rv) { 76 mRv = rv; 77 } 78 79 /** 80 * Registers a new drop target for the current drag only. 81 */ 82 public void registerDropTargetForCurrentDrag(DropTarget target) { 83 mDropTargets.add(target); 84 } 85 86 /** 87 * Returns the preferred dock states for the current orientation. 88 */ 89 public TaskStack.DockState[] getDockStatesForCurrentOrientation() { 90 boolean isLandscape = mRv.getResources().getConfiguration().orientation == 91 Configuration.ORIENTATION_LANDSCAPE; 92 RecentsConfiguration config = Recents.getConfiguration(); 93 TaskStack.DockState[] dockStates = isLandscape ? 94 (config.isLargeScreen ? DockRegion.TABLET_LANDSCAPE : DockRegion.PHONE_LANDSCAPE) : 95 (config.isLargeScreen ? DockRegion.TABLET_PORTRAIT : DockRegion.PHONE_PORTRAIT); 96 return dockStates; 97 } 98 99 /** Touch preprocessing for handling below */ 100 public boolean onInterceptTouchEvent(MotionEvent ev) { 101 handleTouchEvent(ev); 102 return mDragging; 103 } 104 105 /** Handles touch events once we have intercepted them */ 106 public boolean onTouchEvent(MotionEvent ev) { 107 handleTouchEvent(ev); 108 return mDragging; 109 } 110 111 /**** Events ****/ 112 113 public final void onBusEvent(DragStartEvent event) { 114 mRv.getParent().requestDisallowInterceptTouchEvent(true); 115 mDragging = true; 116 mDragTask = event.task; 117 mTaskView = event.taskView; 118 mDropTargets.clear(); 119 120 int[] recentsViewLocation = new int[2]; 121 mRv.getLocationInWindow(recentsViewLocation); 122 mTaskViewOffset.set(mTaskView.getLeft() - recentsViewLocation[0] + event.tlOffset.x, 123 mTaskView.getTop() - recentsViewLocation[1] + event.tlOffset.y); 124 float x = mDownPos.x - mTaskViewOffset.x; 125 float y = mDownPos.y - mTaskViewOffset.y; 126 mTaskView.setTranslationX(x); 127 mTaskView.setTranslationY(y); 128 129 RecentsConfiguration config = Recents.getConfiguration(); 130 if (!config.hasDockedTasks) { 131 // Add the dock state drop targets (these take priority) 132 TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation(); 133 for (TaskStack.DockState dockState : dockStates) { 134 registerDropTargetForCurrentDrag(dockState); 135 } 136 } 137 138 // Request other drop targets to register themselves 139 EventBus.getDefault().send(new DragStartInitializeDropTargetsEvent(event.task, this)); 140 } 141 142 public final void onBusEvent(DragEndEvent event) { 143 mDragging = false; 144 mDragTask = null; 145 mTaskView = null; 146 mLastDropTarget = null; 147 } 148 149 /** 150 * Handles dragging touch events 151 * @param ev 152 */ 153 private void handleTouchEvent(MotionEvent ev) { 154 int action = ev.getAction(); 155 switch (action & MotionEvent.ACTION_MASK) { 156 case MotionEvent.ACTION_DOWN: 157 mDownPos.set((int) ev.getX(), (int) ev.getY()); 158 break; 159 case MotionEvent.ACTION_MOVE: { 160 if (mDragging) { 161 int width = mRv.getMeasuredWidth(); 162 int height = mRv.getMeasuredHeight(); 163 float evX = ev.getX(); 164 float evY = ev.getY(); 165 float x = evX - mTaskViewOffset.x; 166 float y = evY - mTaskViewOffset.y; 167 168 DropTarget currentDropTarget = null; 169 for (DropTarget target : mDropTargets) { 170 if (target.acceptsDrop((int) evX, (int) evY, width, height)) { 171 currentDropTarget = target; 172 break; 173 } 174 } 175 if (mLastDropTarget != currentDropTarget) { 176 mLastDropTarget = currentDropTarget; 177 EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask, 178 currentDropTarget)); 179 } 180 181 mTaskView.setTranslationX(x); 182 mTaskView.setTranslationY(y); 183 } 184 break; 185 } 186 case MotionEvent.ACTION_UP: 187 case MotionEvent.ACTION_CANCEL: { 188 if (mDragging) { 189 ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger( 190 mRv.getContext(), null, null, null); 191 postAnimationTrigger.increment(); 192 EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView, 193 mLastDropTarget, postAnimationTrigger)); 194 postAnimationTrigger.decrement(); 195 break; 196 } 197 } 198 } 199 } 200} 201