blob: 7a933cd6576ad3f7c252351cd02acec3b44f24d5 [file] [log] [blame]
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001/*
2 * Copyright (C) 2015 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.stackdivider;
18
Jorim Jaggid47e7e12016-03-01 09:57:38 +010019import static android.view.PointerIcon.STYLE_HORIZONTAL_DOUBLE_ARROW;
20import static android.view.PointerIcon.STYLE_VERTICAL_DOUBLE_ARROW;
21
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010022import android.animation.Animator;
23import android.animation.AnimatorListenerAdapter;
24import android.animation.ValueAnimator;
25import android.animation.ValueAnimator.AnimatorUpdateListener;
26import android.annotation.Nullable;
Jorim Jaggi50981592015-12-29 17:54:12 +010027import android.app.ActivityManager.StackId;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010028import android.content.Context;
29import android.content.res.Configuration;
30import android.graphics.Rect;
31import android.graphics.Region.Op;
Filip Gruszczynskif6d8e9e2015-11-12 13:39:20 -080032import android.hardware.display.DisplayManager;
Jorim Jaggi88afd022016-02-24 21:11:08 -050033import android.os.Bundle;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010034import android.util.AttributeSet;
Filip Gruszczynskif6d8e9e2015-11-12 13:39:20 -080035import android.view.Display;
36import android.view.DisplayInfo;
Jorim Jaggid47e7e12016-03-01 09:57:38 +010037import android.view.GestureDetector;
38import android.view.GestureDetector.OnDoubleTapListener;
39import android.view.GestureDetector.SimpleOnGestureListener;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010040import android.view.MotionEvent;
Jun Mukaid4eaef72015-10-30 15:54:33 -070041import android.view.PointerIcon;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010042import android.view.VelocityTracker;
43import android.view.View;
44import android.view.View.OnTouchListener;
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +010045import android.view.ViewConfiguration;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010046import android.view.ViewTreeObserver.InternalInsetsInfo;
47import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
Jorim Jaggid47e7e12016-03-01 09:57:38 +010048import android.view.ViewTreeObserver.OnGlobalLayoutListener;
Jorim Jaggi81fe2d12015-12-21 14:45:18 +010049import android.view.WindowInsets;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010050import android.view.WindowManager;
Jorim Jaggi88afd022016-02-24 21:11:08 -050051import android.view.accessibility.AccessibilityNodeInfo;
52import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010053import android.view.animation.Interpolator;
54import android.view.animation.PathInterpolator;
55import android.widget.FrameLayout;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010056
Jorim Jaggi737af722015-12-31 10:42:27 +010057import com.android.internal.policy.DividerSnapAlgorithm;
Winsonc0d70582016-01-29 10:24:39 -080058import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
Jorim Jaggi737af722015-12-31 10:42:27 +010059import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggiea4a19f2016-02-03 21:31:27 -080060import com.android.systemui.Interpolators;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010061import com.android.systemui.R;
Jorim Jaggid47e7e12016-03-01 09:57:38 +010062import com.android.systemui.recents.Recents;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -080063import com.android.systemui.recents.events.EventBus;
Jorim Jaggi899327f2016-02-25 20:44:18 -050064import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
Jorim Jaggicdb06ca2016-01-25 19:15:12 -080065import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
Jorim Jaggiea4a19f2016-02-03 21:31:27 -080066import com.android.systemui.recents.events.activity.UndockingTaskEvent;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -080067import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
Jorim Jaggid47e7e12016-03-01 09:57:38 +010068import com.android.systemui.recents.misc.SystemServicesProxy;
Jorim Jaggi2adba072016-03-03 13:43:39 +010069import com.android.systemui.stackdivider.events.StartedDragingEvent;
70import com.android.systemui.stackdivider.events.StoppedDragingEvent;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010071import com.android.systemui.statusbar.FlingAnimationUtils;
Jorim Jaggicdb06ca2016-01-25 19:15:12 -080072import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010073
74/**
75 * Docked stack divider.
76 */
77public class DividerView extends FrameLayout implements OnTouchListener,
78 OnComputeInternalInsetsListener {
79
Jorim Jaggi514b2cf2016-01-04 13:06:34 +010080 static final long TOUCH_ANIMATION_DURATION = 150;
81 static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
Jorim Jaggi514b2cf2016-01-04 13:06:34 +010082
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010083 private static final String TAG = "DividerView";
84
Jorim Jaggidc249c42015-12-15 14:57:31 -080085 private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
Jorim Jaggi68855982016-03-25 18:46:30 -070086 private static final boolean SWAPPING_ENABLED = false;
Jorim Jaggidc249c42015-12-15 14:57:31 -080087
Jorim Jaggi50cd6362016-01-22 17:18:29 -080088 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080089 * How much the background gets scaled when we are in the minimized dock state.
90 */
91 private static final float MINIMIZE_DOCK_SCALE = 0.375f;
92
Jorim Jaggie435e982015-12-30 13:54:32 +010093 private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
94 new PathInterpolator(0.5f, 1f, 0.5f, 1f);
Jorim Jaggi8f8155b2016-01-25 19:45:42 -080095 private static final PathInterpolator DIM_INTERPOLATOR =
96 new PathInterpolator(.23f, .87f, .52f, -0.11f);
Jorim Jaggie435e982015-12-30 13:54:32 +010097
Jorim Jaggi514b2cf2016-01-04 13:06:34 +010098 private DividerHandleView mHandle;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010099 private View mBackground;
100 private int mStartX;
101 private int mStartY;
102 private int mStartPosition;
103 private int mDockSide;
104 private final int[] mTempInt2 = new int[2];
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100105 private boolean mMoving;
106 private int mTouchSlop;
Jorim Jaggie161f082016-02-05 14:26:16 -0800107 private boolean mBackgroundLifted;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100108
109 private int mDividerInsets;
110 private int mDisplayWidth;
111 private int mDisplayHeight;
112 private int mDividerWindowWidth;
113 private int mDividerSize;
114 private int mTouchElevation;
115
Jorim Jaggidc249c42015-12-15 14:57:31 -0800116 private final Rect mDockedRect = new Rect();
117 private final Rect mDockedTaskRect = new Rect();
118 private final Rect mOtherTaskRect = new Rect();
119 private final Rect mOtherRect = new Rect();
120 private final Rect mDockedInsetRect = new Rect();
121 private final Rect mOtherInsetRect = new Rect();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100122 private final Rect mLastResizeRect = new Rect();
Jorim Jaggi899327f2016-02-25 20:44:18 -0500123 private final Rect mDisplayRect = new Rect();
Jorim Jaggi870ab5a2015-12-02 18:37:54 -0800124 private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100125 private DividerWindowManager mWindowManager;
126 private VelocityTracker mVelocityTracker;
127 private FlingAnimationUtils mFlingAnimationUtils;
Jorim Jaggidc249c42015-12-15 14:57:31 -0800128 private DividerSnapAlgorithm mSnapAlgorithm;
Jorim Jaggi81fe2d12015-12-21 14:45:18 +0100129 private final Rect mStableInsets = new Rect();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100130
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800131 private boolean mAnimateAfterRecentsDrawn;
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800132 private boolean mGrowAfterRecentsDrawn;
133 private boolean mGrowRecents;
Jorim Jaggi899327f2016-02-25 20:44:18 -0500134 private ValueAnimator mCurrentAnimator;
135 private boolean mEntranceAnimationRunning;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100136 private GestureDetector mGestureDetector;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800137
Jorim Jaggi88afd022016-02-24 21:11:08 -0500138 private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
139 @Override
140 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
141 super.onInitializeAccessibilityNodeInfo(host, info);
142 if (isHorizontalDivision()) {
143 info.addAction(new AccessibilityAction(R.id.action_move_up,
144 mContext.getString(R.string.accessibility_action_divider_move_up)));
145 info.addAction(new AccessibilityAction(R.id.action_move_down,
146 mContext.getString(R.string.accessibility_action_divider_move_down)));
147 } else {
148 info.addAction(new AccessibilityAction(R.id.action_move_left,
149 mContext.getString(R.string.accessibility_action_divider_move_left)));
150 info.addAction(new AccessibilityAction(R.id.action_move_right,
151 mContext.getString(R.string.accessibility_action_divider_move_right)));
152 }
153 }
154
155 @Override
156 public boolean performAccessibilityAction(View host, int action, Bundle args) {
157 if (action == R.id.action_move_up || action == R.id.action_move_down
158 || action == R.id.action_move_left || action == R.id.action_move_right) {
159 int position = getCurrentPosition();
160 SnapTarget currentTarget = mSnapAlgorithm.calculateSnapTarget(
161 position, 0 /* velocity */);
162 SnapTarget nextTarget =
163 action == R.id.action_move_up || action == R.id.action_move_left
164 ? mSnapAlgorithm.getPreviousTarget(currentTarget)
165 : mSnapAlgorithm.getNextTarget(currentTarget);
166 startDragging(true /* animate */, false /* touching */);
167 stopDragging(getCurrentPosition(), nextTarget, 250, Interpolators.FAST_OUT_SLOW_IN);
168 return true;
169 }
170 return super.performAccessibilityAction(host, action, args);
171 }
172 };
173
Jorim Jaggie661f402016-03-25 19:11:35 -0700174 private final Runnable mResetBackgroundRunnable = new Runnable() {
175 @Override
176 public void run() {
177 resetBackground();
178 }
179 };
180
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100181 public DividerView(Context context) {
182 super(context);
183 }
184
185 public DividerView(Context context, @Nullable AttributeSet attrs) {
186 super(context, attrs);
187 }
188
189 public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
190 super(context, attrs, defStyleAttr);
191 }
192
193 public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
194 int defStyleRes) {
195 super(context, attrs, defStyleAttr, defStyleRes);
196 }
197
198 @Override
199 protected void onFinishInflate() {
200 super.onFinishInflate();
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100201 mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100202 mBackground = findViewById(R.id.docked_divider_background);
203 mHandle.setOnTouchListener(this);
204 mDividerWindowWidth = getResources().getDimensionPixelSize(
205 com.android.internal.R.dimen.docked_stack_divider_thickness);
206 mDividerInsets = getResources().getDimensionPixelSize(
207 com.android.internal.R.dimen.docked_stack_divider_insets);
208 mDividerSize = mDividerWindowWidth - 2 * mDividerInsets;
209 mTouchElevation = getResources().getDimensionPixelSize(
210 R.dimen.docked_stack_divider_lift_elevation);
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800211 mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100212 mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100213 mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f);
214 updateDisplayInfo();
Jorim Jaggie48f4282015-11-06 17:32:44 +0100215 boolean landscape = getResources().getConfiguration().orientation
216 == Configuration.ORIENTATION_LANDSCAPE;
Jun Mukaid4eaef72015-10-30 15:54:33 -0700217 mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(),
218 landscape ? STYLE_HORIZONTAL_DOUBLE_ARROW : STYLE_VERTICAL_DOUBLE_ARROW));
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100219 getViewTreeObserver().addOnComputeInternalInsetsListener(this);
Jorim Jaggi88afd022016-02-24 21:11:08 -0500220 mHandle.setAccessibilityDelegate(mHandleDelegate);
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100221 mGestureDetector = new GestureDetector(mContext, new SimpleOnGestureListener() {
222 @Override
223 public boolean onSingleTapUp(MotionEvent e) {
Jorim Jaggi68855982016-03-25 18:46:30 -0700224 if (SWAPPING_ENABLED) {
225 updateDockSide();
226 SystemServicesProxy ssp = Recents.getSystemServices();
227 if (mDockSide != WindowManager.DOCKED_INVALID
228 && !ssp.isRecentsTopMost(ssp.getTopMostTask(), null /* isTopHome */)) {
229 mWindowManagerProxy.swapTasks();
230 return true;
231 }
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100232 }
233 return false;
234 }
235 });
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100236 }
237
Jorim Jaggi81fe2d12015-12-21 14:45:18 +0100238 @Override
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800239 protected void onAttachedToWindow() {
240 super.onAttachedToWindow();
241 EventBus.getDefault().register(this);
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100242 getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
243
244 @Override
245 public void onGlobalLayout() {
246 getViewTreeObserver().removeOnGlobalLayoutListener(this);
247 mWindowManagerProxy.setTouchRegion(new Rect(mHandle.getLeft(), mHandle.getTop(),
248 mHandle.getLeft() + mHandle.getWidth(),
249 mHandle.getTop() + mHandle.getHeight()));
250 }
251 });
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800252 }
253
254 @Override
255 protected void onDetachedFromWindow() {
256 super.onDetachedFromWindow();
257 EventBus.getDefault().unregister(this);
258 }
259
260 @Override
Jorim Jaggi81fe2d12015-12-21 14:45:18 +0100261 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800262 if (mStableInsets.left != insets.getStableInsetLeft()
263 || mStableInsets.top != insets.getStableInsetTop()
264 || mStableInsets.right != insets.getStableInsetRight()
265 || mStableInsets.bottom != insets.getStableInsetBottom()) {
266 mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
267 insets.getStableInsetRight(), insets.getStableInsetBottom());
268 if (mSnapAlgorithm != null) {
269 mSnapAlgorithm = null;
Jorim Jaggidefd9222016-02-03 18:28:49 -0800270 initializeSnapAlgorithm();
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800271 }
272 }
Jorim Jaggi81fe2d12015-12-21 14:45:18 +0100273 return super.onApplyWindowInsets(insets);
274 }
275
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100276 public void setWindowManager(DividerWindowManager windowManager) {
277 mWindowManager = windowManager;
278 }
279
Jorim Jaggidd98d412015-11-18 15:57:38 -0800280 public WindowManagerProxy getWindowManagerProxy() {
281 return mWindowManagerProxy;
282 }
283
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800284 public boolean startDragging(boolean animate, boolean touching) {
Jorim Jaggi0c790412016-02-19 16:38:49 -0800285 cancelFlingAnimation();
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800286 if (touching) {
287 mHandle.setTouching(true, animate);
288 }
Jorim Jaggidd98d412015-11-18 15:57:38 -0800289 mDockSide = mWindowManagerProxy.getDockSide();
Jorim Jaggidefd9222016-02-03 18:28:49 -0800290 initializeSnapAlgorithm();
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800291 mWindowManagerProxy.setResizing(true);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800292 if (touching) {
Jorim Jaggie161f082016-02-05 14:26:16 -0800293 mWindowManager.setSlippery(false);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800294 liftBackground();
Jorim Jaggidd98d412015-11-18 15:57:38 -0800295 }
Jorim Jaggi2adba072016-03-03 13:43:39 +0100296 EventBus.getDefault().send(new StartedDragingEvent());
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800297 return mDockSide != WindowManager.DOCKED_INVALID;
Jorim Jaggidd98d412015-11-18 15:57:38 -0800298 }
299
Jorim Jaggidf012d52016-01-15 22:40:13 -0800300 public void stopDragging(int position, float velocity, boolean avoidDismissStart) {
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100301 mHandle.setTouching(false, true /* animate */);
Jorim Jaggidf012d52016-01-15 22:40:13 -0800302 fling(position, velocity, avoidDismissStart);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800303 mWindowManager.setSlippery(true);
304 releaseBackground();
305 }
306
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800307 public void stopDragging(int position, SnapTarget target, long duration,
308 Interpolator interpolator) {
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800309 stopDragging(position, target, duration, 0 /* startDelay*/, interpolator);
310 }
311
312 public void stopDragging(int position, SnapTarget target, long duration, long startDelay,
313 Interpolator interpolator) {
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800314 mHandle.setTouching(false, true /* animate */);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800315 flingTo(position, target, duration, startDelay, interpolator);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800316 mWindowManager.setSlippery(true);
317 releaseBackground();
318 }
319
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800320 private void stopDragging() {
321 mHandle.setTouching(false, true /* animate */);
322 mWindowManager.setSlippery(true);
323 releaseBackground();
324 }
325
326 private void updateDockSide() {
327 mDockSide = mWindowManagerProxy.getDockSide();
328 }
329
Jorim Jaggidefd9222016-02-03 18:28:49 -0800330 private void initializeSnapAlgorithm() {
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800331 if (mSnapAlgorithm == null) {
332 mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
333 mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
334 }
Jorim Jaggidefd9222016-02-03 18:28:49 -0800335 }
336
337 public DividerSnapAlgorithm getSnapAlgorithm() {
338 initializeSnapAlgorithm();
Jorim Jaggidc249c42015-12-15 14:57:31 -0800339 return mSnapAlgorithm;
340 }
341
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800342 public int getCurrentPosition() {
343 getLocationOnScreen(mTempInt2);
344 if (isHorizontalDivision()) {
345 return mTempInt2[1] + mDividerInsets;
346 } else {
347 return mTempInt2[0] + mDividerInsets;
348 }
349 }
350
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100351 @Override
352 public boolean onTouch(View v, MotionEvent event) {
353 convertToScreenCoordinates(event);
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100354 mGestureDetector.onTouchEvent(event);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100355 final int action = event.getAction() & MotionEvent.ACTION_MASK;
356 switch (action) {
357 case MotionEvent.ACTION_DOWN:
358 mVelocityTracker = VelocityTracker.obtain();
359 mVelocityTracker.addMovement(event);
360 mStartX = (int) event.getX();
361 mStartY = (int) event.getY();
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800362 boolean result = startDragging(true /* animate */, true /* touching */);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800363 if (!result) {
364
365 // Weren't able to start dragging successfully, so cancel it again.
366 stopDragging();
367 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800368 mStartPosition = getCurrentPosition();
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100369 mMoving = false;
Jorim Jaggidd98d412015-11-18 15:57:38 -0800370 return result;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100371 case MotionEvent.ACTION_MOVE:
372 mVelocityTracker.addMovement(event);
373 int x = (int) event.getX();
374 int y = (int) event.getY();
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100375 boolean exceededTouchSlop =
376 isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
377 || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
378 if (!mMoving && exceededTouchSlop) {
379 mStartX = x;
380 mStartY = y;
381 mMoving = true;
382 }
383 if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
Wale Ogunwaleef676d82016-03-18 12:51:55 -0700384 SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(
385 mStartPosition, 0 /* velocity */, false /* hardDismiss */);
386 resizeStack(calculatePosition(x, y), mStartPosition, snapTarget);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100387 }
388 break;
389 case MotionEvent.ACTION_UP:
390 case MotionEvent.ACTION_CANCEL:
391 mVelocityTracker.addMovement(event);
392
393 x = (int) event.getRawX();
394 y = (int) event.getRawY();
395
396 mVelocityTracker.computeCurrentVelocity(1000);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800397 int position = calculatePosition(x, y);
398 stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
Jorim Jaggidf012d52016-01-15 22:40:13 -0800399 : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */);
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100400 mMoving = false;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100401 break;
402 }
403 return true;
404 }
405
406 private void convertToScreenCoordinates(MotionEvent event) {
407 event.setLocation(event.getRawX(), event.getRawY());
408 }
409
Jorim Jaggidf012d52016-01-15 22:40:13 -0800410 private void fling(int position, float velocity, boolean avoidDismissStart) {
411 SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
412 if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
413 snapTarget = mSnapAlgorithm.getFirstSplitTarget();
414 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800415 ValueAnimator anim = getFlingAnimator(position, snapTarget);
416 mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
417 anim.start();
418 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100419
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800420 private void flingTo(int position, SnapTarget target, long duration, long startDelay,
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800421 Interpolator interpolator) {
422 ValueAnimator anim = getFlingAnimator(position, target);
423 anim.setDuration(duration);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800424 anim.setStartDelay(startDelay);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800425 anim.setInterpolator(interpolator);
426 anim.start();
427 }
428
429 private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget) {
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100430 ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
431 anim.addUpdateListener(new AnimatorUpdateListener() {
432 @Override
433 public void onAnimationUpdate(ValueAnimator animation) {
Jorim Jaggidc249c42015-12-15 14:57:31 -0800434 resizeStack((Integer) animation.getAnimatedValue(),
435 animation.getAnimatedFraction() == 1f
436 ? TASK_POSITION_SAME
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800437 : snapTarget.position, snapTarget);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100438 }
439 });
440 anim.addListener(new AnimatorListenerAdapter() {
441 @Override
442 public void onAnimationEnd(Animator animation) {
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800443 commitSnapFlags(snapTarget);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100444 mWindowManagerProxy.setResizing(false);
445 mDockSide = WindowManager.DOCKED_INVALID;
Jorim Jaggi0c790412016-02-19 16:38:49 -0800446 mCurrentAnimator = null;
Jorim Jaggi899327f2016-02-25 20:44:18 -0500447 mEntranceAnimationRunning = false;
Jorim Jaggi2adba072016-03-03 13:43:39 +0100448 EventBus.getDefault().send(new StoppedDragingEvent());
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100449 }
450 });
Jorim Jaggi0c790412016-02-19 16:38:49 -0800451 mCurrentAnimator = anim;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800452 return anim;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100453 }
454
Jorim Jaggi0c790412016-02-19 16:38:49 -0800455 private void cancelFlingAnimation() {
456 if (mCurrentAnimator != null) {
457 mCurrentAnimator.cancel();
458 }
459 }
460
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100461 private void commitSnapFlags(SnapTarget target) {
462 if (target.flag == SnapTarget.FLAG_NONE) {
463 return;
464 }
465 boolean dismissOrMaximize;
466 if (target.flag == SnapTarget.FLAG_DISMISS_START) {
467 dismissOrMaximize = mDockSide == WindowManager.DOCKED_LEFT
468 || mDockSide == WindowManager.DOCKED_TOP;
469 } else {
470 dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT
471 || mDockSide == WindowManager.DOCKED_BOTTOM;
472 }
473 if (dismissOrMaximize) {
474 mWindowManagerProxy.dismissDockedStack();
475 } else {
476 mWindowManagerProxy.maximizeDockedStack();
477 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100478 mWindowManagerProxy.setResizeDimLayer(false, -1, 0f);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100479 }
480
481 private void liftBackground() {
Jorim Jaggie161f082016-02-05 14:26:16 -0800482 if (mBackgroundLifted) {
483 return;
484 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100485 if (isHorizontalDivision()) {
Jorim Jaggi79b39f02015-12-17 20:04:31 -0800486 mBackground.animate().scaleY(1.4f);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100487 } else {
Jorim Jaggi79b39f02015-12-17 20:04:31 -0800488 mBackground.animate().scaleX(1.4f);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100489 }
490 mBackground.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800491 .setInterpolator(Interpolators.TOUCH_RESPONSE)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100492 .setDuration(TOUCH_ANIMATION_DURATION)
493 .translationZ(mTouchElevation)
494 .start();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100495
496 // Lift handle as well so it doesn't get behind the background, even though it doesn't
497 // cast shadow.
498 mHandle.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800499 .setInterpolator(Interpolators.TOUCH_RESPONSE)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100500 .setDuration(TOUCH_ANIMATION_DURATION)
501 .translationZ(mTouchElevation)
502 .start();
Jorim Jaggie161f082016-02-05 14:26:16 -0800503 mBackgroundLifted = true;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100504 }
505
506 private void releaseBackground() {
Jorim Jaggie161f082016-02-05 14:26:16 -0800507 if (!mBackgroundLifted) {
508 return;
509 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100510 mBackground.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800511 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100512 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100513 .translationZ(0)
514 .scaleX(1f)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100515 .scaleY(1f)
516 .start();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100517 mHandle.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800518 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100519 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
520 .translationZ(0)
521 .start();
Jorim Jaggie161f082016-02-05 14:26:16 -0800522 mBackgroundLifted = false;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100523 }
524
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800525
526 public void setMinimizedDockStack(boolean minimized) {
527 updateDockSide();
528 mHandle.setAlpha(minimized ? 0f : 1f);
Jorim Jaggie661f402016-03-25 19:11:35 -0700529 if (!minimized) {
530 resetBackground();
531 } else if (mDockSide == WindowManager.DOCKED_TOP) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800532 mBackground.setPivotY(0);
Jorim Jaggie661f402016-03-25 19:11:35 -0700533 mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800534 } else if (mDockSide == WindowManager.DOCKED_LEFT
535 || mDockSide == WindowManager.DOCKED_RIGHT) {
536 mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
537 ? 0
538 : mBackground.getWidth());
Jorim Jaggie661f402016-03-25 19:11:35 -0700539 mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800540 }
541 }
542
543 public void setMinimizedDockStack(boolean minimized, long animDuration) {
544 updateDockSide();
545 mHandle.animate()
546 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
547 .setDuration(animDuration)
548 .alpha(minimized ? 0f : 1f)
549 .start();
550 if (mDockSide == WindowManager.DOCKED_TOP) {
551 mBackground.setPivotY(0);
552 mBackground.animate()
553 .scaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f);
554 } else if (mDockSide == WindowManager.DOCKED_LEFT
555 || mDockSide == WindowManager.DOCKED_RIGHT) {
556 mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
557 ? 0
558 : mBackground.getWidth());
559 mBackground.animate()
560 .scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
561 }
Jorim Jaggie661f402016-03-25 19:11:35 -0700562 if (!minimized) {
563 mBackground.animate().withEndAction(mResetBackgroundRunnable);
564 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800565 mBackground.animate()
566 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
567 .setDuration(animDuration)
568 .start();
569 }
570
Jorim Jaggie661f402016-03-25 19:11:35 -0700571 private void resetBackground() {
572 mBackground.setPivotX(mBackground.getWidth() / 2);
573 mBackground.setPivotY(mBackground.getHeight() / 2);
574 mBackground.setScaleX(1f);
575 mBackground.setScaleY(1f);
576 }
577
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100578 @Override
579 protected void onConfigurationChanged(Configuration newConfig) {
580 super.onConfigurationChanged(newConfig);
581 updateDisplayInfo();
582 }
583
584 private void updateDisplayInfo() {
Filip Gruszczynskif6d8e9e2015-11-12 13:39:20 -0800585 final DisplayManager displayManager =
586 (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
587 Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
588 final DisplayInfo info = new DisplayInfo();
589 display.getDisplayInfo(info);
590 mDisplayWidth = info.logicalWidth;
591 mDisplayHeight = info.logicalHeight;
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800592 mSnapAlgorithm = null;
Jorim Jaggidefd9222016-02-03 18:28:49 -0800593 initializeSnapAlgorithm();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100594 }
595
596 private int calculatePosition(int touchX, int touchY) {
597 return isHorizontalDivision() ? calculateYPosition(touchY) : calculateXPosition(touchX);
598 }
599
Jorim Jaggidd98d412015-11-18 15:57:38 -0800600 public boolean isHorizontalDivision() {
601 return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100602 }
603
604 private int calculateXPosition(int touchX) {
605 return mStartPosition + touchX - mStartX;
606 }
607
608 private int calculateYPosition(int touchY) {
609 return mStartPosition + touchY - mStartY;
610 }
611
Jorim Jaggidc249c42015-12-15 14:57:31 -0800612 private void alignTopLeft(Rect containingRect, Rect rect) {
613 int width = rect.width();
614 int height = rect.height();
615 rect.set(containingRect.left, containingRect.top,
616 containingRect.left + width, containingRect.top + height);
617 }
618
619 private void alignBottomRight(Rect containingRect, Rect rect) {
620 int width = rect.width();
621 int height = rect.height();
622 rect.set(containingRect.right - width, containingRect.bottom - height,
623 containingRect.right, containingRect.bottom);
624 }
625
Jorim Jaggi737af722015-12-31 10:42:27 +0100626 public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
627 DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect, mDisplayWidth,
628 mDisplayHeight, mDividerSize);
629 }
630
Jorim Jaggie435e982015-12-30 13:54:32 +0100631 public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
Jorim Jaggidc249c42015-12-15 14:57:31 -0800632 calculateBoundsForPosition(position, mDockSide, mDockedRect);
633
634 if (mDockedRect.equals(mLastResizeRect)) {
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100635 return;
636 }
Jorim Jaggic97ba492015-11-06 22:00:18 +0100637
638 // Make sure shadows are updated
Jorim Jaggie161f082016-02-05 14:26:16 -0800639 if (mBackground.getZ() > 0f) {
640 mBackground.invalidate();
641 }
Jorim Jaggic97ba492015-11-06 22:00:18 +0100642
Jorim Jaggidc249c42015-12-15 14:57:31 -0800643 mLastResizeRect.set(mDockedRect);
Jorim Jaggi899327f2016-02-25 20:44:18 -0500644 if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) {
645 if (mCurrentAnimator != null) {
646 calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
647 } else {
648 calculateBoundsForPosition(isHorizontalDivision() ? mDisplayHeight : mDisplayWidth,
649 mDockSide, mDockedTaskRect);
650 }
651 calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
652 mOtherTaskRect);
653 mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
654 mOtherTaskRect, null);
655 } else if (taskPosition != TASK_POSITION_SAME) {
Winson3e874742016-01-07 10:08:17 -0800656 calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
657 mOtherRect);
658 int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide);
Jorim Jaggie435e982015-12-30 13:54:32 +0100659 int taskPositionDocked =
660 restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
661 int taskPositionOther =
662 restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
663 calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
664 calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
Jorim Jaggi899327f2016-02-25 20:44:18 -0500665 mDisplayRect.set(0, 0, mDisplayWidth, mDisplayHeight);
Jorim Jaggidc249c42015-12-15 14:57:31 -0800666 alignTopLeft(mDockedRect, mDockedTaskRect);
667 alignTopLeft(mOtherRect, mOtherTaskRect);
668 mDockedInsetRect.set(mDockedTaskRect);
669 mOtherInsetRect.set(mOtherTaskRect);
Jorim Jaggie435e982015-12-30 13:54:32 +0100670 if (dockSideTopLeft(mDockSide)) {
Jorim Jaggi899327f2016-02-25 20:44:18 -0500671 alignTopLeft(mDisplayRect, mDockedInsetRect);
672 alignBottomRight(mDisplayRect, mOtherInsetRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -0800673 } else {
Jorim Jaggi899327f2016-02-25 20:44:18 -0500674 alignBottomRight(mDisplayRect, mDockedInsetRect);
675 alignTopLeft(mDisplayRect, mOtherInsetRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -0800676 }
Jorim Jaggie435e982015-12-30 13:54:32 +0100677 applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
678 taskPositionDocked);
679 applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
680 taskPositionOther);
Jorim Jaggidc249c42015-12-15 14:57:31 -0800681 mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
682 mOtherTaskRect, mOtherInsetRect);
683 } else {
684 mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
685 }
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800686 SnapTarget closestDismissTarget = mSnapAlgorithm.getClosestDismissTarget(position);
687 float dimFraction = getDimFraction(position, closestDismissTarget);
688 mWindowManagerProxy.setResizeDimLayer(dimFraction != 0f,
689 getStackIdForDismissTarget(closestDismissTarget),
690 dimFraction);
691 }
692
693 private float getDimFraction(int position, SnapTarget dismissTarget) {
Jorim Jaggi899327f2016-02-25 20:44:18 -0500694 if (mEntranceAnimationRunning) {
695 return 0f;
696 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100697 float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
Jorim Jaggi8f8155b2016-01-25 19:45:42 -0800698 fraction = Math.max(0, Math.min(fraction, 1f));
699 fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800700 if (hasInsetsAtDismissTarget(dismissTarget)) {
701
702 // Less darkening with system insets.
703 fraction *= 0.8f;
704 }
705 return fraction;
706 }
707
708 /**
709 * @return true if and only if there are system insets at the location of the dismiss target
710 */
711 private boolean hasInsetsAtDismissTarget(SnapTarget dismissTarget) {
712 if (isHorizontalDivision()) {
713 if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) {
714 return mStableInsets.top != 0;
715 } else {
716 return mStableInsets.bottom != 0;
717 }
718 } else {
719 if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) {
720 return mStableInsets.left != 0;
721 } else {
722 return mStableInsets.right != 0;
723 }
724 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100725 }
726
Jorim Jaggie435e982015-12-30 13:54:32 +0100727 /**
728 * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
729 * 0 size.
730 */
731 private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
732 SnapTarget snapTarget) {
733 if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
734 return mSnapAlgorithm.getFirstSplitTarget().position;
735 } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
736 && dockSideBottomRight(dockSide)) {
737 return mSnapAlgorithm.getLastSplitTarget().position;
738 } else {
739 return taskPosition;
740 }
741 }
742
743 /**
744 * Applies a parallax to the task when dismissing.
745 */
746 private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
747 int position, int taskPosition) {
748 float fraction = Math.min(1, Math.max(0,
749 mSnapAlgorithm.calculateDismissingFraction(position)));
750 SnapTarget dismissTarget = null;
751 SnapTarget splitTarget = null;
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700752 int start = 0;
753 if (position <= mSnapAlgorithm.getLastSplitTarget().position
Jorim Jaggie435e982015-12-30 13:54:32 +0100754 && dockSideTopLeft(dockSide)) {
755 dismissTarget = mSnapAlgorithm.getDismissStartTarget();
756 splitTarget = mSnapAlgorithm.getFirstSplitTarget();
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700757 start = taskPosition;
758 } else if (position >= mSnapAlgorithm.getLastSplitTarget().position
Jorim Jaggie435e982015-12-30 13:54:32 +0100759 && dockSideBottomRight(dockSide)) {
760 dismissTarget = mSnapAlgorithm.getDismissEndTarget();
761 splitTarget = mSnapAlgorithm.getLastSplitTarget();
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700762 start = splitTarget.position;
Jorim Jaggie435e982015-12-30 13:54:32 +0100763 }
764 if (dismissTarget != null && fraction > 0f
765 && isDismissing(splitTarget, position, dockSide)) {
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800766 fraction = calculateParallaxDismissingFraction(fraction, dockSide);
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700767 int offsetPosition = (int) (start +
Jorim Jaggie435e982015-12-30 13:54:32 +0100768 fraction * (dismissTarget.position - splitTarget.position));
769 int width = taskRect.width();
770 int height = taskRect.height();
771 switch (dockSide) {
772 case WindowManager.DOCKED_LEFT:
773 taskRect.left = offsetPosition - width;
774 taskRect.right = offsetPosition;
775 break;
776 case WindowManager.DOCKED_RIGHT:
777 taskRect.left = offsetPosition + mDividerSize;
778 taskRect.right = offsetPosition + width + mDividerSize;
779 break;
780 case WindowManager.DOCKED_TOP:
781 taskRect.top = offsetPosition - height;
782 taskRect.bottom = offsetPosition;
783 break;
784 case WindowManager.DOCKED_BOTTOM:
785 taskRect.top = offsetPosition + mDividerSize;
786 taskRect.bottom = offsetPosition + height + mDividerSize;
787 break;
788 }
789 }
790 }
791
792 /**
793 * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
794 * slowing down parallax effect
795 */
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800796 private static float calculateParallaxDismissingFraction(float fraction, int dockSide) {
797 float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
798
799 // Less parallax at the top, just because.
800 if (dockSide == WindowManager.DOCKED_TOP) {
801 result /= 2f;
802 }
803 return result;
Jorim Jaggie435e982015-12-30 13:54:32 +0100804 }
805
806 private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
807 if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
808 return position < snapTarget.position;
809 } else {
810 return position > snapTarget.position;
811 }
812 }
813
Jorim Jaggi50981592015-12-29 17:54:12 +0100814 private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700815 if ((dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
816 || (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END
817 && dockSideBottomRight(mDockSide))) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100818 return StackId.DOCKED_STACK_ID;
819 } else {
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700820 return StackId.HOME_STACK_ID;
Jorim Jaggi50981592015-12-29 17:54:12 +0100821 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100822 }
823
Jorim Jaggie435e982015-12-30 13:54:32 +0100824 /**
825 * @return true if and only if {@code dockSide} is top or left
826 */
827 private static boolean dockSideTopLeft(int dockSide) {
828 return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
829 }
830
831 /**
832 * @return true if and only if {@code dockSide} is bottom or right
833 */
834 private static boolean dockSideBottomRight(int dockSide) {
835 return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
836 }
837
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100838 @Override
839 public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
840 inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
841 inoutInfo.touchableRegion.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(),
842 mHandle.getBottom());
843 inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(),
844 mBackground.getRight(), mBackground.getBottom(), Op.UNION);
845 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800846
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800847 public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) {
848 if (mGrowRecents && getWindowManagerProxy().getDockSide() == WindowManager.DOCKED_TOP
849 && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
850 mGrowAfterRecentsDrawn = true;
851 startDragging(false /* animate */, false /* touching */);
852 }
853 }
854
Jorim Jaggi899327f2016-02-25 20:44:18 -0500855 public final void onBusEvent(DockedTopTaskEvent event) {
856 if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800857 mGrowAfterRecentsDrawn = false;
858 mAnimateAfterRecentsDrawn = true;
859 startDragging(false /* animate */, false /* touching */);
860 }
Jorim Jaggi899327f2016-02-25 20:44:18 -0500861 updateDockSide();
862 int position = DockedDividerUtils.calculatePositionForBounds(event.initialRect,
863 mDockSide, mDividerSize);
864 mEntranceAnimationRunning = true;
865 resizeStack(position, mSnapAlgorithm.getMiddleTarget().position,
866 mSnapAlgorithm.getMiddleTarget());
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800867 }
868
869 public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
870 if (mAnimateAfterRecentsDrawn) {
871 mAnimateAfterRecentsDrawn = false;
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800872 updateDockSide();
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800873 stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800874 Interpolators.TOUCH_RESPONSE);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800875 }
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800876 if (mGrowAfterRecentsDrawn) {
877 mGrowAfterRecentsDrawn = false;
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800878 updateDockSide();
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800879 stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800880 Interpolators.TOUCH_RESPONSE);
881 }
882 }
883
884 public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) {
885 int dockSide = mWindowManagerProxy.getDockSide();
886 if (dockSide != WindowManager.DOCKED_INVALID) {
887 startDragging(false /* animate */, false /* touching */);
888 SnapTarget target = dockSideTopLeft(dockSide)
889 ? mSnapAlgorithm.getDismissEndTarget()
890 : mSnapAlgorithm.getDismissStartTarget();
891
892 // Don't start immediately - give a little bit time to settle the drag resize change.
893 stopDragging(getCurrentPosition(), target, 336 /* duration */, 100 /* startDelay */,
894 Interpolators.TOUCH_RESPONSE);
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800895 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800896 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100897}