RecentsViewTouchHandler.java revision 2364f26dc24191e5bfbab45bc1bdf9babe13af80
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.RecentsConfiguration;
23import com.android.systemui.recents.events.EventBus;
24import com.android.systemui.recents.events.ui.dragndrop.DragDockStateChangedEvent;
25import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
26import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
27import com.android.systemui.recents.misc.ReferenceCountedTrigger;
28import com.android.systemui.recents.model.Task;
29import com.android.systemui.recents.model.TaskStack;
30
31
32/**
33 * Represents the dock regions for each orientation.
34 */
35class DockRegion {
36    public static TaskStack.DockState[] PHONE_LANDSCAPE = {
37            TaskStack.DockState.LEFT
38    };
39    public static TaskStack.DockState[] PHONE_PORTRAIT = {
40            // We only allow docking to the top for now
41            TaskStack.DockState.TOP
42    };
43    public static TaskStack.DockState[] TABLET_LANDSCAPE = {
44            TaskStack.DockState.LEFT
45    };
46    public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT;
47}
48
49/**
50 * Handles touch events for a RecentsView.
51 */
52class RecentsViewTouchHandler {
53
54    private RecentsView mRv;
55
56    private Task mDragTask;
57    private TaskView mTaskView;
58    private DragView mDragView;
59
60    private Point mDownPos = new Point();
61    private boolean mDragging;
62    private TaskStack.DockState mLastDockState = TaskStack.DockState.NONE;
63
64    public RecentsViewTouchHandler(RecentsView rv) {
65        mRv = rv;
66    }
67
68    /**
69     * Returns the preferred dock states for the current orientation.
70     */
71    public TaskStack.DockState[] getDockStatesForCurrentOrientation() {
72        boolean isLandscape = mRv.getResources().getConfiguration().orientation ==
73                Configuration.ORIENTATION_LANDSCAPE;
74        RecentsConfiguration config = RecentsConfiguration.getInstance();
75        TaskStack.DockState[] dockStates = isLandscape ?
76                (config.isLargeScreen ? DockRegion.TABLET_LANDSCAPE : DockRegion.PHONE_LANDSCAPE) :
77                (config.isLargeScreen ? DockRegion.TABLET_PORTRAIT : DockRegion.PHONE_PORTRAIT);
78        return dockStates;
79    }
80
81    /** Touch preprocessing for handling below */
82    public boolean onInterceptTouchEvent(MotionEvent ev) {
83        handleTouchEvent(ev);
84        return mDragging;
85    }
86
87    /** Handles touch events once we have intercepted them */
88    public boolean onTouchEvent(MotionEvent ev) {
89        handleTouchEvent(ev);
90        return mDragging;
91    }
92
93    /**** Events ****/
94
95    public final void onBusEvent(DragStartEvent event) {
96        mRv.getParent().requestDisallowInterceptTouchEvent(true);
97        mDragging = true;
98        mDragTask = event.task;
99        mTaskView = event.taskView;
100        mDragView = event.dragView;
101
102        float x = mDownPos.x - mDragView.getTopLeftOffset().x;
103        float y = mDownPos.y - mDragView.getTopLeftOffset().y;
104        mDragView.setTranslationX(x);
105        mDragView.setTranslationY(y);
106    }
107
108    public final void onBusEvent(DragEndEvent event) {
109        mDragging = false;
110        mDragTask = null;
111        mTaskView = null;
112        mDragView = null;
113        mLastDockState = TaskStack.DockState.NONE;
114    }
115
116    /**
117     * Handles dragging touch events
118     * @param ev
119     */
120    private void handleTouchEvent(MotionEvent ev) {
121        boolean isLandscape = mRv.getResources().getConfiguration().orientation ==
122                Configuration.ORIENTATION_LANDSCAPE;
123        int action = ev.getAction();
124        switch (action & MotionEvent.ACTION_MASK) {
125            case MotionEvent.ACTION_DOWN:
126                mDownPos.set((int) ev.getX(), (int) ev.getY());
127                break;
128            case MotionEvent.ACTION_MOVE: {
129                if (mDragging) {
130                    int width = mRv.getMeasuredWidth();
131                    int height = mRv.getMeasuredHeight();
132                    float evX = ev.getX();
133                    float evY = ev.getY();
134                    float x = evX - mDragView.getTopLeftOffset().x;
135                    float y = evY - mDragView.getTopLeftOffset().y;
136
137                    // Update the dock state
138                    TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
139                    TaskStack.DockState foundDockState = TaskStack.DockState.NONE;
140                    for (int i = dockStates.length - 1; i >= 0; i--) {
141                        TaskStack.DockState state = dockStates[i];
142                        if (state.touchAreaContainsPoint(width, height, evX, evY)) {
143                            foundDockState = state;
144                            break;
145                        }
146                    }
147                    if (mLastDockState != foundDockState) {
148                        mLastDockState = foundDockState;
149                        EventBus.getDefault().send(new DragDockStateChangedEvent(mDragTask,
150                                foundDockState));
151                    }
152
153                    mDragView.setTranslationX(x);
154                    mDragView.setTranslationY(y);
155                }
156                break;
157            }
158            case MotionEvent.ACTION_UP:
159            case MotionEvent.ACTION_CANCEL: {
160                if (mDragging) {
161                    ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(
162                            mRv.getContext(), null, null, null);
163                    postAnimationTrigger.increment();
164                    EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView, mDragView,
165                            mLastDockState, postAnimationTrigger));
166                    postAnimationTrigger.decrement();
167                    break;
168                }
169            }
170        }
171    }
172}
173