1dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi/* 2dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * Copyright (C) 2014 The Android Open Source Project 3dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * 4dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License"); 5dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * you may not use this file except in compliance with the License. 6dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * You may obtain a copy of the License at 7dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * 8dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * http://www.apache.org/licenses/LICENSE-2.0 9dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * 10dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * Unless required by applicable law or agreed to in writing, software 11dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS, 12dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * See the License for the specific language governing permissions and 14dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * limitations under the License. 15dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi */ 16dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 17dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggipackage com.android.systemui.statusbar.phone; 18dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 19213cbe665b1c45112f46c006f8b7db19b0c7663cJorim Jaggiimport android.app.ActivityManager; 20dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport android.content.Context; 21dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport android.content.res.Resources; 229ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggiimport android.graphics.Rect; 23dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport android.view.GestureDetector; 24dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport android.view.MotionEvent; 25dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport android.view.VelocityTracker; 26298c08115110a5615a1972884fa7ee24dd9c59d6Jorim Jaggiimport android.view.View; 27dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport android.view.ViewConfiguration; 28dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 2992de6b63819d7af4a93f1e1da33e89d453a0ad65Jorim Jaggiimport com.android.internal.logging.MetricsLogger; 30f6e9228b8a97603d3ceb8f0d61e8d87cf19bd21fChris Wrenimport com.android.internal.logging.MetricsProto.MetricsEvent; 31c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; 32dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.R; 33dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.RecentsComponent; 34dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggiimport com.android.systemui.stackdivider.Divider; 35e759cd58bda6652e5413e7ca2a39b77bb776a610Winsonimport com.android.systemui.tuner.TunerService; 36dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 37c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport static android.view.WindowManager.DOCKED_INVALID; 38c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport static android.view.WindowManager.DOCKED_LEFT; 39c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport static android.view.WindowManager.DOCKED_TOP; 40dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 41dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi/** 42dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * Class to detect gestures on the navigation bar. 43dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi */ 44e759cd58bda6652e5413e7ca2a39b77bb776a610Winsonpublic class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureListener 45e759cd58bda6652e5413e7ca2a39b77bb776a610Winson implements TunerService.Tunable { 46dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 47e759cd58bda6652e5413e7ca2a39b77bb776a610Winson private static final String KEY_DOCK_WINDOW_GESTURE = "overview_nav_bar_gesture"; 48cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi /** 49cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi * When dragging from the navigation bar, we drag in recents. 50cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi */ 51cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi public static final int DRAG_MODE_NONE = -1; 52dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 53dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi /** 54dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * When dragging from the navigation bar, we drag in recents. 55dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi */ 56cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi public static final int DRAG_MODE_RECENTS = 0; 57dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 58dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi /** 59dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi * When dragging from the navigation bar, we drag the divider. 60dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi */ 61cdb06caebb5f6f554b2ed8c76963970d8cc0ab54Jorim Jaggi public static final int DRAG_MODE_DIVIDER = 1; 62dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 63dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private RecentsComponent mRecentsComponent; 64dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private Divider mDivider; 65213cbe665b1c45112f46c006f8b7db19b0c7663cJorim Jaggi private Context mContext; 66298c08115110a5615a1972884fa7ee24dd9c59d6Jorim Jaggi private NavigationBarView mNavigationBarView; 67dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private boolean mIsVertical; 68dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private boolean mIsRTL; 69dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 70dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private final GestureDetector mTaskSwitcherDetector; 71dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private final int mScrollTouchSlop; 72dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private final int mMinFlingVelocity; 73dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private int mTouchDownX; 74dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private int mTouchDownY; 75298c08115110a5615a1972884fa7ee24dd9c59d6Jorim Jaggi private boolean mDownOnRecents; 76dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private VelocityTracker mVelocityTracker; 77dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 78dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private boolean mDockWindowEnabled; 79dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private boolean mDockWindowTouchSlopExceeded; 80dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private int mDragMode; 81dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 82dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public NavigationBarGestureHelper(Context context) { 83213cbe665b1c45112f46c006f8b7db19b0c7663cJorim Jaggi mContext = context; 84dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi ViewConfiguration configuration = ViewConfiguration.get(context); 85dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi Resources r = context.getResources(); 86dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance); 87dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity(); 88dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mTaskSwitcherDetector = new GestureDetector(context, this); 89e759cd58bda6652e5413e7ca2a39b77bb776a610Winson TunerService.get(context).addTunable(this, KEY_DOCK_WINDOW_GESTURE); 90dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 91dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 92298c08115110a5615a1972884fa7ee24dd9c59d6Jorim Jaggi public void setComponents(RecentsComponent recentsComponent, Divider divider, 93298c08115110a5615a1972884fa7ee24dd9c59d6Jorim Jaggi NavigationBarView navigationBarView) { 94dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mRecentsComponent = recentsComponent; 95dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mDivider = divider; 96298c08115110a5615a1972884fa7ee24dd9c59d6Jorim Jaggi mNavigationBarView = navigationBarView; 97dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 98dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 99dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public void setBarState(boolean isVertical, boolean isRTL) { 100dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mIsVertical = isVertical; 101dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mIsRTL = isRTL; 102dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 103dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 104dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public boolean onInterceptTouchEvent(MotionEvent event) { 105dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi // If we move more than a fixed amount, then start capturing for the 106dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi // task switcher detector 107dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mTaskSwitcherDetector.onTouchEvent(event); 108dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi int action = event.getAction(); 109dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi switch (action & MotionEvent.ACTION_MASK) { 110dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_DOWN: { 111dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mTouchDownX = (int) event.getX(); 112dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mTouchDownY = (int) event.getY(); 113dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi break; 114dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 115dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_MOVE: { 116dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi int x = (int) event.getX(); 117dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi int y = (int) event.getY(); 118dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi int xDiff = Math.abs(x - mTouchDownX); 119dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi int yDiff = Math.abs(y - mTouchDownY); 120dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi boolean exceededTouchSlop = !mIsVertical 121dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi ? xDiff > mScrollTouchSlop && xDiff > yDiff 122dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi : yDiff > mScrollTouchSlop && yDiff > xDiff; 123dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi if (exceededTouchSlop) { 124dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return true; 125dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 126dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi break; 127dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 128dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_CANCEL: 129dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_UP: 130dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi break; 131dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 132dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return mDockWindowEnabled && interceptDockWindowEvent(event); 133dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 134dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 135dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private boolean interceptDockWindowEvent(MotionEvent event) { 136dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi switch (event.getActionMasked()) { 137dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_DOWN: 138dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi handleDragActionDownEvent(event); 139dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi break; 140dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_MOVE: 141dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return handleDragActionMoveEvent(event); 142dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_UP: 143dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_CANCEL: 144dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi handleDragActionUpEvent(event); 145dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi break; 146dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 147dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return false; 148dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 149dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 150dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private boolean handleDockWindowEvent(MotionEvent event) { 151dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi switch (event.getActionMasked()) { 152dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_DOWN: 153dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi handleDragActionDownEvent(event); 154dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi break; 155dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_MOVE: 156dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi handleDragActionMoveEvent(event); 157dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi break; 158dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_UP: 159dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi case MotionEvent.ACTION_CANCEL: 160dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi handleDragActionUpEvent(event); 161dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi break; 162dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 163dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return true; 164dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 165dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 166dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private void handleDragActionDownEvent(MotionEvent event) { 167dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mVelocityTracker = VelocityTracker.obtain(); 168dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mVelocityTracker.addMovement(event); 169dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mDockWindowTouchSlopExceeded = false; 170dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mTouchDownX = (int) event.getX(); 171dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mTouchDownY = (int) event.getY(); 172ada13040d020a289805ddc1f2f49079570cc0e0fAnthony Chen 173ada13040d020a289805ddc1f2f49079570cc0e0fAnthony Chen if (mNavigationBarView != null) { 174a20818257e6927560a676d99dbc563a0394f74d8Jason Monk View recentsButton = mNavigationBarView.getRecentsButton().getCurrentView(); 175ada13040d020a289805ddc1f2f49079570cc0e0fAnthony Chen if (recentsButton != null) { 176ada13040d020a289805ddc1f2f49079570cc0e0fAnthony Chen mDownOnRecents = mTouchDownX >= recentsButton.getLeft() 177ada13040d020a289805ddc1f2f49079570cc0e0fAnthony Chen && mTouchDownX <= recentsButton.getRight() 178ada13040d020a289805ddc1f2f49079570cc0e0fAnthony Chen && mTouchDownY >= recentsButton.getTop() 179ada13040d020a289805ddc1f2f49079570cc0e0fAnthony Chen && mTouchDownY <= recentsButton.getBottom(); 180a20818257e6927560a676d99dbc563a0394f74d8Jason Monk } else { 181a20818257e6927560a676d99dbc563a0394f74d8Jason Monk mDownOnRecents = false; 182ada13040d020a289805ddc1f2f49079570cc0e0fAnthony Chen } 183ada13040d020a289805ddc1f2f49079570cc0e0fAnthony Chen } 184dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 185dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 186dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private boolean handleDragActionMoveEvent(MotionEvent event) { 187dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mVelocityTracker.addMovement(event); 188dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi int x = (int) event.getX(); 189dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi int y = (int) event.getY(); 190dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi int xDiff = Math.abs(x - mTouchDownX); 191dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi int yDiff = Math.abs(y - mTouchDownY); 1929b8018ce9d5d8d2bbc6242989dd18c27d503d925Victor Chan if (mDivider == null || mRecentsComponent == null) { 1939b8018ce9d5d8d2bbc6242989dd18c27d503d925Victor Chan return false; 1949b8018ce9d5d8d2bbc6242989dd18c27d503d925Victor Chan } 195dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi if (!mDockWindowTouchSlopExceeded) { 196dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi boolean touchSlopExceeded = !mIsVertical 19747cf6381a88baee1213eb40de090ed13da892416Jorim Jaggi ? yDiff > mScrollTouchSlop && yDiff > xDiff 19847cf6381a88baee1213eb40de090ed13da892416Jorim Jaggi : xDiff > mScrollTouchSlop && xDiff > yDiff; 199298c08115110a5615a1972884fa7ee24dd9c59d6Jorim Jaggi if (mDownOnRecents && touchSlopExceeded 200298c08115110a5615a1972884fa7ee24dd9c59d6Jorim Jaggi && mDivider.getView().getWindowManagerProxy().getDockSide() == DOCKED_INVALID) { 2019ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi Rect initialBounds = null; 202e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson int dragMode = calculateDragMode(); 203213cbe665b1c45112f46c006f8b7db19b0c7663cJorim Jaggi int createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; 204e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson if (dragMode == DRAG_MODE_DIVIDER) { 2059ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi initialBounds = new Rect(); 2069ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi mDivider.getView().calculateBoundsForPosition(mIsVertical 2079ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi ? (int) event.getRawX() 2089ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi : (int) event.getRawY(), 2099ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi mDivider.getView().isHorizontalDivision() 2109ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi ? DOCKED_TOP 2119ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi : DOCKED_LEFT, 2129ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi initialBounds); 213e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson } else if (dragMode == DRAG_MODE_RECENTS && mTouchDownX 214213cbe665b1c45112f46c006f8b7db19b0c7663cJorim Jaggi < mContext.getResources().getDisplayMetrics().widthPixels / 2) { 215213cbe665b1c45112f46c006f8b7db19b0c7663cJorim Jaggi createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; 2169ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi } 21729379ec859bf7118dec9f3248c63ee369218ad6bJorim Jaggi boolean docked = mRecentsComponent.dockTopTask(dragMode, createMode, initialBounds, 21829379ec859bf7118dec9f3248c63ee369218ad6bJorim Jaggi MetricsEvent.ACTION_WINDOW_DOCK_SWIPE); 219e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson if (docked) { 220e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson mDragMode = dragMode; 221e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson if (mDragMode == DRAG_MODE_DIVIDER) { 22211cc01df271fce5ec3eb05a7281032d1271cc782Jorim Jaggi mDivider.getView().startDragging(false /* animate */, true /* touching*/); 223e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson } 224e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson mDockWindowTouchSlopExceeded = true; 225e6309aa57ee2e33cf1aa0f177948f5b454d8bb12Winson return true; 226dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 227dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 228dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } else { 229dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi if (mDragMode == DRAG_MODE_DIVIDER) { 230dc249c4ae7c7838928f53f151bfda8a6817b8784Jorim Jaggi int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX(); 231e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm() 232df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi .calculateSnapTarget(position, 0f /* velocity */, false /* hardDismiss */); 233e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi mDivider.getView().resizeStack(position, snapTarget.position, snapTarget); 234dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } else if (mDragMode == DRAG_MODE_RECENTS) { 235dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mRecentsComponent.onDraggingInRecents(event.getRawY()); 236dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 237dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 238dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return false; 239dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 240dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 241dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private void handleDragActionUpEvent(MotionEvent event) { 242dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mVelocityTracker.addMovement(event); 243dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mVelocityTracker.computeCurrentVelocity(1000); 2449b8018ce9d5d8d2bbc6242989dd18c27d503d925Victor Chan if (mDockWindowTouchSlopExceeded && mDivider != null && mRecentsComponent != null) { 245dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi if (mDragMode == DRAG_MODE_DIVIDER) { 2469ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi mDivider.getView().stopDragging(mIsVertical 2479ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi ? (int) event.getRawX() 2489ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi : (int) event.getRawY(), 2499ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi mIsVertical 2509ea2f7ba3155a455724f64e2d6a964ad4e99dfa5Jorim Jaggi ? mVelocityTracker.getXVelocity() 251df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi : mVelocityTracker.getYVelocity(), 25229379ec859bf7118dec9f3248c63ee369218ad6bJorim Jaggi true /* avoidDismissStart */, false /* logMetrics */); 253dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } else if (mDragMode == DRAG_MODE_RECENTS) { 254dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity()); 255dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 256dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 257dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mVelocityTracker.recycle(); 258dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mVelocityTracker = null; 259dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 260dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 261dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi private int calculateDragMode() { 262dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi if (mIsVertical && !mDivider.getView().isHorizontalDivision()) { 263dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return DRAG_MODE_DIVIDER; 264dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 265dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi if (!mIsVertical && mDivider.getView().isHorizontalDivision()) { 266dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return DRAG_MODE_DIVIDER; 267dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 268dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return DRAG_MODE_RECENTS; 269dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 270dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 271dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public boolean onTouchEvent(MotionEvent event) { 272dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi boolean result = mTaskSwitcherDetector.onTouchEvent(event); 273dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi if (mDockWindowEnabled) { 274dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi result |= handleDockWindowEvent(event); 275dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 276dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return result; 277dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 278dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi 279dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi @Override 280dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 281dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi float absVelX = Math.abs(velocityX); 282dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi float absVelY = Math.abs(velocityY); 283dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi boolean isValidFling = absVelX > mMinFlingVelocity && 284dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mIsVertical ? (absVelY > absVelX) : (absVelX > absVelY); 2859b8018ce9d5d8d2bbc6242989dd18c27d503d925Victor Chan if (isValidFling && mRecentsComponent != null) { 286dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi boolean showNext; 287dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi if (!mIsRTL) { 288dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi showNext = mIsVertical ? (velocityY < 0) : (velocityX < 0); 289dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } else { 290dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi // In RTL, vertical is still the same, but horizontal is flipped 291dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi showNext = mIsVertical ? (velocityY < 0) : (velocityX > 0); 292dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 293dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi if (showNext) { 294dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mRecentsComponent.showNextAffiliatedTask(); 295dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } else { 296dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi mRecentsComponent.showPrevAffiliatedTask(); 297dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 298dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 299dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi return true; 300dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi } 301e759cd58bda6652e5413e7ca2a39b77bb776a610Winson 302e759cd58bda6652e5413e7ca2a39b77bb776a610Winson @Override 303e759cd58bda6652e5413e7ca2a39b77bb776a610Winson public void onTuningChanged(String key, String newValue) { 304e759cd58bda6652e5413e7ca2a39b77bb776a610Winson switch (key) { 305e759cd58bda6652e5413e7ca2a39b77bb776a610Winson case KEY_DOCK_WINDOW_GESTURE: 3068f2a44f934afd5492248935f564d0b3f2f676d93Jorim Jaggi mDockWindowEnabled = newValue != null && (Integer.parseInt(newValue) != 0); 307e759cd58bda6652e5413e7ca2a39b77bb776a610Winson break; 308e759cd58bda6652e5413e7ca2a39b77bb776a610Winson } 309e759cd58bda6652e5413e7ca2a39b77bb776a610Winson } 310dd98d41e3a65b3bcb37007ea5b29371cf013f563Jorim Jaggi} 311