blob: 42d8c959371f30f094821834ee9fdbff308ba6aa [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
Michael Wrightf9d9ce772016-05-13 17:44:16 +010019import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
20import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
Matthew Ng62c78462018-04-09 14:43:21 -070021import static android.view.WindowManager.DOCKED_RIGHT;
Jorim Jaggid47e7e12016-03-01 09:57:38 +010022
Tony Huang89d580c2020-03-26 14:10:26 +080023import android.animation.AnimationHandler;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010024import android.animation.Animator;
25import android.animation.AnimatorListenerAdapter;
26import android.animation.ValueAnimator;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010027import android.annotation.Nullable;
28import android.content.Context;
29import android.content.res.Configuration;
Evan Rosky0f4db1b2020-04-28 16:20:00 -070030import android.graphics.Matrix;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010031import android.graphics.Rect;
Evan Rosky12837282020-04-27 19:12:25 -070032import android.graphics.Region;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010033import android.graphics.Region.Op;
Filip Gruszczynskif6d8e9e2015-11-12 13:39:20 -080034import android.hardware.display.DisplayManager;
Jorim Jaggi88afd022016-02-24 21:11:08 -050035import android.os.Bundle;
Jorim Jaggia6c05d52016-05-27 00:31:21 -070036import android.os.Handler;
Evan Rosky0f4db1b2020-04-28 16:20:00 -070037import android.os.RemoteException;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010038import android.util.AttributeSet;
Evan Roskyfdc71c42020-03-13 18:23:08 -070039import android.util.Slog;
Filip Gruszczynskif6d8e9e2015-11-12 13:39:20 -080040import android.view.Display;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010041import android.view.MotionEvent;
Jun Mukaid4eaef72015-10-30 15:54:33 -070042import android.view.PointerIcon;
Evan Roskyaf9f27c2020-02-18 18:58:35 +000043import android.view.SurfaceControl;
44import android.view.SurfaceControl.Transaction;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010045import android.view.VelocityTracker;
46import android.view.View;
47import android.view.View.OnTouchListener;
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +010048import android.view.ViewConfiguration;
Evan Rosky36138542020-05-01 18:02:11 -070049import android.view.ViewRootImpl;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010050import android.view.ViewTreeObserver.InternalInsetsInfo;
51import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
52import android.view.WindowManager;
Jorim Jaggi88afd022016-02-24 21:11:08 -050053import android.view.accessibility.AccessibilityNodeInfo;
54import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010055import android.view.animation.Interpolator;
56import android.view.animation.PathInterpolator;
57import android.widget.FrameLayout;
Gus Prevasab336792018-11-14 13:52:20 -050058
Tony Huang89d580c2020-03-26 14:10:26 +080059import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
Jorim Jaggi29379ec2016-04-11 23:43:42 -070060import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010061import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jorim Jaggi737af722015-12-31 10:42:27 +010062import com.android.internal.policy.DividerSnapAlgorithm;
Winsonc0d70582016-01-29 10:24:39 -080063import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
Jorim Jaggi737af722015-12-31 10:42:27 +010064import com.android.internal.policy.DockedDividerUtils;
Sunny Goyal21482542020-05-05 16:34:17 -070065import com.android.systemui.Dependency;
Jorim Jaggiea4a19f2016-02-03 21:31:27 -080066import com.android.systemui.Interpolators;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010067import com.android.systemui.R;
Sunny Goyal21482542020-05-05 16:34:17 -070068import com.android.systemui.recents.OverviewProxyService;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010069import com.android.systemui.statusbar.FlingAnimationUtils;
70
Evan Roskyc0eec052020-03-06 18:54:55 -080071import java.util.function.Consumer;
72
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010073/**
74 * Docked stack divider.
75 */
76public class DividerView extends FrameLayout implements OnTouchListener,
77 OnComputeInternalInsetsListener {
Evan Roskyaf9f27c2020-02-18 18:58:35 +000078 private static final String TAG = "DividerView";
Evan Roskyfdc71c42020-03-13 18:23:08 -070079 private static final boolean DEBUG = Divider.DEBUG;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010080
Winson Chung67f5c8b2018-09-24 12:09:19 -070081 public interface DividerCallbacks {
82 void onDraggingStart();
83 void onDraggingEnd();
84 void growRecents();
85 }
86
Jorim Jaggi514b2cf2016-01-04 13:06:34 +010087 static final long TOUCH_ANIMATION_DURATION = 150;
88 static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
Jorim Jaggi514b2cf2016-01-04 13:06:34 +010089
Jorim Jaggidb21bbd2016-04-18 15:32:07 -070090 public static final int INVALID_RECENTS_GROW_TARGET = -1;
91
Jorim Jaggi29379ec2016-04-11 23:43:42 -070092 private static final int LOG_VALUE_RESIZE_50_50 = 0;
93 private static final int LOG_VALUE_RESIZE_DOCKED_SMALLER = 1;
94 private static final int LOG_VALUE_RESIZE_DOCKED_LARGER = 2;
95
96 private static final int LOG_VALUE_UNDOCK_MAX_DOCKED = 0;
97 private static final int LOG_VALUE_UNDOCK_MAX_OTHER = 1;
98
Jorim Jaggidc249c42015-12-15 14:57:31 -080099 private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
100
Jorim Jaggi50cd6362016-01-22 17:18:29 -0800101 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800102 * How much the background gets scaled when we are in the minimized dock state.
103 */
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700104 private static final float MINIMIZE_DOCK_SCALE = 0f;
Jorim Jaggi698e7632016-04-13 21:02:22 -0700105 private static final float ADJUSTED_FOR_IME_SCALE = 0.5f;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800106
Jorim Jaggie435e982015-12-30 13:54:32 +0100107 private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
108 new PathInterpolator(0.5f, 1f, 0.5f, 1f);
Jorim Jaggi8f8155b2016-01-25 19:45:42 -0800109 private static final PathInterpolator DIM_INTERPOLATOR =
110 new PathInterpolator(.23f, .87f, .52f, -0.11f);
Jorim Jaggi7b458392016-04-20 16:42:06 -0700111 private static final Interpolator IME_ADJUST_INTERPOLATOR =
112 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggie435e982015-12-30 13:54:32 +0100113
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100114 private DividerHandleView mHandle;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100115 private View mBackground;
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700116 private MinimizedDockShadow mMinimizedShadow;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100117 private int mStartX;
118 private int mStartY;
119 private int mStartPosition;
120 private int mDockSide;
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100121 private boolean mMoving;
122 private int mTouchSlop;
Jorim Jaggie161f082016-02-05 14:26:16 -0800123 private boolean mBackgroundLifted;
Matthew Nge15352e2016-12-20 15:36:29 -0800124 private boolean mIsInMinimizeInteraction;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000125 SnapTarget mSnapTargetBeforeMinimized;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100126
127 private int mDividerInsets;
Matthew Ng30307122018-04-13 11:36:34 -0700128 private final Display mDefaultDisplay;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000129
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100130 private int mDividerSize;
131 private int mTouchElevation;
Jorim Jaggie370e152016-04-15 14:13:33 -0700132 private int mLongPressEntraceAnimDuration;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100133
Jorim Jaggidc249c42015-12-15 14:57:31 -0800134 private final Rect mDockedRect = new Rect();
135 private final Rect mDockedTaskRect = new Rect();
136 private final Rect mOtherTaskRect = new Rect();
137 private final Rect mOtherRect = new Rect();
138 private final Rect mDockedInsetRect = new Rect();
139 private final Rect mOtherInsetRect = new Rect();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100140 private final Rect mLastResizeRect = new Rect();
Matthew Ng30307122018-04-13 11:36:34 -0700141 private final Rect mTmpRect = new Rect();
Evan Rosky36138542020-05-01 18:02:11 -0700142 private WindowManagerProxy mWindowManagerProxy;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100143 private DividerWindowManager mWindowManager;
144 private VelocityTracker mVelocityTracker;
145 private FlingAnimationUtils mFlingAnimationUtils;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000146 private SplitDisplayLayout mSplitLayout;
Evan Roskyc3a50902020-05-19 13:36:28 -0700147 private DividerImeController mImeController;
Winson Chung67f5c8b2018-09-24 12:09:19 -0700148 private DividerCallbacks mCallback;
Tony Huang89d580c2020-03-26 14:10:26 +0800149 private final AnimationHandler mAnimationHandler = new AnimationHandler();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100150
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800151 private boolean mGrowRecents;
Jorim Jaggi899327f2016-02-25 20:44:18 -0500152 private ValueAnimator mCurrentAnimator;
153 private boolean mEntranceAnimationRunning;
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -0700154 private boolean mExitAnimationRunning;
155 private int mExitStartPosition;
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700156 private boolean mDockedStackMinimized;
Matthew Nge15352e2016-12-20 15:36:29 -0800157 private boolean mHomeStackResizable;
Jorim Jaggi698e7632016-04-13 21:02:22 -0700158 private boolean mAdjustedForIme;
Jorim Jaggia6c05d52016-05-27 00:31:21 -0700159 private DividerState mState;
Jorim Jaggidbe6fdb2016-07-29 17:16:03 +0200160
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000161 private SplitScreenTaskOrganizer mTiles;
162 boolean mFirstLayout = true;
163 int mDividerPositionX;
164 int mDividerPositionY;
Winson Chung67f5c8b2018-09-24 12:09:19 -0700165
Evan Rosky0f4db1b2020-04-28 16:20:00 -0700166 private final Matrix mTmpMatrix = new Matrix();
167 private final float[] mTmpValues = new float[9];
168
Wale Ogunwale15ba1512017-06-06 08:31:17 -0700169 // The view is removed or in the process of been removed from the system.
170 private boolean mRemoved;
171
Evan Roskye5fb45a2020-03-09 10:51:27 -0700172 // Whether the surface for this view has been hidden regardless of actual visibility. This is
173 // used interact with keyguard.
174 private boolean mSurfaceHidden = false;
175
Tony Huang89d580c2020-03-26 14:10:26 +0800176 private final Handler mHandler = new Handler();
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800177
Jorim Jaggi88afd022016-02-24 21:11:08 -0500178 private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
179 @Override
180 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
181 super.onInitializeAccessibilityNodeInfo(host, info);
Matthew Ng6317df62018-05-04 15:42:54 -0700182 final DividerSnapAlgorithm snapAlgorithm = getSnapAlgorithm();
Jorim Jaggi88afd022016-02-24 21:11:08 -0500183 if (isHorizontalDivision()) {
Winsonce9630d2016-04-19 11:33:04 -0700184 info.addAction(new AccessibilityAction(R.id.action_move_tl_full,
185 mContext.getString(R.string.accessibility_action_divider_top_full)));
Matthew Ng6317df62018-05-04 15:42:54 -0700186 if (snapAlgorithm.isFirstSplitTargetAvailable()) {
Winsonce9630d2016-04-19 11:33:04 -0700187 info.addAction(new AccessibilityAction(R.id.action_move_tl_70,
188 mContext.getString(R.string.accessibility_action_divider_top_70)));
189 }
Matthew Ng6317df62018-05-04 15:42:54 -0700190 if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
191 // Only show the middle target if there are more than 1 split target
192 info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
Winsonce9630d2016-04-19 11:33:04 -0700193 mContext.getString(R.string.accessibility_action_divider_top_50)));
Matthew Ng6317df62018-05-04 15:42:54 -0700194 }
195 if (snapAlgorithm.isLastSplitTargetAvailable()) {
Winsonce9630d2016-04-19 11:33:04 -0700196 info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
197 mContext.getString(R.string.accessibility_action_divider_top_30)));
198 }
199 info.addAction(new AccessibilityAction(R.id.action_move_rb_full,
200 mContext.getString(R.string.accessibility_action_divider_bottom_full)));
Jorim Jaggi88afd022016-02-24 21:11:08 -0500201 } else {
Winsonce9630d2016-04-19 11:33:04 -0700202 info.addAction(new AccessibilityAction(R.id.action_move_tl_full,
203 mContext.getString(R.string.accessibility_action_divider_left_full)));
Matthew Ng6317df62018-05-04 15:42:54 -0700204 if (snapAlgorithm.isFirstSplitTargetAvailable()) {
Winsonce9630d2016-04-19 11:33:04 -0700205 info.addAction(new AccessibilityAction(R.id.action_move_tl_70,
206 mContext.getString(R.string.accessibility_action_divider_left_70)));
207 }
Matthew Ng6317df62018-05-04 15:42:54 -0700208 if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
209 // Only show the middle target if there are more than 1 split target
210 info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
Winsonce9630d2016-04-19 11:33:04 -0700211 mContext.getString(R.string.accessibility_action_divider_left_50)));
Matthew Ng6317df62018-05-04 15:42:54 -0700212 }
213 if (snapAlgorithm.isLastSplitTargetAvailable()) {
Winsonce9630d2016-04-19 11:33:04 -0700214 info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
215 mContext.getString(R.string.accessibility_action_divider_left_30)));
216 }
217 info.addAction(new AccessibilityAction(R.id.action_move_rb_full,
218 mContext.getString(R.string.accessibility_action_divider_right_full)));
Jorim Jaggi88afd022016-02-24 21:11:08 -0500219 }
220 }
221
222 @Override
223 public boolean performAccessibilityAction(View host, int action, Bundle args) {
Winsonce9630d2016-04-19 11:33:04 -0700224 int currentPosition = getCurrentPosition();
225 SnapTarget nextTarget = null;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000226 DividerSnapAlgorithm snapAlgorithm = mSplitLayout.getSnapAlgorithm();
Jason Monk05dd5672018-08-09 09:38:21 -0400227 if (action == R.id.action_move_tl_full) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000228 nextTarget = snapAlgorithm.getDismissEndTarget();
Jason Monk05dd5672018-08-09 09:38:21 -0400229 } else if (action == R.id.action_move_tl_70) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000230 nextTarget = snapAlgorithm.getLastSplitTarget();
Jason Monk05dd5672018-08-09 09:38:21 -0400231 } else if (action == R.id.action_move_tl_50) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000232 nextTarget = snapAlgorithm.getMiddleTarget();
Jason Monk05dd5672018-08-09 09:38:21 -0400233 } else if (action == R.id.action_move_tl_30) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000234 nextTarget = snapAlgorithm.getFirstSplitTarget();
Jason Monk05dd5672018-08-09 09:38:21 -0400235 } else if (action == R.id.action_move_rb_full) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000236 nextTarget = snapAlgorithm.getDismissStartTarget();
Winsonce9630d2016-04-19 11:33:04 -0700237 }
238 if (nextTarget != null) {
Jorim Jaggi88afd022016-02-24 21:11:08 -0500239 startDragging(true /* animate */, false /* touching */);
Winsonce9630d2016-04-19 11:33:04 -0700240 stopDragging(currentPosition, nextTarget, 250, Interpolators.FAST_OUT_SLOW_IN);
Jorim Jaggi88afd022016-02-24 21:11:08 -0500241 return true;
242 }
243 return super.performAccessibilityAction(host, action, args);
244 }
245 };
246
Jorim Jaggie661f402016-03-25 19:11:35 -0700247 private final Runnable mResetBackgroundRunnable = new Runnable() {
248 @Override
249 public void run() {
250 resetBackground();
251 }
252 };
253
Evan Rosky0f4db1b2020-04-28 16:20:00 -0700254 private Runnable mUpdateEmbeddedMatrix = () -> {
255 if (getViewRootImpl() == null) {
256 return;
257 }
258 if (isHorizontalDivision()) {
259 mTmpMatrix.setTranslate(0, mDividerPositionY - mDividerInsets);
260 } else {
261 mTmpMatrix.setTranslate(mDividerPositionX - mDividerInsets, 0);
262 }
263 mTmpMatrix.getValues(mTmpValues);
264 try {
265 getViewRootImpl().getAccessibilityEmbeddedConnection().setScreenMatrix(mTmpValues);
266 } catch (RemoteException e) {
267 }
268 };
269
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100270 public DividerView(Context context) {
Matthew Nga10a9db2017-05-23 15:00:56 -0700271 this(context, null);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100272 }
273
274 public DividerView(Context context, @Nullable AttributeSet attrs) {
Matthew Nga10a9db2017-05-23 15:00:56 -0700275 this(context, attrs, 0);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100276 }
277
278 public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
Matthew Nga10a9db2017-05-23 15:00:56 -0700279 this(context, attrs, defStyleAttr, 0);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100280 }
281
282 public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
283 int defStyleRes) {
284 super(context, attrs, defStyleAttr, defStyleRes);
Matthew Ng30307122018-04-13 11:36:34 -0700285 final DisplayManager displayManager =
286 (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
287 mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
Tony Huang89d580c2020-03-26 14:10:26 +0800288 mAnimationHandler.setProvider(new SfVsyncFrameCallbackProvider());
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100289 }
290
291 @Override
292 protected void onFinishInflate() {
293 super.onFinishInflate();
Alan Viverette51efddb2017-04-05 10:00:01 -0400294 mHandle = findViewById(R.id.docked_divider_handle);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100295 mBackground = findViewById(R.id.docked_divider_background);
Alan Viverette51efddb2017-04-05 10:00:01 -0400296 mMinimizedShadow = findViewById(R.id.minimized_dock_shadow);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100297 mHandle.setOnTouchListener(this);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000298 final int dividerWindowWidth = getResources().getDimensionPixelSize(
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100299 com.android.internal.R.dimen.docked_stack_divider_thickness);
300 mDividerInsets = getResources().getDimensionPixelSize(
301 com.android.internal.R.dimen.docked_stack_divider_insets);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000302 mDividerSize = dividerWindowWidth - 2 * mDividerInsets;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100303 mTouchElevation = getResources().getDimensionPixelSize(
304 R.dimen.docked_stack_divider_lift_elevation);
Jorim Jaggie370e152016-04-15 14:13:33 -0700305 mLongPressEntraceAnimDuration = getResources().getInteger(
306 R.integer.long_press_dock_anim_duration);
Jorim Jaggicdb06ca2016-01-25 19:15:12 -0800307 mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100308 mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
Dave Mankoff1373fdb2019-12-18 14:04:37 -0500309 mFlingAnimationUtils = new FlingAnimationUtils(getResources().getDisplayMetrics(), 0.3f);
Jorim Jaggie48f4282015-11-06 17:32:44 +0100310 boolean landscape = getResources().getConfiguration().orientation
311 == Configuration.ORIENTATION_LANDSCAPE;
Jun Mukaid4eaef72015-10-30 15:54:33 -0700312 mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(),
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100313 landscape ? TYPE_HORIZONTAL_DOUBLE_ARROW : TYPE_VERTICAL_DOUBLE_ARROW));
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100314 getViewTreeObserver().addOnComputeInternalInsetsListener(this);
Jorim Jaggi88afd022016-02-24 21:11:08 -0500315 mHandle.setAccessibilityDelegate(mHandleDelegate);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100316 }
317
Jorim Jaggi81fe2d12015-12-21 14:45:18 +0100318 @Override
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800319 protected void onAttachedToWindow() {
320 super.onAttachedToWindow();
Matthew Ng597bcbb2017-09-07 17:17:38 -0700321
322 // Save the current target if not minimized once attached to window
Evan Rosky89c285e2020-06-17 21:21:53 -0700323 if (mDockSide != WindowManager.DOCKED_INVALID && !mIsInMinimizeInteraction) {
Matthew Ng597bcbb2017-09-07 17:17:38 -0700324 saveSnapTargetBeforeMinimized(mSnapTargetBeforeMinimized);
325 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000326 mFirstLayout = true;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800327 }
328
Wale Ogunwale15ba1512017-06-06 08:31:17 -0700329 void onDividerRemoved() {
330 mRemoved = true;
Winson Chung67f5c8b2018-09-24 12:09:19 -0700331 mCallback = null;
Wale Ogunwale15ba1512017-06-06 08:31:17 -0700332 }
333
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800334 @Override
Jorim Jaggi8eb8a322016-04-05 18:03:56 -0700335 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Evan Rosky12837282020-04-27 19:12:25 -0700336 super.onLayout(changed, left, top, right, bottom);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000337 if (mFirstLayout) {
338 // Wait for first layout so that the ViewRootImpl surface has been created.
339 initializeSurfaceState();
340 mFirstLayout = false;
341 }
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700342 int minimizeLeft = 0;
343 int minimizeTop = 0;
344 if (mDockSide == WindowManager.DOCKED_TOP) {
345 minimizeTop = mBackground.getTop();
346 } else if (mDockSide == WindowManager.DOCKED_LEFT) {
347 minimizeLeft = mBackground.getLeft();
348 } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
349 minimizeLeft = mBackground.getRight() - mMinimizedShadow.getWidth();
350 }
351 mMinimizedShadow.layout(minimizeLeft, minimizeTop,
352 minimizeLeft + mMinimizedShadow.getMeasuredWidth(),
353 minimizeTop + mMinimizedShadow.getMeasuredHeight());
Jorim Jaggi8eb8a322016-04-05 18:03:56 -0700354 if (changed) {
355 mWindowManagerProxy.setTouchRegion(new Rect(mHandle.getLeft(), mHandle.getTop(),
356 mHandle.getRight(), mHandle.getBottom()));
Sunny Goyal21482542020-05-05 16:34:17 -0700357 notifySplitScreenBoundsChanged();
Jorim Jaggi8eb8a322016-04-05 18:03:56 -0700358 }
359 }
360
Winson Chung67f5c8b2018-09-24 12:09:19 -0700361 public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState,
Evan Roskyc3a50902020-05-19 13:36:28 -0700362 DividerCallbacks callback, SplitScreenTaskOrganizer tiles, SplitDisplayLayout sdl,
Evan Rosky36138542020-05-01 18:02:11 -0700363 DividerImeController imeController, WindowManagerProxy wmProxy) {
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100364 mWindowManager = windowManager;
Jorim Jaggia6c05d52016-05-27 00:31:21 -0700365 mState = dividerState;
Winson Chung67f5c8b2018-09-24 12:09:19 -0700366 mCallback = callback;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000367 mTiles = tiles;
368 mSplitLayout = sdl;
Evan Roskyc3a50902020-05-19 13:36:28 -0700369 mImeController = imeController;
Evan Rosky36138542020-05-01 18:02:11 -0700370 mWindowManagerProxy = wmProxy;
Matthew Ng30307122018-04-13 11:36:34 -0700371
372 if (mState.mRatioPositionBeforeMinimized == 0) {
373 // Set the middle target as the initial state
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000374 mSnapTargetBeforeMinimized = mSplitLayout.getSnapAlgorithm().getMiddleTarget();
Matthew Ng30307122018-04-13 11:36:34 -0700375 } else {
376 repositionSnapTargetBeforeMinimized();
377 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100378 }
379
Matthew Ngc603a502018-04-18 17:14:22 -0700380 public Rect getNonMinimizedSplitScreenSecondaryBounds() {
Sunny Goyal21482542020-05-05 16:34:17 -0700381 mOtherTaskRect.set(mSplitLayout.mSecondary);
Matthew Ngc603a502018-04-18 17:14:22 -0700382 return mOtherTaskRect;
383 }
384
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000385 private boolean inSplitMode() {
386 return getVisibility() == VISIBLE;
387 }
388
389 /** Unlike setVisible, this directly hides the surface without changing view visibility. */
390 void setHidden(boolean hidden) {
Evan Roskye5fb45a2020-03-09 10:51:27 -0700391 if (mSurfaceHidden == hidden) {
392 return;
393 }
394 mSurfaceHidden = hidden;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000395 post(() -> {
396 final SurfaceControl sc = getWindowSurfaceControl();
397 if (sc == null) {
398 return;
399 }
400 Transaction t = mTiles.getTransaction();
401 if (hidden) {
402 t.hide(sc);
403 } else {
404 t.show(sc);
405 }
Evan Roskyc3a50902020-05-19 13:36:28 -0700406 mImeController.setDimsHidden(t, hidden);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000407 t.apply();
408 mTiles.releaseTransaction(t);
409 });
410 }
411
Evan Roskye5fb45a2020-03-09 10:51:27 -0700412 boolean isHidden() {
413 return mSurfaceHidden;
414 }
415
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800416 public boolean startDragging(boolean animate, boolean touching) {
Jorim Jaggi0c790412016-02-19 16:38:49 -0800417 cancelFlingAnimation();
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800418 if (touching) {
419 mHandle.setTouching(true, animate);
420 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000421 mDockSide = mSplitLayout.getPrimarySplitSide();
Matthew Ng30307122018-04-13 11:36:34 -0700422
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800423 mWindowManagerProxy.setResizing(true);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800424 if (touching) {
Jorim Jaggie161f082016-02-05 14:26:16 -0800425 mWindowManager.setSlippery(false);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800426 liftBackground();
Jorim Jaggidd98d412015-11-18 15:57:38 -0800427 }
Winson Chung67f5c8b2018-09-24 12:09:19 -0700428 if (mCallback != null) {
429 mCallback.onDraggingStart();
430 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000431 return inSplitMode();
Jorim Jaggidd98d412015-11-18 15:57:38 -0800432 }
433
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700434 public void stopDragging(int position, float velocity, boolean avoidDismissStart,
435 boolean logMetrics) {
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100436 mHandle.setTouching(false, true /* animate */);
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700437 fling(position, velocity, avoidDismissStart, logMetrics);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800438 mWindowManager.setSlippery(true);
439 releaseBackground();
440 }
441
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800442 public void stopDragging(int position, SnapTarget target, long duration,
443 Interpolator interpolator) {
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700444 stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator);
445 }
446
447 public void stopDragging(int position, SnapTarget target, long duration,
448 Interpolator interpolator, long endDelay) {
449 stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800450 }
451
452 public void stopDragging(int position, SnapTarget target, long duration, long startDelay,
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700453 long endDelay, Interpolator interpolator) {
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800454 mHandle.setTouching(false, true /* animate */);
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700455 flingTo(position, target, duration, startDelay, endDelay, interpolator);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800456 mWindowManager.setSlippery(true);
457 releaseBackground();
458 }
459
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800460 private void stopDragging() {
461 mHandle.setTouching(false, true /* animate */);
462 mWindowManager.setSlippery(true);
463 releaseBackground();
464 }
465
466 private void updateDockSide() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000467 mDockSide = mSplitLayout.getPrimarySplitSide();
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700468 mMinimizedShadow.setDockSide(mDockSide);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800469 }
470
Jorim Jaggidefd9222016-02-03 18:28:49 -0800471 public DividerSnapAlgorithm getSnapAlgorithm() {
Evan Rosky89c285e2020-06-17 21:21:53 -0700472 return mDockedStackMinimized ? mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000473 : mSplitLayout.getSnapAlgorithm();
Jorim Jaggidc249c42015-12-15 14:57:31 -0800474 }
475
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800476 public int getCurrentPosition() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000477 return isHorizontalDivision() ? mDividerPositionY : mDividerPositionX;
478 }
479
480 public boolean isMinimized() {
481 return mDockedStackMinimized;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800482 }
483
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100484 @Override
485 public boolean onTouch(View v, MotionEvent event) {
486 convertToScreenCoordinates(event);
487 final int action = event.getAction() & MotionEvent.ACTION_MASK;
488 switch (action) {
489 case MotionEvent.ACTION_DOWN:
490 mVelocityTracker = VelocityTracker.obtain();
491 mVelocityTracker.addMovement(event);
492 mStartX = (int) event.getX();
493 mStartY = (int) event.getY();
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800494 boolean result = startDragging(true /* animate */, true /* touching */);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800495 if (!result) {
496
497 // Weren't able to start dragging successfully, so cancel it again.
498 stopDragging();
499 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800500 mStartPosition = getCurrentPosition();
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100501 mMoving = false;
Jorim Jaggidd98d412015-11-18 15:57:38 -0800502 return result;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100503 case MotionEvent.ACTION_MOVE:
504 mVelocityTracker.addMovement(event);
505 int x = (int) event.getX();
506 int y = (int) event.getY();
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100507 boolean exceededTouchSlop =
508 isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
509 || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
510 if (!mMoving && exceededTouchSlop) {
511 mStartX = x;
512 mStartY = y;
513 mMoving = true;
514 }
515 if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
Matthew Nge15352e2016-12-20 15:36:29 -0800516 SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget(
Wale Ogunwaleef676d82016-03-18 12:51:55 -0700517 mStartPosition, 0 /* velocity */, false /* hardDismiss */);
Evan Rosky36138542020-05-01 18:02:11 -0700518 resizeStackSurfaces(calculatePosition(x, y), mStartPosition, snapTarget,
519 null /* transaction */);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100520 }
521 break;
522 case MotionEvent.ACTION_UP:
523 case MotionEvent.ACTION_CANCEL:
524 mVelocityTracker.addMovement(event);
525
526 x = (int) event.getRawX();
527 y = (int) event.getRawY();
528
529 mVelocityTracker.computeCurrentVelocity(1000);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800530 int position = calculatePosition(x, y);
531 stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700532 : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */,
533 true /* log */);
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100534 mMoving = false;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100535 break;
536 }
537 return true;
538 }
539
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700540 private void logResizeEvent(SnapTarget snapTarget) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000541 if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissStartTarget()) {
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700542 MetricsLogger.action(
543 mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideTopLeft(mDockSide)
544 ? LOG_VALUE_UNDOCK_MAX_OTHER
545 : LOG_VALUE_UNDOCK_MAX_DOCKED);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000546 } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissEndTarget()) {
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700547 MetricsLogger.action(
548 mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideBottomRight(mDockSide)
549 ? LOG_VALUE_UNDOCK_MAX_OTHER
550 : LOG_VALUE_UNDOCK_MAX_DOCKED);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000551 } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getMiddleTarget()) {
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700552 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
553 LOG_VALUE_RESIZE_50_50);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000554 } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getFirstSplitTarget()) {
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700555 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
556 dockSideTopLeft(mDockSide)
557 ? LOG_VALUE_RESIZE_DOCKED_SMALLER
558 : LOG_VALUE_RESIZE_DOCKED_LARGER);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000559 } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getLastSplitTarget()) {
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700560 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
561 dockSideTopLeft(mDockSide)
562 ? LOG_VALUE_RESIZE_DOCKED_LARGER
563 : LOG_VALUE_RESIZE_DOCKED_SMALLER);
564 }
565 }
566
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100567 private void convertToScreenCoordinates(MotionEvent event) {
568 event.setLocation(event.getRawX(), event.getRawY());
569 }
570
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700571 private void fling(int position, float velocity, boolean avoidDismissStart,
572 boolean logMetrics) {
Matthew Nge15352e2016-12-20 15:36:29 -0800573 DividerSnapAlgorithm currentSnapAlgorithm = getSnapAlgorithm();
574 SnapTarget snapTarget = currentSnapAlgorithm.calculateSnapTarget(position, velocity);
575 if (avoidDismissStart && snapTarget == currentSnapAlgorithm.getDismissStartTarget()) {
576 snapTarget = currentSnapAlgorithm.getFirstSplitTarget();
Jorim Jaggidf012d52016-01-15 22:40:13 -0800577 }
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700578 if (logMetrics) {
579 logResizeEvent(snapTarget);
580 }
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700581 ValueAnimator anim = getFlingAnimator(position, snapTarget, 0 /* endDelay */);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800582 mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
583 anim.start();
584 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100585
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800586 private void flingTo(int position, SnapTarget target, long duration, long startDelay,
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700587 long endDelay, Interpolator interpolator) {
588 ValueAnimator anim = getFlingAnimator(position, target, endDelay);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800589 anim.setDuration(duration);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800590 anim.setStartDelay(startDelay);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800591 anim.setInterpolator(interpolator);
592 anim.start();
593 }
594
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700595 private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget,
596 final long endDelay) {
Matthew Nge15352e2016-12-20 15:36:29 -0800597 if (mCurrentAnimator != null) {
598 cancelFlingAnimation();
599 updateDockSide();
600 }
Evan Roskyfdc71c42020-03-13 18:23:08 -0700601 if (DEBUG) Slog.d(TAG, "Getting fling " + position + "->" + snapTarget.position);
Jorim Jaggi069dfe62016-05-04 17:24:47 -0700602 final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100603 ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
Tony Huang89d580c2020-03-26 14:10:26 +0800604 anim.addUpdateListener(animation -> resizeStackSurfaces((int) animation.getAnimatedValue(),
Jorim Jaggi069dfe62016-05-04 17:24:47 -0700605 taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f
606 ? TASK_POSITION_SAME
Jorim Jaggidbe6fdb2016-07-29 17:16:03 +0200607 : snapTarget.taskPosition,
Evan Rosky36138542020-05-01 18:02:11 -0700608 snapTarget, null /* transaction */));
Evan Roskyc0eec052020-03-06 18:54:55 -0800609 Consumer<Boolean> endAction = cancelled -> {
Evan Roskyfdc71c42020-03-13 18:23:08 -0700610 if (DEBUG) Slog.d(TAG, "End Fling " + cancelled + " min:" + mIsInMinimizeInteraction);
Evan Roskyc0eec052020-03-06 18:54:55 -0800611 final boolean wasMinimizeInteraction = mIsInMinimizeInteraction;
612 // Reset minimized divider position after unminimized state animation finishes.
613 if (!cancelled && !mDockedStackMinimized && mIsInMinimizeInteraction) {
614 mIsInMinimizeInteraction = false;
615 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000616 boolean dismissed = commitSnapFlags(snapTarget);
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700617 mWindowManagerProxy.setResizing(false);
Matthew Ngd411f6c2017-07-26 11:09:35 -0700618 updateDockSide();
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700619 mCurrentAnimator = null;
620 mEntranceAnimationRunning = false;
621 mExitAnimationRunning = false;
Evan Roskyc0eec052020-03-06 18:54:55 -0800622 if (!dismissed && !wasMinimizeInteraction) {
623 WindowManagerProxy.applyResizeSplits(snapTarget.position, mSplitLayout);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000624 }
Winson Chung67f5c8b2018-09-24 12:09:19 -0700625 if (mCallback != null) {
626 mCallback.onDraggingEnd();
627 }
Matthew Ng597bcbb2017-09-07 17:17:38 -0700628
629 // Record last snap target the divider moved to
Evan Rosky89c285e2020-06-17 21:21:53 -0700630 if (!mIsInMinimizeInteraction) {
chaviwee947f22018-03-27 16:49:27 -0700631 // The last snapTarget position can be negative when the last divider position was
632 // offscreen. In that case, save the middle (default) SnapTarget so calculating next
633 // position isn't negative.
634 final SnapTarget saveTarget;
635 if (snapTarget.position < 0) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000636 saveTarget = mSplitLayout.getSnapAlgorithm().getMiddleTarget();
chaviwee947f22018-03-27 16:49:27 -0700637 } else {
638 saveTarget = snapTarget;
639 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000640 final DividerSnapAlgorithm snapAlgo = mSplitLayout.getSnapAlgorithm();
641 if (saveTarget.position != snapAlgo.getDismissEndTarget().position
642 && saveTarget.position != snapAlgo.getDismissStartTarget().position) {
Matthew Ng30307122018-04-13 11:36:34 -0700643 saveSnapTargetBeforeMinimized(saveTarget);
644 }
Matthew Ng597bcbb2017-09-07 17:17:38 -0700645 }
Sunny Goyal21482542020-05-05 16:34:17 -0700646 notifySplitScreenBoundsChanged();
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700647 };
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100648 anim.addListener(new AnimatorListenerAdapter() {
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700649
650 private boolean mCancelled;
651
652 @Override
653 public void onAnimationCancel(Animator animation) {
654 mCancelled = true;
655 }
656
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100657 @Override
658 public void onAnimationEnd(Animator animation) {
Jorim Jaggidbe6fdb2016-07-29 17:16:03 +0200659 long delay = 0;
660 if (endDelay != 0) {
661 delay = endDelay;
662 } else if (mCancelled) {
663 delay = 0;
Jorim Jaggidbe6fdb2016-07-29 17:16:03 +0200664 }
665 if (delay == 0) {
Evan Roskyc0eec052020-03-06 18:54:55 -0800666 endAction.accept(mCancelled);
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700667 } else {
Evan Roskyc0eec052020-03-06 18:54:55 -0800668 final Boolean cancelled = mCancelled;
Evan Roskyfdc71c42020-03-13 18:23:08 -0700669 if (DEBUG) Slog.d(TAG, "Posting endFling " + cancelled + " d:" + delay + "ms");
Evan Roskyc0eec052020-03-06 18:54:55 -0800670 mHandler.postDelayed(() -> endAction.accept(cancelled), delay);
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700671 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100672 }
673 });
Tony Huang89d580c2020-03-26 14:10:26 +0800674 anim.setAnimationHandler(mAnimationHandler);
Jorim Jaggi0c790412016-02-19 16:38:49 -0800675 mCurrentAnimator = anim;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800676 return anim;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100677 }
678
Sunny Goyal21482542020-05-05 16:34:17 -0700679 private void notifySplitScreenBoundsChanged() {
680 mOtherTaskRect.set(mSplitLayout.mSecondary);
681
682 mTmpRect.set(mSplitLayout.mDisplayLayout.stableInsets());
683 switch (mSplitLayout.getPrimarySplitSide()) {
684 case WindowManager.DOCKED_LEFT:
685 mTmpRect.left = 0;
686 break;
687 case WindowManager.DOCKED_RIGHT:
688 mTmpRect.right = 0;
689 break;
690 case WindowManager.DOCKED_TOP:
691 mTmpRect.top = 0;
692 break;
693 }
694 Dependency.get(OverviewProxyService.class)
695 .notifySplitScreenBoundsChanged(mOtherTaskRect, mTmpRect);
696 }
697
Jorim Jaggi0c790412016-02-19 16:38:49 -0800698 private void cancelFlingAnimation() {
699 if (mCurrentAnimator != null) {
700 mCurrentAnimator.cancel();
701 }
702 }
703
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000704 private boolean commitSnapFlags(SnapTarget target) {
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100705 if (target.flag == SnapTarget.FLAG_NONE) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000706 return false;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100707 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000708 final boolean dismissOrMaximize;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100709 if (target.flag == SnapTarget.FLAG_DISMISS_START) {
710 dismissOrMaximize = mDockSide == WindowManager.DOCKED_LEFT
711 || mDockSide == WindowManager.DOCKED_TOP;
712 } else {
713 dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT
714 || mDockSide == WindowManager.DOCKED_BOTTOM;
715 }
Evan Rosky36138542020-05-01 18:02:11 -0700716 mWindowManagerProxy.dismissOrMaximizeDocked(mTiles, mSplitLayout, dismissOrMaximize);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000717 Transaction t = mTiles.getTransaction();
718 setResizeDimLayer(t, true /* primary */, 0f);
719 setResizeDimLayer(t, false /* primary */, 0f);
720 t.apply();
721 mTiles.releaseTransaction(t);
722 return true;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100723 }
724
725 private void liftBackground() {
Jorim Jaggie161f082016-02-05 14:26:16 -0800726 if (mBackgroundLifted) {
727 return;
728 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100729 if (isHorizontalDivision()) {
Jorim Jaggi79b39f02015-12-17 20:04:31 -0800730 mBackground.animate().scaleY(1.4f);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100731 } else {
Jorim Jaggi79b39f02015-12-17 20:04:31 -0800732 mBackground.animate().scaleX(1.4f);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100733 }
734 mBackground.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800735 .setInterpolator(Interpolators.TOUCH_RESPONSE)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100736 .setDuration(TOUCH_ANIMATION_DURATION)
737 .translationZ(mTouchElevation)
738 .start();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100739
740 // Lift handle as well so it doesn't get behind the background, even though it doesn't
741 // cast shadow.
742 mHandle.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800743 .setInterpolator(Interpolators.TOUCH_RESPONSE)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100744 .setDuration(TOUCH_ANIMATION_DURATION)
745 .translationZ(mTouchElevation)
746 .start();
Jorim Jaggie161f082016-02-05 14:26:16 -0800747 mBackgroundLifted = true;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100748 }
749
750 private void releaseBackground() {
Jorim Jaggie161f082016-02-05 14:26:16 -0800751 if (!mBackgroundLifted) {
752 return;
753 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100754 mBackground.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800755 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100756 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100757 .translationZ(0)
758 .scaleX(1f)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100759 .scaleY(1f)
760 .start();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100761 mHandle.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800762 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100763 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
764 .translationZ(0)
765 .start();
Jorim Jaggie161f082016-02-05 14:26:16 -0800766 mBackgroundLifted = false;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100767 }
768
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000769 private void initializeSurfaceState() {
770 int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
771 // Recalculate the split-layout's internal tile bounds
772 mSplitLayout.resizeSplits(midPos);
773 Transaction t = mTiles.getTransaction();
774 if (mDockedStackMinimized) {
Evan Rosky89c285e2020-06-17 21:21:53 -0700775 int position = mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
776 .getMiddleTarget().position;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000777 calculateBoundsForPosition(position, mDockSide, mDockedRect);
778 calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
779 mOtherRect);
780 mDividerPositionX = mDividerPositionY = position;
781 resizeSplitSurfaces(t, mDockedRect, mSplitLayout.mPrimary,
782 mOtherRect, mSplitLayout.mSecondary);
783 } else {
784 resizeSplitSurfaces(t, mSplitLayout.mPrimary, null,
785 mSplitLayout.mSecondary, null);
786 }
787 setResizeDimLayer(t, true /* primary */, 0.f /* alpha */);
788 setResizeDimLayer(t, false /* secondary */, 0.f /* alpha */);
789 t.apply();
790 mTiles.releaseTransaction(t);
Evan Rosky12837282020-04-27 19:12:25 -0700791
792 // Get the actually-visible bar dimensions (relative to full window). This is a thin
793 // bar going through the center.
794 final Rect dividerBar = isHorizontalDivision()
795 ? new Rect(0, mDividerInsets, mSplitLayout.mDisplayLayout.width(),
796 mDividerInsets + mDividerSize)
797 : new Rect(mDividerInsets, 0, mDividerInsets + mDividerSize,
798 mSplitLayout.mDisplayLayout.height());
799 final Region touchRegion = new Region(dividerBar);
800 // Add in the "draggable" portion. While not visible, this is an expanded area that the
801 // user can interact with.
802 touchRegion.union(new Rect(mHandle.getLeft(), mHandle.getTop(),
803 mHandle.getRight(), mHandle.getBottom()));
804 mWindowManager.setTouchRegion(touchRegion);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000805 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800806
Evan Rosky36138542020-05-01 18:02:11 -0700807 void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable,
808 Transaction t) {
Matthew Nge15352e2016-12-20 15:36:29 -0800809 mHomeStackResizable = isHomeStackResizable;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800810 updateDockSide();
Jorim Jaggie661f402016-03-25 19:11:35 -0700811 if (!minimized) {
812 resetBackground();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800813 }
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700814 mMinimizedShadow.setAlpha(minimized ? 1f : 0f);
Evan Rosky89c285e2020-06-17 21:21:53 -0700815 if (mDockedStackMinimized != minimized) {
Matthew Ngaa2b6202017-02-10 14:48:21 -0800816 mDockedStackMinimized = minimized;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000817 if (mSplitLayout.mDisplayLayout.rotation() != mDefaultDisplay.getRotation()) {
Matthew Ng4c76a1c2018-05-14 12:45:08 -0700818 // Splitscreen to minimize is about to starts after rotating landscape to seascape,
Sunny Goyal21482542020-05-05 16:34:17 -0700819 // update display info and snap algorithm targets
Matthew Ng4c76a1c2018-05-14 12:45:08 -0700820 repositionSnapTargetBeforeMinimized();
Matthew Ng4c76a1c2018-05-14 12:45:08 -0700821 }
Matthew Nga51dcaa2018-05-07 15:36:06 -0700822 if (mIsInMinimizeInteraction != minimized || mCurrentAnimator != null) {
823 cancelFlingAnimation();
Matthew Ng04f34302017-04-27 16:28:49 -0700824 if (minimized) {
Matthew Ng30307122018-04-13 11:36:34 -0700825 // Relayout to recalculate the divider shadow when minimizing
826 requestLayout();
Matthew Ng04f34302017-04-27 16:28:49 -0700827 mIsInMinimizeInteraction = true;
Evan Rosky89c285e2020-06-17 21:21:53 -0700828 resizeStackSurfaces(mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
829 .getMiddleTarget(), t);
Matthew Ng04f34302017-04-27 16:28:49 -0700830 } else {
Evan Rosky36138542020-05-01 18:02:11 -0700831 resizeStackSurfaces(mSnapTargetBeforeMinimized, t);
Matthew Ng04f34302017-04-27 16:28:49 -0700832 mIsInMinimizeInteraction = false;
833 }
Matthew Nge15352e2016-12-20 15:36:29 -0800834 }
Matthew Nge15352e2016-12-20 15:36:29 -0800835 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800836 }
837
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000838 void enterSplitMode(boolean isHomeStackResizable) {
839 post(() -> {
840 final SurfaceControl sc = getWindowSurfaceControl();
841 if (sc == null) {
842 return;
843 }
844 Transaction t = mTiles.getTransaction();
845 t.show(sc).apply();
846 mTiles.releaseTransaction(t);
847 });
Evan Rosky89c285e2020-06-17 21:21:53 -0700848
849 SnapTarget miniMid =
850 mSplitLayout.getMinimizedSnapAlgorithm(isHomeStackResizable).getMiddleTarget();
851 if (mDockedStackMinimized) {
852 mDividerPositionY = mDividerPositionX = miniMid.position;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000853 }
854 }
855
856 /**
857 * Tries to grab a surface control from ViewRootImpl. If this isn't available for some reason
858 * (ie. the window isn't ready yet), it will get the surfacecontrol that the WindowlessWM has
859 * assigned to it.
860 */
861 private SurfaceControl getWindowSurfaceControl() {
Evan Rosky36138542020-05-01 18:02:11 -0700862 final ViewRootImpl root = getViewRootImpl();
863 if (root == null) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000864 return null;
865 }
Evan Rosky36138542020-05-01 18:02:11 -0700866 SurfaceControl out = root.getSurfaceControl();
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000867 if (out != null && out.isValid()) {
868 return out;
869 }
870 return mWindowManager.mSystemWindows.getViewSurface(this);
871 }
872
873 void exitSplitMode() {
874 // Reset tile bounds
Evan Rosky36138542020-05-01 18:02:11 -0700875 final SurfaceControl sc = getWindowSurfaceControl();
876 if (sc == null) {
877 return;
878 }
879 Transaction t = mTiles.getTransaction();
880 t.hide(sc).apply();
881 mTiles.releaseTransaction(t);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000882 int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
883 WindowManagerProxy.applyResizeSplits(midPos, mSplitLayout);
884 }
885
Matthew Nge15352e2016-12-20 15:36:29 -0800886 public void setMinimizedDockStack(boolean minimized, long animDuration,
887 boolean isHomeStackResizable) {
Evan Roskyfdc71c42020-03-13 18:23:08 -0700888 if (DEBUG) Slog.d(TAG, "setMinDock: " + mDockedStackMinimized + "->" + minimized);
Matthew Nge15352e2016-12-20 15:36:29 -0800889 mHomeStackResizable = isHomeStackResizable;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800890 updateDockSide();
Evan Rosky89c285e2020-06-17 21:21:53 -0700891 if (mDockedStackMinimized != minimized) {
Matthew Nge15352e2016-12-20 15:36:29 -0800892 mIsInMinimizeInteraction = true;
Matthew Nge15352e2016-12-20 15:36:29 -0800893 mDockedStackMinimized = minimized;
Matthew Ngf9989e22017-04-24 17:14:14 -0700894 stopDragging(minimized
Matthew Ng597bcbb2017-09-07 17:17:38 -0700895 ? mSnapTargetBeforeMinimized.position
Matthew Ngf9989e22017-04-24 17:14:14 -0700896 : getCurrentPosition(),
897 minimized
Evan Rosky89c285e2020-06-17 21:21:53 -0700898 ? mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
899 .getMiddleTarget()
Matthew Ng597bcbb2017-09-07 17:17:38 -0700900 : mSnapTargetBeforeMinimized,
Matthew Nge15352e2016-12-20 15:36:29 -0800901 animDuration, Interpolators.FAST_OUT_SLOW_IN, 0);
Matthew Ngf9989e22017-04-24 17:14:14 -0700902 setAdjustedForIme(false, animDuration);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800903 }
Jorim Jaggie661f402016-03-25 19:11:35 -0700904 if (!minimized) {
905 mBackground.animate().withEndAction(mResetBackgroundRunnable);
906 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800907 mBackground.animate()
908 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
909 .setDuration(animDuration)
910 .start();
911 }
912
Evan Roskyc0eec052020-03-06 18:54:55 -0800913 // Needed to end any currently playing animations when they might compete with other anims
914 // (specifically, IME adjust animation immediately after leaving minimized). Someday maybe
915 // these can be unified, but not today.
916 void finishAnimations() {
917 if (mCurrentAnimator != null) {
918 mCurrentAnimator.end();
919 }
920 }
921
Jorim Jaggi698e7632016-04-13 21:02:22 -0700922 public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
Evan Rosky95729202020-02-21 10:16:08 -0800923 if (mAdjustedForIme == adjustedForIme) {
924 return;
925 }
Jorim Jaggi698e7632016-04-13 21:02:22 -0700926 updateDockSide();
927 mHandle.animate()
Jorim Jaggi7b458392016-04-20 16:42:06 -0700928 .setInterpolator(IME_ADJUST_INTERPOLATOR)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700929 .setDuration(animDuration)
930 .alpha(adjustedForIme ? 0f : 1f)
931 .start();
932 if (mDockSide == WindowManager.DOCKED_TOP) {
933 mBackground.setPivotY(0);
934 mBackground.animate()
Jorim Jaggi7b458392016-04-20 16:42:06 -0700935 .scaleY(adjustedForIme ? ADJUSTED_FOR_IME_SCALE : 1f);
Jorim Jaggi698e7632016-04-13 21:02:22 -0700936 }
937 if (!adjustedForIme) {
938 mBackground.animate().withEndAction(mResetBackgroundRunnable);
939 }
940 mBackground.animate()
Jorim Jaggi7b458392016-04-20 16:42:06 -0700941 .setInterpolator(IME_ADJUST_INTERPOLATOR)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700942 .setDuration(animDuration)
943 .start();
944 mAdjustedForIme = adjustedForIme;
945 }
946
Matthew Ng597bcbb2017-09-07 17:17:38 -0700947 private void saveSnapTargetBeforeMinimized(SnapTarget target) {
948 mSnapTargetBeforeMinimized = target;
949 mState.mRatioPositionBeforeMinimized = (float) target.position /
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000950 (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
951 : mSplitLayout.mDisplayLayout.width());
Matthew Ngca3168b2017-05-24 16:40:31 -0700952 }
953
Jorim Jaggie661f402016-03-25 19:11:35 -0700954 private void resetBackground() {
955 mBackground.setPivotX(mBackground.getWidth() / 2);
956 mBackground.setPivotY(mBackground.getHeight() / 2);
957 mBackground.setScaleX(1f);
958 mBackground.setScaleY(1f);
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700959 mMinimizedShadow.setAlpha(0f);
Jorim Jaggie661f402016-03-25 19:11:35 -0700960 }
961
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100962 @Override
963 protected void onConfigurationChanged(Configuration newConfig) {
964 super.onConfigurationChanged(newConfig);
Matthew Ng62c78462018-04-09 14:43:21 -0700965 }
966
967 private void repositionSnapTargetBeforeMinimized() {
968 int position = (int) (mState.mRatioPositionBeforeMinimized *
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000969 (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
970 : mSplitLayout.mDisplayLayout.width()));
Matthew Ng62c78462018-04-09 14:43:21 -0700971
972 // Set the snap target before minimized but do not save until divider is attached and not
973 // minimized because it does not know its minimized state yet.
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000974 mSnapTargetBeforeMinimized =
975 mSplitLayout.getSnapAlgorithm().calculateNonDismissingSnapTarget(position);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100976 }
977
978 private int calculatePosition(int touchX, int touchY) {
979 return isHorizontalDivision() ? calculateYPosition(touchY) : calculateXPosition(touchX);
980 }
981
Jorim Jaggidd98d412015-11-18 15:57:38 -0800982 public boolean isHorizontalDivision() {
983 return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100984 }
985
986 private int calculateXPosition(int touchX) {
987 return mStartPosition + touchX - mStartX;
988 }
989
990 private int calculateYPosition(int touchY) {
991 return mStartPosition + touchY - mStartY;
992 }
993
Jorim Jaggidc249c42015-12-15 14:57:31 -0800994 private void alignTopLeft(Rect containingRect, Rect rect) {
995 int width = rect.width();
996 int height = rect.height();
997 rect.set(containingRect.left, containingRect.top,
998 containingRect.left + width, containingRect.top + height);
999 }
1000
1001 private void alignBottomRight(Rect containingRect, Rect rect) {
1002 int width = rect.width();
1003 int height = rect.height();
1004 rect.set(containingRect.right - width, containingRect.bottom - height,
1005 containingRect.right, containingRect.bottom);
1006 }
1007
Jorim Jaggi737af722015-12-31 10:42:27 +01001008 public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001009 DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect,
1010 mSplitLayout.mDisplayLayout.width(), mSplitLayout.mDisplayLayout.height(),
1011 mDividerSize);
Jorim Jaggi737af722015-12-31 10:42:27 +01001012 }
1013
Evan Rosky36138542020-05-01 18:02:11 -07001014 private void resizeStackSurfaces(SnapTarget taskSnapTarget, Transaction t) {
1015 resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget, t);
Matthew Ng597bcbb2017-09-07 17:17:38 -07001016 }
1017
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001018 void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect otherRect) {
1019 resizeSplitSurfaces(t, dockedRect, null, otherRect, null);
1020 }
1021
1022 private void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect dockedTaskRect,
1023 Rect otherRect, Rect otherTaskRect) {
1024 dockedTaskRect = dockedTaskRect == null ? dockedRect : dockedTaskRect;
1025 otherTaskRect = otherTaskRect == null ? otherRect : otherTaskRect;
1026
Tony Huang0bbb7ef2020-03-24 18:24:54 +08001027 mDividerPositionX = mSplitLayout.getPrimarySplitSide() == DOCKED_RIGHT
1028 ? otherRect.right : dockedRect.right;
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001029 mDividerPositionY = dockedRect.bottom;
1030
Evan Roskyfdc71c42020-03-13 18:23:08 -07001031 if (DEBUG) {
1032 Slog.d(TAG, "Resizing split surfaces: " + dockedRect + " " + dockedTaskRect
1033 + " " + otherRect + " " + otherTaskRect);
1034 }
1035
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001036 t.setPosition(mTiles.mPrimarySurface, dockedTaskRect.left, dockedTaskRect.top);
1037 Rect crop = new Rect(dockedRect);
1038 crop.offsetTo(-Math.min(dockedTaskRect.left - dockedRect.left, 0),
1039 -Math.min(dockedTaskRect.top - dockedRect.top, 0));
1040 t.setWindowCrop(mTiles.mPrimarySurface, crop);
1041 t.setPosition(mTiles.mSecondarySurface, otherTaskRect.left, otherTaskRect.top);
1042 crop.set(otherRect);
1043 crop.offsetTo(-(otherTaskRect.left - otherRect.left),
1044 -(otherTaskRect.top - otherRect.top));
1045 t.setWindowCrop(mTiles.mSecondarySurface, crop);
1046 final SurfaceControl dividerCtrl = getWindowSurfaceControl();
1047 if (dividerCtrl != null) {
1048 if (isHorizontalDivision()) {
1049 t.setPosition(dividerCtrl, 0, mDividerPositionY - mDividerInsets);
1050 } else {
1051 t.setPosition(dividerCtrl, mDividerPositionX - mDividerInsets, 0);
1052 }
1053 }
Evan Rosky0f4db1b2020-04-28 16:20:00 -07001054 if (getViewRootImpl() != null) {
1055 mHandler.removeCallbacks(mUpdateEmbeddedMatrix);
1056 mHandler.post(mUpdateEmbeddedMatrix);
1057 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001058 }
1059
1060 void setResizeDimLayer(Transaction t, boolean primary, float alpha) {
1061 SurfaceControl dim = primary ? mTiles.mPrimaryDim : mTiles.mSecondaryDim;
Evan Roskye5fb45a2020-03-09 10:51:27 -07001062 if (alpha <= 0.001f) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001063 t.hide(dim);
1064 } else {
1065 t.setAlpha(dim, alpha);
1066 t.show(dim);
1067 }
1068 }
1069
Evan Rosky36138542020-05-01 18:02:11 -07001070 void resizeStackSurfaces(int position, int taskPosition, SnapTarget taskSnapTarget,
1071 Transaction transaction) {
Wale Ogunwale15ba1512017-06-06 08:31:17 -07001072 if (mRemoved) {
1073 // This divider view has been removed so shouldn't have any additional influence.
1074 return;
1075 }
Jorim Jaggidc249c42015-12-15 14:57:31 -08001076 calculateBoundsForPosition(position, mDockSide, mDockedRect);
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001077 calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
1078 mOtherRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -08001079
Jorim Jaggie370e152016-04-15 14:13:33 -07001080 if (mDockedRect.equals(mLastResizeRect) && !mEntranceAnimationRunning) {
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001081 return;
1082 }
Jorim Jaggic97ba492015-11-06 22:00:18 +01001083
1084 // Make sure shadows are updated
Jorim Jaggie161f082016-02-05 14:26:16 -08001085 if (mBackground.getZ() > 0f) {
1086 mBackground.invalidate();
1087 }
Jorim Jaggic97ba492015-11-06 22:00:18 +01001088
Evan Rosky36138542020-05-01 18:02:11 -07001089 final boolean ownTransaction = transaction == null;
1090 final Transaction t = ownTransaction ? mTiles.getTransaction() : transaction;
Jorim Jaggidc249c42015-12-15 14:57:31 -08001091 mLastResizeRect.set(mDockedRect);
Evan Rosky89c285e2020-06-17 21:21:53 -07001092 if (mIsInMinimizeInteraction) {
Matthew Ng597bcbb2017-09-07 17:17:38 -07001093 calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
1094 mDockedTaskRect);
Matthew Ng30307122018-04-13 11:36:34 -07001095 calculateBoundsForPosition(mSnapTargetBeforeMinimized.position,
1096 DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
Matthew Ng62c78462018-04-09 14:43:21 -07001097
1098 // Move a right-docked-app to line up with the divider while dragging it
1099 if (mDockSide == DOCKED_RIGHT) {
Sunny Goyal21482542020-05-05 16:34:17 -07001100 mDockedTaskRect.offset(Math.max(position, -mDividerSize)
Matthew Ng62c78462018-04-09 14:43:21 -07001101 - mDockedTaskRect.left + mDividerSize, 0);
1102 }
Evan Rosky89c285e2020-06-17 21:21:53 -07001103 resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
Evan Rosky36138542020-05-01 18:02:11 -07001104 if (ownTransaction) {
1105 t.apply();
1106 mTiles.releaseTransaction(t);
1107 }
Matthew Nge15352e2016-12-20 15:36:29 -08001108 return;
1109 }
1110
Jorim Jaggi899327f2016-02-25 20:44:18 -05001111 if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) {
Matthew Ng30307122018-04-13 11:36:34 -07001112 calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
Matthew Ng62c78462018-04-09 14:43:21 -07001113
1114 // Move a docked app if from the right in position with the divider up to insets
1115 if (mDockSide == DOCKED_RIGHT) {
Sunny Goyal21482542020-05-05 16:34:17 -07001116 mDockedTaskRect.offset(Math.max(position, -mDividerSize)
Matthew Ng30307122018-04-13 11:36:34 -07001117 - mDockedTaskRect.left + mDividerSize, 0);
Matthew Ng62c78462018-04-09 14:43:21 -07001118 }
Jorim Jaggi899327f2016-02-25 20:44:18 -05001119 calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
1120 mOtherTaskRect);
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001121 resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -07001122 } else if (mExitAnimationRunning && taskPosition != TASK_POSITION_SAME) {
Matthew Ng30307122018-04-13 11:36:34 -07001123 calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
1124 mDockedInsetRect.set(mDockedTaskRect);
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -07001125 calculateBoundsForPosition(mExitStartPosition,
1126 DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001127 mOtherInsetRect.set(mOtherTaskRect);
1128 applyExitAnimationParallax(mOtherTaskRect, position);
Matthew Ng30307122018-04-13 11:36:34 -07001129
1130 // Move a right-docked-app to line up with the divider while dragging it
1131 if (mDockSide == DOCKED_RIGHT) {
Sunny Goyal21482542020-05-05 16:34:17 -07001132 mDockedTaskRect.offset(position + mDividerSize, 0);
Matthew Ng30307122018-04-13 11:36:34 -07001133 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001134 resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
Jorim Jaggi899327f2016-02-25 20:44:18 -05001135 } else if (taskPosition != TASK_POSITION_SAME) {
Winson3e874742016-01-07 10:08:17 -08001136 calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
1137 mOtherRect);
1138 int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide);
Jorim Jaggie435e982015-12-30 13:54:32 +01001139 int taskPositionDocked =
1140 restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
1141 int taskPositionOther =
1142 restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
1143 calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
1144 calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001145 mTmpRect.set(0, 0, mSplitLayout.mDisplayLayout.width(),
1146 mSplitLayout.mDisplayLayout.height());
Jorim Jaggidc249c42015-12-15 14:57:31 -08001147 alignTopLeft(mDockedRect, mDockedTaskRect);
1148 alignTopLeft(mOtherRect, mOtherTaskRect);
1149 mDockedInsetRect.set(mDockedTaskRect);
1150 mOtherInsetRect.set(mOtherTaskRect);
Jorim Jaggie435e982015-12-30 13:54:32 +01001151 if (dockSideTopLeft(mDockSide)) {
Matthew Ng30307122018-04-13 11:36:34 -07001152 alignTopLeft(mTmpRect, mDockedInsetRect);
1153 alignBottomRight(mTmpRect, mOtherInsetRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -08001154 } else {
Matthew Ng30307122018-04-13 11:36:34 -07001155 alignBottomRight(mTmpRect, mDockedInsetRect);
1156 alignTopLeft(mTmpRect, mOtherInsetRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -08001157 }
Jorim Jaggie435e982015-12-30 13:54:32 +01001158 applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
1159 taskPositionDocked);
1160 applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
1161 taskPositionOther);
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001162 resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -08001163 } else {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001164 resizeSplitSurfaces(t, mDockedRect, null, mOtherRect, null);
Jorim Jaggidc249c42015-12-15 14:57:31 -08001165 }
Matthew Nge15352e2016-12-20 15:36:29 -08001166 SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position);
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001167 float dimFraction = getDimFraction(position, closestDismissTarget);
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001168 setResizeDimLayer(t, isDismissTargetPrimary(closestDismissTarget), dimFraction);
Evan Rosky36138542020-05-01 18:02:11 -07001169 if (ownTransaction) {
1170 t.apply();
1171 mTiles.releaseTransaction(t);
1172 }
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001173 }
1174
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001175 private void applyExitAnimationParallax(Rect taskRect, int position) {
1176 if (mDockSide == WindowManager.DOCKED_TOP) {
1177 taskRect.offset(0, (int) ((position - mExitStartPosition) * 0.25f));
1178 } else if (mDockSide == WindowManager.DOCKED_LEFT) {
1179 taskRect.offset((int) ((position - mExitStartPosition) * 0.25f), 0);
1180 } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
1181 taskRect.offset((int) ((mExitStartPosition - position) * 0.25f), 0);
1182 }
1183 }
1184
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001185 private float getDimFraction(int position, SnapTarget dismissTarget) {
Jorim Jaggi899327f2016-02-25 20:44:18 -05001186 if (mEntranceAnimationRunning) {
1187 return 0f;
1188 }
Matthew Nge15352e2016-12-20 15:36:29 -08001189 float fraction = getSnapAlgorithm().calculateDismissingFraction(position);
Jorim Jaggi8f8155b2016-01-25 19:45:42 -08001190 fraction = Math.max(0, Math.min(fraction, 1f));
1191 fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001192 return fraction;
1193 }
1194
1195 /**
Jorim Jaggie435e982015-12-30 13:54:32 +01001196 * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
1197 * 0 size.
1198 */
1199 private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
1200 SnapTarget snapTarget) {
1201 if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001202 return Math.max(mSplitLayout.getSnapAlgorithm().getFirstSplitTarget().position,
1203 mStartPosition);
Jorim Jaggie435e982015-12-30 13:54:32 +01001204 } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
1205 && dockSideBottomRight(dockSide)) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001206 return Math.min(mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position,
1207 mStartPosition);
Jorim Jaggie435e982015-12-30 13:54:32 +01001208 } else {
1209 return taskPosition;
1210 }
1211 }
1212
1213 /**
1214 * Applies a parallax to the task when dismissing.
1215 */
1216 private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
1217 int position, int taskPosition) {
1218 float fraction = Math.min(1, Math.max(0,
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001219 mSplitLayout.getSnapAlgorithm().calculateDismissingFraction(position)));
Jorim Jaggie435e982015-12-30 13:54:32 +01001220 SnapTarget dismissTarget = null;
1221 SnapTarget splitTarget = null;
Jorim Jaggi8dccd232016-03-25 18:10:14 -07001222 int start = 0;
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001223 if (position <= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position
Jorim Jaggie435e982015-12-30 13:54:32 +01001224 && dockSideTopLeft(dockSide)) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001225 dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissStartTarget();
1226 splitTarget = mSplitLayout.getSnapAlgorithm().getFirstSplitTarget();
Jorim Jaggi8dccd232016-03-25 18:10:14 -07001227 start = taskPosition;
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001228 } else if (position >= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position
Jorim Jaggie435e982015-12-30 13:54:32 +01001229 && dockSideBottomRight(dockSide)) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001230 dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissEndTarget();
1231 splitTarget = mSplitLayout.getSnapAlgorithm().getLastSplitTarget();
Jorim Jaggi8dccd232016-03-25 18:10:14 -07001232 start = splitTarget.position;
Jorim Jaggie435e982015-12-30 13:54:32 +01001233 }
1234 if (dismissTarget != null && fraction > 0f
1235 && isDismissing(splitTarget, position, dockSide)) {
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001236 fraction = calculateParallaxDismissingFraction(fraction, dockSide);
Jorim Jaggi8dccd232016-03-25 18:10:14 -07001237 int offsetPosition = (int) (start +
Jorim Jaggie435e982015-12-30 13:54:32 +01001238 fraction * (dismissTarget.position - splitTarget.position));
1239 int width = taskRect.width();
1240 int height = taskRect.height();
1241 switch (dockSide) {
1242 case WindowManager.DOCKED_LEFT:
1243 taskRect.left = offsetPosition - width;
1244 taskRect.right = offsetPosition;
1245 break;
1246 case WindowManager.DOCKED_RIGHT:
1247 taskRect.left = offsetPosition + mDividerSize;
1248 taskRect.right = offsetPosition + width + mDividerSize;
1249 break;
1250 case WindowManager.DOCKED_TOP:
1251 taskRect.top = offsetPosition - height;
1252 taskRect.bottom = offsetPosition;
1253 break;
1254 case WindowManager.DOCKED_BOTTOM:
1255 taskRect.top = offsetPosition + mDividerSize;
1256 taskRect.bottom = offsetPosition + height + mDividerSize;
1257 break;
1258 }
1259 }
1260 }
1261
1262 /**
1263 * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
1264 * slowing down parallax effect
1265 */
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001266 private static float calculateParallaxDismissingFraction(float fraction, int dockSide) {
1267 float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
1268
1269 // Less parallax at the top, just because.
1270 if (dockSide == WindowManager.DOCKED_TOP) {
1271 result /= 2f;
1272 }
1273 return result;
Jorim Jaggie435e982015-12-30 13:54:32 +01001274 }
1275
1276 private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
1277 if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
1278 return position < snapTarget.position;
1279 } else {
1280 return position > snapTarget.position;
1281 }
1282 }
1283
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001284 private boolean isDismissTargetPrimary(SnapTarget dismissTarget) {
1285 return (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
Jorim Jaggi8dccd232016-03-25 18:10:14 -07001286 || (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001287 && dockSideBottomRight(mDockSide));
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001288 }
1289
Jorim Jaggie435e982015-12-30 13:54:32 +01001290 /**
1291 * @return true if and only if {@code dockSide} is top or left
1292 */
1293 private static boolean dockSideTopLeft(int dockSide) {
1294 return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
1295 }
1296
1297 /**
1298 * @return true if and only if {@code dockSide} is bottom or right
1299 */
1300 private static boolean dockSideBottomRight(int dockSide) {
1301 return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
1302 }
1303
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001304 @Override
1305 public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
1306 inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
1307 inoutInfo.touchableRegion.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(),
1308 mHandle.getBottom());
1309 inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(),
1310 mBackground.getRight(), mBackground.getBottom(), Op.UNION);
1311 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001312
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001313 /**
1314 * Checks whether recents will grow when invoked. This happens in multi-window when recents is
1315 * very small. When invoking recents, we shrink the docked stack so recents has more space.
1316 *
1317 * @return the position of the divider when recents grows, or
1318 * {@link #INVALID_RECENTS_GROW_TARGET} if recents won't grow
1319 */
1320 public int growsRecents() {
1321 boolean result = mGrowRecents
Jorim Jaggiddb449e2017-05-12 16:32:58 +02001322 && mDockSide == WindowManager.DOCKED_TOP
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001323 && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position;
1324 if (result) {
1325 return getSnapAlgorithm().getMiddleTarget().position;
1326 } else {
1327 return INVALID_RECENTS_GROW_TARGET;
1328 }
1329 }
1330
Winson Chung67f5c8b2018-09-24 12:09:19 -07001331 void onRecentsActivityStarting() {
Jorim Jaggief496ea2017-05-13 23:16:44 +02001332 if (mGrowRecents && mDockSide == WindowManager.DOCKED_TOP
Qiushi.Han9170ca82016-10-10 13:31:48 +08001333 && getSnapAlgorithm().getMiddleTarget() != getSnapAlgorithm().getLastSplitTarget()
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001334 && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
Jorim Jaggia6c05d52016-05-27 00:31:21 -07001335 mState.growAfterRecentsDrawn = true;
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001336 startDragging(false /* animate */, false /* touching */);
1337 }
1338 }
1339
Winson Chung67f5c8b2018-09-24 12:09:19 -07001340 void onDockedFirstAnimationFrame() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001341 saveSnapTargetBeforeMinimized(mSplitLayout.getSnapAlgorithm().getMiddleTarget());
Winson Chung37b20242017-09-26 11:51:08 -07001342 }
1343
Winson Chung67f5c8b2018-09-24 12:09:19 -07001344 void onDockedTopTask() {
1345 mState.growAfterRecentsDrawn = false;
1346 mState.animateAfterRecentsDrawn = true;
1347 startDragging(false /* animate */, false /* touching */);
Jorim Jaggi899327f2016-02-25 20:44:18 -05001348 updateDockSide();
Jorim Jaggi899327f2016-02-25 20:44:18 -05001349 mEntranceAnimationRunning = true;
Jorim Jaggie525a352016-05-27 16:56:55 -07001350
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001351 resizeStackSurfaces(calculatePositionForInsetBounds(),
1352 mSplitLayout.getSnapAlgorithm().getMiddleTarget().position,
Evan Rosky36138542020-05-01 18:02:11 -07001353 mSplitLayout.getSnapAlgorithm().getMiddleTarget(),
1354 null /* transaction */);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001355 }
1356
Winson Chung67f5c8b2018-09-24 12:09:19 -07001357 void onRecentsDrawn() {
Matthew Ng30307122018-04-13 11:36:34 -07001358 updateDockSide();
1359 final int position = calculatePositionForInsetBounds();
Jorim Jaggia6c05d52016-05-27 00:31:21 -07001360 if (mState.animateAfterRecentsDrawn) {
1361 mState.animateAfterRecentsDrawn = false;
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001362
Jorim Jaggia6c05d52016-05-27 00:31:21 -07001363 mHandler.post(() -> {
Jorim Jaggic5887ea2016-05-13 18:21:48 -07001364 // Delay switching resizing mode because this might cause jank in recents animation
1365 // that's longer than this animation.
Matthew Ng30307122018-04-13 11:36:34 -07001366 stopDragging(position, getSnapAlgorithm().getMiddleTarget(),
Jorim Jaggic5887ea2016-05-13 18:21:48 -07001367 mLongPressEntraceAnimDuration, Interpolators.FAST_OUT_SLOW_IN,
1368 200 /* endDelay */);
1369 });
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001370 }
Jorim Jaggia6c05d52016-05-27 00:31:21 -07001371 if (mState.growAfterRecentsDrawn) {
1372 mState.growAfterRecentsDrawn = false;
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001373 updateDockSide();
Winson Chung67f5c8b2018-09-24 12:09:19 -07001374 if (mCallback != null) {
1375 mCallback.growRecents();
1376 }
Matthew Ng30307122018-04-13 11:36:34 -07001377 stopDragging(position, getSnapAlgorithm().getMiddleTarget(), 336,
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001378 Interpolators.FAST_OUT_SLOW_IN);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -08001379 }
1380 }
1381
Winson Chung67f5c8b2018-09-24 12:09:19 -07001382 void onUndockingTask() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001383 int dockSide = mSplitLayout.getPrimarySplitSide();
Evan Rosky89c285e2020-06-17 21:21:53 -07001384 if (inSplitMode()) {
Jorim Jaggiea4a19f2016-02-03 21:31:27 -08001385 startDragging(false /* animate */, false /* touching */);
1386 SnapTarget target = dockSideTopLeft(dockSide)
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001387 ? mSplitLayout.getSnapAlgorithm().getDismissEndTarget()
1388 : mSplitLayout.getSnapAlgorithm().getDismissStartTarget();
Jorim Jaggiea4a19f2016-02-03 21:31:27 -08001389
1390 // Don't start immediately - give a little bit time to settle the drag resize change.
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -07001391 mExitAnimationRunning = true;
1392 mExitStartPosition = getCurrentPosition();
1393 stopDragging(mExitStartPosition, target, 336 /* duration */, 100 /* startDelay */,
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001394 0 /* endDelay */, Interpolators.FAST_OUT_SLOW_IN);
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001395 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001396 }
Matthew Ng30307122018-04-13 11:36:34 -07001397
1398 private int calculatePositionForInsetBounds() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001399 mSplitLayout.mDisplayLayout.getStableBounds(mTmpRect);
Matthew Ng30307122018-04-13 11:36:34 -07001400 return DockedDividerUtils.calculatePositionForBounds(mTmpRect, mDockSide, mDividerSize);
1401 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001402}