blob: 67c4008b4dc6ce005b15e1be9d260c19888f9000 [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;
Jorim Jaggid47e7e12016-03-01 09:57:38 +010038import android.view.GestureDetector.SimpleOnGestureListener;
Winsond87e9a42016-04-11 12:57:31 -070039import android.view.HapticFeedbackConstants;
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 Jaggi81fe2d12015-12-21 14:45:18 +010048import android.view.WindowInsets;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010049import android.view.WindowManager;
Jorim Jaggi88afd022016-02-24 21:11:08 -050050import android.view.accessibility.AccessibilityNodeInfo;
51import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010052import android.view.animation.Interpolator;
53import android.view.animation.PathInterpolator;
54import android.widget.FrameLayout;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010055
Jorim Jaggi29379ec2016-04-11 23:43:42 -070056import com.android.internal.logging.MetricsLogger;
57import com.android.internal.logging.MetricsProto.MetricsEvent;
Jorim Jaggi737af722015-12-31 10:42:27 +010058import com.android.internal.policy.DividerSnapAlgorithm;
Winsonc0d70582016-01-29 10:24:39 -080059import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
Jorim Jaggi737af722015-12-31 10:42:27 +010060import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggiea4a19f2016-02-03 21:31:27 -080061import com.android.systemui.Interpolators;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010062import com.android.systemui.R;
Jorim Jaggid47e7e12016-03-01 09:57:38 +010063import com.android.systemui.recents.Recents;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -080064import com.android.systemui.recents.events.EventBus;
Jorim Jaggi899327f2016-02-25 20:44:18 -050065import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
Jorim Jaggicdb06ca2016-01-25 19:15:12 -080066import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
Jorim Jaggiea4a19f2016-02-03 21:31:27 -080067import com.android.systemui.recents.events.activity.UndockingTaskEvent;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -080068import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
Jorim Jaggid47e7e12016-03-01 09:57:38 +010069import com.android.systemui.recents.misc.SystemServicesProxy;
Jorim Jaggi2adba072016-03-03 13:43:39 +010070import com.android.systemui.stackdivider.events.StartedDragingEvent;
71import com.android.systemui.stackdivider.events.StoppedDragingEvent;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010072import com.android.systemui.statusbar.FlingAnimationUtils;
Jorim Jaggicdb06ca2016-01-25 19:15:12 -080073import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010074
75/**
76 * Docked stack divider.
77 */
78public class DividerView extends FrameLayout implements OnTouchListener,
79 OnComputeInternalInsetsListener {
80
Jorim Jaggi514b2cf2016-01-04 13:06:34 +010081 static final long TOUCH_ANIMATION_DURATION = 150;
82 static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
Jorim Jaggi514b2cf2016-01-04 13:06:34 +010083
Jorim Jaggi29379ec2016-04-11 23:43:42 -070084 private static final int LOG_VALUE_RESIZE_50_50 = 0;
85 private static final int LOG_VALUE_RESIZE_DOCKED_SMALLER = 1;
86 private static final int LOG_VALUE_RESIZE_DOCKED_LARGER = 2;
87
88 private static final int LOG_VALUE_UNDOCK_MAX_DOCKED = 0;
89 private static final int LOG_VALUE_UNDOCK_MAX_OTHER = 1;
90
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010091
Jorim Jaggidc249c42015-12-15 14:57:31 -080092 private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
Jorim Jaggi68855982016-03-25 18:46:30 -070093 private static final boolean SWAPPING_ENABLED = false;
Jorim Jaggidc249c42015-12-15 14:57:31 -080094
Jorim Jaggi50cd6362016-01-22 17:18:29 -080095 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080096 * How much the background gets scaled when we are in the minimized dock state.
97 */
Jorim Jaggi2917dc42016-04-11 11:39:13 -070098 private static final float MINIMIZE_DOCK_SCALE = 0f;
Jorim Jaggi698e7632016-04-13 21:02:22 -070099 private static final float ADJUSTED_FOR_IME_SCALE = 0.5f;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800100
Jorim Jaggie435e982015-12-30 13:54:32 +0100101 private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
102 new PathInterpolator(0.5f, 1f, 0.5f, 1f);
Jorim Jaggi8f8155b2016-01-25 19:45:42 -0800103 private static final PathInterpolator DIM_INTERPOLATOR =
104 new PathInterpolator(.23f, .87f, .52f, -0.11f);
Jorim Jaggie435e982015-12-30 13:54:32 +0100105
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100106 private DividerHandleView mHandle;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100107 private View mBackground;
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700108 private MinimizedDockShadow mMinimizedShadow;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100109 private int mStartX;
110 private int mStartY;
111 private int mStartPosition;
112 private int mDockSide;
113 private final int[] mTempInt2 = new int[2];
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100114 private boolean mMoving;
115 private int mTouchSlop;
Jorim Jaggie161f082016-02-05 14:26:16 -0800116 private boolean mBackgroundLifted;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100117
118 private int mDividerInsets;
119 private int mDisplayWidth;
120 private int mDisplayHeight;
121 private int mDividerWindowWidth;
122 private int mDividerSize;
123 private int mTouchElevation;
Jorim Jaggie370e152016-04-15 14:13:33 -0700124 private int mLongPressEntraceAnimDuration;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100125
Jorim Jaggidc249c42015-12-15 14:57:31 -0800126 private final Rect mDockedRect = new Rect();
127 private final Rect mDockedTaskRect = new Rect();
128 private final Rect mOtherTaskRect = new Rect();
129 private final Rect mOtherRect = new Rect();
130 private final Rect mDockedInsetRect = new Rect();
131 private final Rect mOtherInsetRect = new Rect();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100132 private final Rect mLastResizeRect = new Rect();
Jorim Jaggi899327f2016-02-25 20:44:18 -0500133 private final Rect mDisplayRect = new Rect();
Jorim Jaggi870ab5a2015-12-02 18:37:54 -0800134 private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100135 private DividerWindowManager mWindowManager;
136 private VelocityTracker mVelocityTracker;
137 private FlingAnimationUtils mFlingAnimationUtils;
Jorim Jaggidc249c42015-12-15 14:57:31 -0800138 private DividerSnapAlgorithm mSnapAlgorithm;
Jorim Jaggi81fe2d12015-12-21 14:45:18 +0100139 private final Rect mStableInsets = new Rect();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100140
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800141 private boolean mAnimateAfterRecentsDrawn;
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800142 private boolean mGrowAfterRecentsDrawn;
143 private boolean mGrowRecents;
Jorim Jaggi899327f2016-02-25 20:44:18 -0500144 private ValueAnimator mCurrentAnimator;
145 private boolean mEntranceAnimationRunning;
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -0700146 private boolean mExitAnimationRunning;
147 private int mExitStartPosition;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100148 private GestureDetector mGestureDetector;
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700149 private boolean mDockedStackMinimized;
Jorim Jaggi698e7632016-04-13 21:02:22 -0700150 private boolean mAdjustedForIme;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800151
Jorim Jaggi88afd022016-02-24 21:11:08 -0500152 private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
153 @Override
154 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
155 super.onInitializeAccessibilityNodeInfo(host, info);
156 if (isHorizontalDivision()) {
157 info.addAction(new AccessibilityAction(R.id.action_move_up,
158 mContext.getString(R.string.accessibility_action_divider_move_up)));
159 info.addAction(new AccessibilityAction(R.id.action_move_down,
160 mContext.getString(R.string.accessibility_action_divider_move_down)));
161 } else {
162 info.addAction(new AccessibilityAction(R.id.action_move_left,
163 mContext.getString(R.string.accessibility_action_divider_move_left)));
164 info.addAction(new AccessibilityAction(R.id.action_move_right,
165 mContext.getString(R.string.accessibility_action_divider_move_right)));
166 }
167 }
168
169 @Override
170 public boolean performAccessibilityAction(View host, int action, Bundle args) {
171 if (action == R.id.action_move_up || action == R.id.action_move_down
172 || action == R.id.action_move_left || action == R.id.action_move_right) {
173 int position = getCurrentPosition();
174 SnapTarget currentTarget = mSnapAlgorithm.calculateSnapTarget(
175 position, 0 /* velocity */);
176 SnapTarget nextTarget =
177 action == R.id.action_move_up || action == R.id.action_move_left
178 ? mSnapAlgorithm.getPreviousTarget(currentTarget)
179 : mSnapAlgorithm.getNextTarget(currentTarget);
180 startDragging(true /* animate */, false /* touching */);
181 stopDragging(getCurrentPosition(), nextTarget, 250, Interpolators.FAST_OUT_SLOW_IN);
182 return true;
183 }
184 return super.performAccessibilityAction(host, action, args);
185 }
186 };
187
Jorim Jaggie661f402016-03-25 19:11:35 -0700188 private final Runnable mResetBackgroundRunnable = new Runnable() {
189 @Override
190 public void run() {
191 resetBackground();
192 }
193 };
194
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100195 public DividerView(Context context) {
196 super(context);
197 }
198
199 public DividerView(Context context, @Nullable AttributeSet attrs) {
200 super(context, attrs);
201 }
202
203 public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
204 super(context, attrs, defStyleAttr);
205 }
206
207 public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
208 int defStyleRes) {
209 super(context, attrs, defStyleAttr, defStyleRes);
210 }
211
212 @Override
213 protected void onFinishInflate() {
214 super.onFinishInflate();
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100215 mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100216 mBackground = findViewById(R.id.docked_divider_background);
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700217 mMinimizedShadow = (MinimizedDockShadow) findViewById(R.id.minimized_dock_shadow);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100218 mHandle.setOnTouchListener(this);
219 mDividerWindowWidth = getResources().getDimensionPixelSize(
220 com.android.internal.R.dimen.docked_stack_divider_thickness);
221 mDividerInsets = getResources().getDimensionPixelSize(
222 com.android.internal.R.dimen.docked_stack_divider_insets);
223 mDividerSize = mDividerWindowWidth - 2 * mDividerInsets;
224 mTouchElevation = getResources().getDimensionPixelSize(
225 R.dimen.docked_stack_divider_lift_elevation);
Jorim Jaggie370e152016-04-15 14:13:33 -0700226 mLongPressEntraceAnimDuration = getResources().getInteger(
227 R.integer.long_press_dock_anim_duration);
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800228 mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100229 mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100230 mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f);
231 updateDisplayInfo();
Jorim Jaggie48f4282015-11-06 17:32:44 +0100232 boolean landscape = getResources().getConfiguration().orientation
233 == Configuration.ORIENTATION_LANDSCAPE;
Jun Mukaid4eaef72015-10-30 15:54:33 -0700234 mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(),
235 landscape ? STYLE_HORIZONTAL_DOUBLE_ARROW : STYLE_VERTICAL_DOUBLE_ARROW));
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100236 getViewTreeObserver().addOnComputeInternalInsetsListener(this);
Jorim Jaggi88afd022016-02-24 21:11:08 -0500237 mHandle.setAccessibilityDelegate(mHandleDelegate);
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100238 mGestureDetector = new GestureDetector(mContext, new SimpleOnGestureListener() {
239 @Override
240 public boolean onSingleTapUp(MotionEvent e) {
Jorim Jaggi68855982016-03-25 18:46:30 -0700241 if (SWAPPING_ENABLED) {
242 updateDockSide();
243 SystemServicesProxy ssp = Recents.getSystemServices();
244 if (mDockSide != WindowManager.DOCKED_INVALID
245 && !ssp.isRecentsTopMost(ssp.getTopMostTask(), null /* isTopHome */)) {
246 mWindowManagerProxy.swapTasks();
247 return true;
248 }
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100249 }
250 return false;
251 }
252 });
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100253 }
254
Jorim Jaggi81fe2d12015-12-21 14:45:18 +0100255 @Override
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800256 protected void onAttachedToWindow() {
257 super.onAttachedToWindow();
258 EventBus.getDefault().register(this);
259 }
260
261 @Override
262 protected void onDetachedFromWindow() {
263 super.onDetachedFromWindow();
264 EventBus.getDefault().unregister(this);
265 }
266
267 @Override
Jorim Jaggi81fe2d12015-12-21 14:45:18 +0100268 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800269 if (mStableInsets.left != insets.getStableInsetLeft()
270 || mStableInsets.top != insets.getStableInsetTop()
271 || mStableInsets.right != insets.getStableInsetRight()
272 || mStableInsets.bottom != insets.getStableInsetBottom()) {
273 mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
274 insets.getStableInsetRight(), insets.getStableInsetBottom());
275 if (mSnapAlgorithm != null) {
276 mSnapAlgorithm = null;
Jorim Jaggidefd9222016-02-03 18:28:49 -0800277 initializeSnapAlgorithm();
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800278 }
279 }
Jorim Jaggi81fe2d12015-12-21 14:45:18 +0100280 return super.onApplyWindowInsets(insets);
281 }
282
Jorim Jaggi8eb8a322016-04-05 18:03:56 -0700283 @Override
284 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
285 super.onLayout(changed, left, top, right, bottom);
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700286 int minimizeLeft = 0;
287 int minimizeTop = 0;
288 if (mDockSide == WindowManager.DOCKED_TOP) {
289 minimizeTop = mBackground.getTop();
290 } else if (mDockSide == WindowManager.DOCKED_LEFT) {
291 minimizeLeft = mBackground.getLeft();
292 } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
293 minimizeLeft = mBackground.getRight() - mMinimizedShadow.getWidth();
294 }
295 mMinimizedShadow.layout(minimizeLeft, minimizeTop,
296 minimizeLeft + mMinimizedShadow.getMeasuredWidth(),
297 minimizeTop + mMinimizedShadow.getMeasuredHeight());
Jorim Jaggi8eb8a322016-04-05 18:03:56 -0700298 if (changed) {
299 mWindowManagerProxy.setTouchRegion(new Rect(mHandle.getLeft(), mHandle.getTop(),
300 mHandle.getRight(), mHandle.getBottom()));
301 }
302 }
303
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100304 public void setWindowManager(DividerWindowManager windowManager) {
305 mWindowManager = windowManager;
306 }
307
Jorim Jaggidd98d412015-11-18 15:57:38 -0800308 public WindowManagerProxy getWindowManagerProxy() {
309 return mWindowManagerProxy;
310 }
311
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800312 public boolean startDragging(boolean animate, boolean touching) {
Jorim Jaggi0c790412016-02-19 16:38:49 -0800313 cancelFlingAnimation();
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800314 if (touching) {
315 mHandle.setTouching(true, animate);
316 }
Jorim Jaggidd98d412015-11-18 15:57:38 -0800317 mDockSide = mWindowManagerProxy.getDockSide();
Jorim Jaggidefd9222016-02-03 18:28:49 -0800318 initializeSnapAlgorithm();
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800319 mWindowManagerProxy.setResizing(true);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800320 if (touching) {
Jorim Jaggie161f082016-02-05 14:26:16 -0800321 mWindowManager.setSlippery(false);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800322 liftBackground();
Jorim Jaggidd98d412015-11-18 15:57:38 -0800323 }
Jorim Jaggi2adba072016-03-03 13:43:39 +0100324 EventBus.getDefault().send(new StartedDragingEvent());
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800325 return mDockSide != WindowManager.DOCKED_INVALID;
Jorim Jaggidd98d412015-11-18 15:57:38 -0800326 }
327
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700328 public void stopDragging(int position, float velocity, boolean avoidDismissStart,
329 boolean logMetrics) {
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100330 mHandle.setTouching(false, true /* animate */);
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700331 fling(position, velocity, avoidDismissStart, logMetrics);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800332 mWindowManager.setSlippery(true);
333 releaseBackground();
334 }
335
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800336 public void stopDragging(int position, SnapTarget target, long duration,
337 Interpolator interpolator) {
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700338 stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator);
339 }
340
341 public void stopDragging(int position, SnapTarget target, long duration,
342 Interpolator interpolator, long endDelay) {
343 stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800344 }
345
346 public void stopDragging(int position, SnapTarget target, long duration, long startDelay,
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700347 long endDelay, Interpolator interpolator) {
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800348 mHandle.setTouching(false, true /* animate */);
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700349 flingTo(position, target, duration, startDelay, endDelay, interpolator);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800350 mWindowManager.setSlippery(true);
351 releaseBackground();
352 }
353
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800354 private void stopDragging() {
355 mHandle.setTouching(false, true /* animate */);
356 mWindowManager.setSlippery(true);
357 releaseBackground();
358 }
359
360 private void updateDockSide() {
361 mDockSide = mWindowManagerProxy.getDockSide();
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700362 mMinimizedShadow.setDockSide(mDockSide);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800363 }
364
Jorim Jaggidefd9222016-02-03 18:28:49 -0800365 private void initializeSnapAlgorithm() {
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800366 if (mSnapAlgorithm == null) {
367 mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
368 mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
369 }
Jorim Jaggidefd9222016-02-03 18:28:49 -0800370 }
371
372 public DividerSnapAlgorithm getSnapAlgorithm() {
373 initializeSnapAlgorithm();
Jorim Jaggidc249c42015-12-15 14:57:31 -0800374 return mSnapAlgorithm;
375 }
376
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800377 public int getCurrentPosition() {
378 getLocationOnScreen(mTempInt2);
379 if (isHorizontalDivision()) {
380 return mTempInt2[1] + mDividerInsets;
381 } else {
382 return mTempInt2[0] + mDividerInsets;
383 }
384 }
385
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100386 @Override
387 public boolean onTouch(View v, MotionEvent event) {
388 convertToScreenCoordinates(event);
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100389 mGestureDetector.onTouchEvent(event);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100390 final int action = event.getAction() & MotionEvent.ACTION_MASK;
391 switch (action) {
392 case MotionEvent.ACTION_DOWN:
393 mVelocityTracker = VelocityTracker.obtain();
394 mVelocityTracker.addMovement(event);
395 mStartX = (int) event.getX();
396 mStartY = (int) event.getY();
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800397 boolean result = startDragging(true /* animate */, true /* touching */);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800398 if (!result) {
399
400 // Weren't able to start dragging successfully, so cancel it again.
401 stopDragging();
402 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800403 mStartPosition = getCurrentPosition();
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100404 mMoving = false;
Jorim Jaggidd98d412015-11-18 15:57:38 -0800405 return result;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100406 case MotionEvent.ACTION_MOVE:
407 mVelocityTracker.addMovement(event);
408 int x = (int) event.getX();
409 int y = (int) event.getY();
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100410 boolean exceededTouchSlop =
411 isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
412 || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
413 if (!mMoving && exceededTouchSlop) {
414 mStartX = x;
415 mStartY = y;
416 mMoving = true;
417 }
418 if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
Wale Ogunwaleef676d82016-03-18 12:51:55 -0700419 SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(
420 mStartPosition, 0 /* velocity */, false /* hardDismiss */);
421 resizeStack(calculatePosition(x, y), mStartPosition, snapTarget);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100422 }
423 break;
424 case MotionEvent.ACTION_UP:
425 case MotionEvent.ACTION_CANCEL:
426 mVelocityTracker.addMovement(event);
427
428 x = (int) event.getRawX();
429 y = (int) event.getRawY();
430
431 mVelocityTracker.computeCurrentVelocity(1000);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800432 int position = calculatePosition(x, y);
433 stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700434 : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */,
435 true /* log */);
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100436 mMoving = false;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100437 break;
438 }
439 return true;
440 }
441
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700442 private void logResizeEvent(SnapTarget snapTarget) {
443 if (snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
444 MetricsLogger.action(
445 mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideTopLeft(mDockSide)
446 ? LOG_VALUE_UNDOCK_MAX_OTHER
447 : LOG_VALUE_UNDOCK_MAX_DOCKED);
448 } else if (snapTarget == mSnapAlgorithm.getDismissEndTarget()) {
449 MetricsLogger.action(
450 mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideBottomRight(mDockSide)
451 ? LOG_VALUE_UNDOCK_MAX_OTHER
452 : LOG_VALUE_UNDOCK_MAX_DOCKED);
453 } else if (snapTarget == mSnapAlgorithm.getMiddleTarget()) {
454 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
455 LOG_VALUE_RESIZE_50_50);
456 } else if (snapTarget == mSnapAlgorithm.getFirstSplitTarget()) {
457 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
458 dockSideTopLeft(mDockSide)
459 ? LOG_VALUE_RESIZE_DOCKED_SMALLER
460 : LOG_VALUE_RESIZE_DOCKED_LARGER);
461 } else if (snapTarget == mSnapAlgorithm.getLastSplitTarget()) {
462 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
463 dockSideTopLeft(mDockSide)
464 ? LOG_VALUE_RESIZE_DOCKED_LARGER
465 : LOG_VALUE_RESIZE_DOCKED_SMALLER);
466 }
467 }
468
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100469 private void convertToScreenCoordinates(MotionEvent event) {
470 event.setLocation(event.getRawX(), event.getRawY());
471 }
472
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700473 private void fling(int position, float velocity, boolean avoidDismissStart,
474 boolean logMetrics) {
Jorim Jaggidf012d52016-01-15 22:40:13 -0800475 SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
476 if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
477 snapTarget = mSnapAlgorithm.getFirstSplitTarget();
478 }
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700479 if (logMetrics) {
480 logResizeEvent(snapTarget);
481 }
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700482 ValueAnimator anim = getFlingAnimator(position, snapTarget, 0 /* endDelay */);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800483 mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
484 anim.start();
485 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100486
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800487 private void flingTo(int position, SnapTarget target, long duration, long startDelay,
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700488 long endDelay, Interpolator interpolator) {
489 ValueAnimator anim = getFlingAnimator(position, target, endDelay);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800490 anim.setDuration(duration);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800491 anim.setStartDelay(startDelay);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800492 anim.setInterpolator(interpolator);
493 anim.start();
494 }
495
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700496 private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget,
497 final long endDelay) {
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100498 ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
499 anim.addUpdateListener(new AnimatorUpdateListener() {
500 @Override
501 public void onAnimationUpdate(ValueAnimator animation) {
Jorim Jaggidc249c42015-12-15 14:57:31 -0800502 resizeStack((Integer) animation.getAnimatedValue(),
503 animation.getAnimatedFraction() == 1f
504 ? TASK_POSITION_SAME
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800505 : snapTarget.position, snapTarget);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100506 }
507 });
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700508 Runnable endAction = () -> {
509 commitSnapFlags(snapTarget);
510 mWindowManagerProxy.setResizing(false);
511 mDockSide = WindowManager.DOCKED_INVALID;
512 mCurrentAnimator = null;
513 mEntranceAnimationRunning = false;
514 mExitAnimationRunning = false;
515 EventBus.getDefault().send(new StoppedDragingEvent());
516 };
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100517 anim.addListener(new AnimatorListenerAdapter() {
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700518
519 private boolean mCancelled;
520
521 @Override
522 public void onAnimationCancel(Animator animation) {
523 mCancelled = true;
524 }
525
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100526 @Override
527 public void onAnimationEnd(Animator animation) {
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700528 if (endDelay == 0 || mCancelled) {
529 endAction.run();
530 } else {
531 postDelayed(endAction, endDelay);
532 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100533 }
534 });
Jorim Jaggi0c790412016-02-19 16:38:49 -0800535 mCurrentAnimator = anim;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800536 return anim;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100537 }
538
Jorim Jaggi0c790412016-02-19 16:38:49 -0800539 private void cancelFlingAnimation() {
540 if (mCurrentAnimator != null) {
541 mCurrentAnimator.cancel();
542 }
543 }
544
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100545 private void commitSnapFlags(SnapTarget target) {
546 if (target.flag == SnapTarget.FLAG_NONE) {
547 return;
548 }
549 boolean dismissOrMaximize;
550 if (target.flag == SnapTarget.FLAG_DISMISS_START) {
551 dismissOrMaximize = mDockSide == WindowManager.DOCKED_LEFT
552 || mDockSide == WindowManager.DOCKED_TOP;
553 } else {
554 dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT
555 || mDockSide == WindowManager.DOCKED_BOTTOM;
556 }
557 if (dismissOrMaximize) {
558 mWindowManagerProxy.dismissDockedStack();
559 } else {
560 mWindowManagerProxy.maximizeDockedStack();
561 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100562 mWindowManagerProxy.setResizeDimLayer(false, -1, 0f);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100563 }
564
565 private void liftBackground() {
Jorim Jaggie161f082016-02-05 14:26:16 -0800566 if (mBackgroundLifted) {
567 return;
568 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100569 if (isHorizontalDivision()) {
Jorim Jaggi79b39f02015-12-17 20:04:31 -0800570 mBackground.animate().scaleY(1.4f);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100571 } else {
Jorim Jaggi79b39f02015-12-17 20:04:31 -0800572 mBackground.animate().scaleX(1.4f);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100573 }
574 mBackground.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800575 .setInterpolator(Interpolators.TOUCH_RESPONSE)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100576 .setDuration(TOUCH_ANIMATION_DURATION)
577 .translationZ(mTouchElevation)
578 .start();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100579
580 // Lift handle as well so it doesn't get behind the background, even though it doesn't
581 // cast shadow.
582 mHandle.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800583 .setInterpolator(Interpolators.TOUCH_RESPONSE)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100584 .setDuration(TOUCH_ANIMATION_DURATION)
585 .translationZ(mTouchElevation)
586 .start();
Jorim Jaggie161f082016-02-05 14:26:16 -0800587 mBackgroundLifted = true;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100588 }
589
590 private void releaseBackground() {
Jorim Jaggie161f082016-02-05 14:26:16 -0800591 if (!mBackgroundLifted) {
592 return;
593 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100594 mBackground.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800595 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100596 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100597 .translationZ(0)
598 .scaleX(1f)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100599 .scaleY(1f)
600 .start();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100601 mHandle.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800602 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100603 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
604 .translationZ(0)
605 .start();
Jorim Jaggie161f082016-02-05 14:26:16 -0800606 mBackgroundLifted = false;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100607 }
608
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800609
610 public void setMinimizedDockStack(boolean minimized) {
611 updateDockSide();
612 mHandle.setAlpha(minimized ? 0f : 1f);
Jorim Jaggie661f402016-03-25 19:11:35 -0700613 if (!minimized) {
614 resetBackground();
615 } else if (mDockSide == WindowManager.DOCKED_TOP) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800616 mBackground.setPivotY(0);
Jorim Jaggie661f402016-03-25 19:11:35 -0700617 mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800618 } else if (mDockSide == WindowManager.DOCKED_LEFT
619 || mDockSide == WindowManager.DOCKED_RIGHT) {
620 mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
621 ? 0
622 : mBackground.getWidth());
Jorim Jaggie661f402016-03-25 19:11:35 -0700623 mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800624 }
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700625 mMinimizedShadow.setAlpha(minimized ? 1f : 0f);
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700626 mDockedStackMinimized = minimized;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800627 }
628
629 public void setMinimizedDockStack(boolean minimized, long animDuration) {
630 updateDockSide();
631 mHandle.animate()
632 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
633 .setDuration(animDuration)
634 .alpha(minimized ? 0f : 1f)
635 .start();
636 if (mDockSide == WindowManager.DOCKED_TOP) {
637 mBackground.setPivotY(0);
638 mBackground.animate()
639 .scaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f);
640 } else if (mDockSide == WindowManager.DOCKED_LEFT
641 || mDockSide == WindowManager.DOCKED_RIGHT) {
642 mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
643 ? 0
644 : mBackground.getWidth());
645 mBackground.animate()
646 .scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
647 }
Jorim Jaggie661f402016-03-25 19:11:35 -0700648 if (!minimized) {
649 mBackground.animate().withEndAction(mResetBackgroundRunnable);
650 }
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700651 mMinimizedShadow.animate()
652 .alpha(minimized ? 1f : 0f)
653 .setInterpolator(Interpolators.ALPHA_IN)
654 .setDuration(animDuration)
655 .start();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800656 mBackground.animate()
657 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
658 .setDuration(animDuration)
659 .start();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700660 mDockedStackMinimized = minimized;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800661 }
662
Jorim Jaggi698e7632016-04-13 21:02:22 -0700663 public void setAdjustedForIme(boolean adjustedForIme) {
664 updateDockSide();
665 mHandle.setAlpha(adjustedForIme ? 0f : 1f);
666 if (!adjustedForIme) {
667 resetBackground();
668 } else if (mDockSide == WindowManager.DOCKED_TOP) {
669 mBackground.setPivotY(0);
670 mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
671 }
672 mAdjustedForIme = adjustedForIme;
673 }
674
675 public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
676 updateDockSide();
677 mHandle.animate()
678 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
679 .setDuration(animDuration)
680 .alpha(adjustedForIme ? 0f : 1f)
681 .start();
682 if (mDockSide == WindowManager.DOCKED_TOP) {
683 mBackground.setPivotY(0);
684 mBackground.animate()
685 .scaleY(adjustedForIme ? MINIMIZE_DOCK_SCALE : 1f);
686 }
687 if (!adjustedForIme) {
688 mBackground.animate().withEndAction(mResetBackgroundRunnable);
689 }
690 mBackground.animate()
691 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
692 .setDuration(animDuration)
693 .start();
694 mAdjustedForIme = adjustedForIme;
695 }
696
Jorim Jaggie661f402016-03-25 19:11:35 -0700697 private void resetBackground() {
698 mBackground.setPivotX(mBackground.getWidth() / 2);
699 mBackground.setPivotY(mBackground.getHeight() / 2);
700 mBackground.setScaleX(1f);
701 mBackground.setScaleY(1f);
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700702 mMinimizedShadow.setAlpha(0f);
Jorim Jaggie661f402016-03-25 19:11:35 -0700703 }
704
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100705 @Override
706 protected void onConfigurationChanged(Configuration newConfig) {
707 super.onConfigurationChanged(newConfig);
708 updateDisplayInfo();
709 }
710
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700711
712 public void notifyDockSideChanged(int newDockSide) {
713 mDockSide = newDockSide;
714 mMinimizedShadow.setDockSide(mDockSide);
715 requestLayout();
716 }
717
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100718 private void updateDisplayInfo() {
Filip Gruszczynskif6d8e9e2015-11-12 13:39:20 -0800719 final DisplayManager displayManager =
720 (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
721 Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
722 final DisplayInfo info = new DisplayInfo();
723 display.getDisplayInfo(info);
724 mDisplayWidth = info.logicalWidth;
725 mDisplayHeight = info.logicalHeight;
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800726 mSnapAlgorithm = null;
Jorim Jaggidefd9222016-02-03 18:28:49 -0800727 initializeSnapAlgorithm();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100728 }
729
730 private int calculatePosition(int touchX, int touchY) {
731 return isHorizontalDivision() ? calculateYPosition(touchY) : calculateXPosition(touchX);
732 }
733
Jorim Jaggidd98d412015-11-18 15:57:38 -0800734 public boolean isHorizontalDivision() {
735 return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100736 }
737
738 private int calculateXPosition(int touchX) {
739 return mStartPosition + touchX - mStartX;
740 }
741
742 private int calculateYPosition(int touchY) {
743 return mStartPosition + touchY - mStartY;
744 }
745
Jorim Jaggidc249c42015-12-15 14:57:31 -0800746 private void alignTopLeft(Rect containingRect, Rect rect) {
747 int width = rect.width();
748 int height = rect.height();
749 rect.set(containingRect.left, containingRect.top,
750 containingRect.left + width, containingRect.top + height);
751 }
752
753 private void alignBottomRight(Rect containingRect, Rect rect) {
754 int width = rect.width();
755 int height = rect.height();
756 rect.set(containingRect.right - width, containingRect.bottom - height,
757 containingRect.right, containingRect.bottom);
758 }
759
Jorim Jaggi737af722015-12-31 10:42:27 +0100760 public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
761 DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect, mDisplayWidth,
762 mDisplayHeight, mDividerSize);
763 }
764
Jorim Jaggie435e982015-12-30 13:54:32 +0100765 public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
Jorim Jaggidc249c42015-12-15 14:57:31 -0800766 calculateBoundsForPosition(position, mDockSide, mDockedRect);
767
Jorim Jaggie370e152016-04-15 14:13:33 -0700768 if (mDockedRect.equals(mLastResizeRect) && !mEntranceAnimationRunning) {
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100769 return;
770 }
Jorim Jaggic97ba492015-11-06 22:00:18 +0100771
772 // Make sure shadows are updated
Jorim Jaggie161f082016-02-05 14:26:16 -0800773 if (mBackground.getZ() > 0f) {
774 mBackground.invalidate();
775 }
Jorim Jaggic97ba492015-11-06 22:00:18 +0100776
Jorim Jaggidc249c42015-12-15 14:57:31 -0800777 mLastResizeRect.set(mDockedRect);
Jorim Jaggi899327f2016-02-25 20:44:18 -0500778 if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) {
779 if (mCurrentAnimator != null) {
780 calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
781 } else {
782 calculateBoundsForPosition(isHorizontalDivision() ? mDisplayHeight : mDisplayWidth,
783 mDockSide, mDockedTaskRect);
784 }
785 calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
786 mOtherTaskRect);
787 mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
788 mOtherTaskRect, null);
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -0700789 } else if (mExitAnimationRunning && taskPosition != TASK_POSITION_SAME) {
790 calculateBoundsForPosition(taskPosition,
791 mDockSide, mDockedTaskRect);
792 calculateBoundsForPosition(mExitStartPosition,
793 DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700794 mOtherInsetRect.set(mOtherTaskRect);
795 applyExitAnimationParallax(mOtherTaskRect, position);
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -0700796 mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700797 mOtherTaskRect, mOtherInsetRect);
Jorim Jaggi899327f2016-02-25 20:44:18 -0500798 } else if (taskPosition != TASK_POSITION_SAME) {
Winson3e874742016-01-07 10:08:17 -0800799 calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
800 mOtherRect);
801 int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide);
Jorim Jaggie435e982015-12-30 13:54:32 +0100802 int taskPositionDocked =
803 restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
804 int taskPositionOther =
805 restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
806 calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
807 calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
Jorim Jaggi899327f2016-02-25 20:44:18 -0500808 mDisplayRect.set(0, 0, mDisplayWidth, mDisplayHeight);
Jorim Jaggidc249c42015-12-15 14:57:31 -0800809 alignTopLeft(mDockedRect, mDockedTaskRect);
810 alignTopLeft(mOtherRect, mOtherTaskRect);
811 mDockedInsetRect.set(mDockedTaskRect);
812 mOtherInsetRect.set(mOtherTaskRect);
Jorim Jaggie435e982015-12-30 13:54:32 +0100813 if (dockSideTopLeft(mDockSide)) {
Jorim Jaggi899327f2016-02-25 20:44:18 -0500814 alignTopLeft(mDisplayRect, mDockedInsetRect);
815 alignBottomRight(mDisplayRect, mOtherInsetRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -0800816 } else {
Jorim Jaggi899327f2016-02-25 20:44:18 -0500817 alignBottomRight(mDisplayRect, mDockedInsetRect);
818 alignTopLeft(mDisplayRect, mOtherInsetRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -0800819 }
Jorim Jaggie435e982015-12-30 13:54:32 +0100820 applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
821 taskPositionDocked);
822 applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
823 taskPositionOther);
Jorim Jaggidc249c42015-12-15 14:57:31 -0800824 mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
825 mOtherTaskRect, mOtherInsetRect);
826 } else {
827 mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
828 }
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800829 SnapTarget closestDismissTarget = mSnapAlgorithm.getClosestDismissTarget(position);
830 float dimFraction = getDimFraction(position, closestDismissTarget);
831 mWindowManagerProxy.setResizeDimLayer(dimFraction != 0f,
832 getStackIdForDismissTarget(closestDismissTarget),
833 dimFraction);
834 }
835
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700836 private void applyExitAnimationParallax(Rect taskRect, int position) {
837 if (mDockSide == WindowManager.DOCKED_TOP) {
838 taskRect.offset(0, (int) ((position - mExitStartPosition) * 0.25f));
839 } else if (mDockSide == WindowManager.DOCKED_LEFT) {
840 taskRect.offset((int) ((position - mExitStartPosition) * 0.25f), 0);
841 } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
842 taskRect.offset((int) ((mExitStartPosition - position) * 0.25f), 0);
843 }
844 }
845
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800846 private float getDimFraction(int position, SnapTarget dismissTarget) {
Jorim Jaggi899327f2016-02-25 20:44:18 -0500847 if (mEntranceAnimationRunning) {
848 return 0f;
849 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100850 float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
Jorim Jaggi8f8155b2016-01-25 19:45:42 -0800851 fraction = Math.max(0, Math.min(fraction, 1f));
852 fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800853 if (hasInsetsAtDismissTarget(dismissTarget)) {
854
855 // Less darkening with system insets.
856 fraction *= 0.8f;
857 }
858 return fraction;
859 }
860
861 /**
862 * @return true if and only if there are system insets at the location of the dismiss target
863 */
864 private boolean hasInsetsAtDismissTarget(SnapTarget dismissTarget) {
865 if (isHorizontalDivision()) {
866 if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) {
867 return mStableInsets.top != 0;
868 } else {
869 return mStableInsets.bottom != 0;
870 }
871 } else {
872 if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) {
873 return mStableInsets.left != 0;
874 } else {
875 return mStableInsets.right != 0;
876 }
877 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100878 }
879
Jorim Jaggie435e982015-12-30 13:54:32 +0100880 /**
881 * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
882 * 0 size.
883 */
884 private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
885 SnapTarget snapTarget) {
886 if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
887 return mSnapAlgorithm.getFirstSplitTarget().position;
888 } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
889 && dockSideBottomRight(dockSide)) {
890 return mSnapAlgorithm.getLastSplitTarget().position;
891 } else {
892 return taskPosition;
893 }
894 }
895
896 /**
897 * Applies a parallax to the task when dismissing.
898 */
899 private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
900 int position, int taskPosition) {
901 float fraction = Math.min(1, Math.max(0,
902 mSnapAlgorithm.calculateDismissingFraction(position)));
903 SnapTarget dismissTarget = null;
904 SnapTarget splitTarget = null;
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700905 int start = 0;
906 if (position <= mSnapAlgorithm.getLastSplitTarget().position
Jorim Jaggie435e982015-12-30 13:54:32 +0100907 && dockSideTopLeft(dockSide)) {
908 dismissTarget = mSnapAlgorithm.getDismissStartTarget();
909 splitTarget = mSnapAlgorithm.getFirstSplitTarget();
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700910 start = taskPosition;
911 } else if (position >= mSnapAlgorithm.getLastSplitTarget().position
Jorim Jaggie435e982015-12-30 13:54:32 +0100912 && dockSideBottomRight(dockSide)) {
913 dismissTarget = mSnapAlgorithm.getDismissEndTarget();
914 splitTarget = mSnapAlgorithm.getLastSplitTarget();
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700915 start = splitTarget.position;
Jorim Jaggie435e982015-12-30 13:54:32 +0100916 }
917 if (dismissTarget != null && fraction > 0f
918 && isDismissing(splitTarget, position, dockSide)) {
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800919 fraction = calculateParallaxDismissingFraction(fraction, dockSide);
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700920 int offsetPosition = (int) (start +
Jorim Jaggie435e982015-12-30 13:54:32 +0100921 fraction * (dismissTarget.position - splitTarget.position));
922 int width = taskRect.width();
923 int height = taskRect.height();
924 switch (dockSide) {
925 case WindowManager.DOCKED_LEFT:
926 taskRect.left = offsetPosition - width;
927 taskRect.right = offsetPosition;
928 break;
929 case WindowManager.DOCKED_RIGHT:
930 taskRect.left = offsetPosition + mDividerSize;
931 taskRect.right = offsetPosition + width + mDividerSize;
932 break;
933 case WindowManager.DOCKED_TOP:
934 taskRect.top = offsetPosition - height;
935 taskRect.bottom = offsetPosition;
936 break;
937 case WindowManager.DOCKED_BOTTOM:
938 taskRect.top = offsetPosition + mDividerSize;
939 taskRect.bottom = offsetPosition + height + mDividerSize;
940 break;
941 }
942 }
943 }
944
945 /**
946 * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
947 * slowing down parallax effect
948 */
Jorim Jaggi1b12ef52016-01-29 16:49:55 -0800949 private static float calculateParallaxDismissingFraction(float fraction, int dockSide) {
950 float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
951
952 // Less parallax at the top, just because.
953 if (dockSide == WindowManager.DOCKED_TOP) {
954 result /= 2f;
955 }
956 return result;
Jorim Jaggie435e982015-12-30 13:54:32 +0100957 }
958
959 private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
960 if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
961 return position < snapTarget.position;
962 } else {
963 return position > snapTarget.position;
964 }
965 }
966
Jorim Jaggi50981592015-12-29 17:54:12 +0100967 private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700968 if ((dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
969 || (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END
970 && dockSideBottomRight(mDockSide))) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100971 return StackId.DOCKED_STACK_ID;
972 } else {
Jorim Jaggi8dccd232016-03-25 18:10:14 -0700973 return StackId.HOME_STACK_ID;
Jorim Jaggi50981592015-12-29 17:54:12 +0100974 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100975 }
976
Jorim Jaggie435e982015-12-30 13:54:32 +0100977 /**
978 * @return true if and only if {@code dockSide} is top or left
979 */
980 private static boolean dockSideTopLeft(int dockSide) {
981 return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
982 }
983
984 /**
985 * @return true if and only if {@code dockSide} is bottom or right
986 */
987 private static boolean dockSideBottomRight(int dockSide) {
988 return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
989 }
990
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100991 @Override
992 public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
993 inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
994 inoutInfo.touchableRegion.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(),
995 mHandle.getBottom());
996 inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(),
997 mBackground.getRight(), mBackground.getBottom(), Op.UNION);
998 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800999
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001000 public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) {
1001 if (mGrowRecents && getWindowManagerProxy().getDockSide() == WindowManager.DOCKED_TOP
1002 && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
1003 mGrowAfterRecentsDrawn = true;
1004 startDragging(false /* animate */, false /* touching */);
1005 }
1006 }
1007
Jorim Jaggi899327f2016-02-25 20:44:18 -05001008 public final void onBusEvent(DockedTopTaskEvent event) {
1009 if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001010 mGrowAfterRecentsDrawn = false;
1011 mAnimateAfterRecentsDrawn = true;
1012 startDragging(false /* animate */, false /* touching */);
1013 }
Jorim Jaggi899327f2016-02-25 20:44:18 -05001014 updateDockSide();
1015 int position = DockedDividerUtils.calculatePositionForBounds(event.initialRect,
1016 mDockSide, mDividerSize);
1017 mEntranceAnimationRunning = true;
1018 resizeStack(position, mSnapAlgorithm.getMiddleTarget().position,
1019 mSnapAlgorithm.getMiddleTarget());
Winsond87e9a42016-04-11 12:57:31 -07001020
1021 // Vibrate after docking
1022 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001023 }
1024
1025 public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
1026 if (mAnimateAfterRecentsDrawn) {
1027 mAnimateAfterRecentsDrawn = false;
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001028 updateDockSide();
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001029
1030 // Delay switching resizing mode because this might cause jank in recents animation
1031 // that's long than this animation.
1032 stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(),
Jorim Jaggie370e152016-04-15 14:13:33 -07001033 mLongPressEntraceAnimDuration, Interpolators.FAST_OUT_SLOW_IN,
1034 200 /* endDelay */);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001035 }
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001036 if (mGrowAfterRecentsDrawn) {
1037 mGrowAfterRecentsDrawn = false;
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001038 updateDockSide();
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001039 stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001040 Interpolators.FAST_OUT_SLOW_IN);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -08001041 }
1042 }
1043
1044 public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) {
1045 int dockSide = mWindowManagerProxy.getDockSide();
Jorim Jaggief92d6f2016-03-25 22:07:16 -07001046 if (dockSide != WindowManager.DOCKED_INVALID && !mDockedStackMinimized) {
Jorim Jaggiea4a19f2016-02-03 21:31:27 -08001047 startDragging(false /* animate */, false /* touching */);
1048 SnapTarget target = dockSideTopLeft(dockSide)
1049 ? mSnapAlgorithm.getDismissEndTarget()
1050 : mSnapAlgorithm.getDismissStartTarget();
1051
1052 // Don't start immediately - give a little bit time to settle the drag resize change.
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -07001053 mExitAnimationRunning = true;
1054 mExitStartPosition = getCurrentPosition();
1055 stopDragging(mExitStartPosition, target, 336 /* duration */, 100 /* startDelay */,
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001056 0 /* endDelay */, Interpolators.FAST_OUT_SLOW_IN);
Winsond87e9a42016-04-11 12:57:31 -07001057
1058 // Vibrate after undocking
1059 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001060 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001061 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001062}