blob: 6f554e698c58eada9e87fdba7e00d4442354ee6b [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) {
Sunny Goyal21482542020-05-05 16:34:17 -0700355 notifySplitScreenBoundsChanged();
Jorim Jaggi8eb8a322016-04-05 18:03:56 -0700356 }
357 }
358
Winson Chung67f5c8b2018-09-24 12:09:19 -0700359 public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState,
Evan Roskyc3a50902020-05-19 13:36:28 -0700360 DividerCallbacks callback, SplitScreenTaskOrganizer tiles, SplitDisplayLayout sdl,
Evan Rosky36138542020-05-01 18:02:11 -0700361 DividerImeController imeController, WindowManagerProxy wmProxy) {
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100362 mWindowManager = windowManager;
Jorim Jaggia6c05d52016-05-27 00:31:21 -0700363 mState = dividerState;
Winson Chung67f5c8b2018-09-24 12:09:19 -0700364 mCallback = callback;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000365 mTiles = tiles;
366 mSplitLayout = sdl;
Evan Roskyc3a50902020-05-19 13:36:28 -0700367 mImeController = imeController;
Evan Rosky36138542020-05-01 18:02:11 -0700368 mWindowManagerProxy = wmProxy;
Matthew Ng30307122018-04-13 11:36:34 -0700369
370 if (mState.mRatioPositionBeforeMinimized == 0) {
371 // Set the middle target as the initial state
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000372 mSnapTargetBeforeMinimized = mSplitLayout.getSnapAlgorithm().getMiddleTarget();
Matthew Ng30307122018-04-13 11:36:34 -0700373 } else {
374 repositionSnapTargetBeforeMinimized();
375 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100376 }
377
Matthew Ngc603a502018-04-18 17:14:22 -0700378 public Rect getNonMinimizedSplitScreenSecondaryBounds() {
Sunny Goyal21482542020-05-05 16:34:17 -0700379 mOtherTaskRect.set(mSplitLayout.mSecondary);
Matthew Ngc603a502018-04-18 17:14:22 -0700380 return mOtherTaskRect;
381 }
382
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000383 private boolean inSplitMode() {
384 return getVisibility() == VISIBLE;
385 }
386
387 /** Unlike setVisible, this directly hides the surface without changing view visibility. */
388 void setHidden(boolean hidden) {
Evan Roskye5fb45a2020-03-09 10:51:27 -0700389 if (mSurfaceHidden == hidden) {
390 return;
391 }
392 mSurfaceHidden = hidden;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000393 post(() -> {
394 final SurfaceControl sc = getWindowSurfaceControl();
395 if (sc == null) {
396 return;
397 }
398 Transaction t = mTiles.getTransaction();
399 if (hidden) {
400 t.hide(sc);
401 } else {
402 t.show(sc);
403 }
Evan Roskyc3a50902020-05-19 13:36:28 -0700404 mImeController.setDimsHidden(t, hidden);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000405 t.apply();
406 mTiles.releaseTransaction(t);
407 });
408 }
409
Evan Roskye5fb45a2020-03-09 10:51:27 -0700410 boolean isHidden() {
411 return mSurfaceHidden;
412 }
413
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800414 public boolean startDragging(boolean animate, boolean touching) {
Jorim Jaggi0c790412016-02-19 16:38:49 -0800415 cancelFlingAnimation();
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800416 if (touching) {
417 mHandle.setTouching(true, animate);
418 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000419 mDockSide = mSplitLayout.getPrimarySplitSide();
Matthew Ng30307122018-04-13 11:36:34 -0700420
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800421 mWindowManagerProxy.setResizing(true);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800422 if (touching) {
Jorim Jaggie161f082016-02-05 14:26:16 -0800423 mWindowManager.setSlippery(false);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800424 liftBackground();
Jorim Jaggidd98d412015-11-18 15:57:38 -0800425 }
Winson Chung67f5c8b2018-09-24 12:09:19 -0700426 if (mCallback != null) {
427 mCallback.onDraggingStart();
428 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000429 return inSplitMode();
Jorim Jaggidd98d412015-11-18 15:57:38 -0800430 }
431
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700432 public void stopDragging(int position, float velocity, boolean avoidDismissStart,
433 boolean logMetrics) {
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100434 mHandle.setTouching(false, true /* animate */);
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700435 fling(position, velocity, avoidDismissStart, logMetrics);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800436 mWindowManager.setSlippery(true);
437 releaseBackground();
438 }
439
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800440 public void stopDragging(int position, SnapTarget target, long duration,
441 Interpolator interpolator) {
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700442 stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator);
443 }
444
445 public void stopDragging(int position, SnapTarget target, long duration,
446 Interpolator interpolator, long endDelay) {
447 stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800448 }
449
450 public void stopDragging(int position, SnapTarget target, long duration, long startDelay,
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700451 long endDelay, Interpolator interpolator) {
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800452 mHandle.setTouching(false, true /* animate */);
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700453 flingTo(position, target, duration, startDelay, endDelay, interpolator);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800454 mWindowManager.setSlippery(true);
455 releaseBackground();
456 }
457
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800458 private void stopDragging() {
459 mHandle.setTouching(false, true /* animate */);
460 mWindowManager.setSlippery(true);
461 releaseBackground();
462 }
463
464 private void updateDockSide() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000465 mDockSide = mSplitLayout.getPrimarySplitSide();
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700466 mMinimizedShadow.setDockSide(mDockSide);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800467 }
468
Jorim Jaggidefd9222016-02-03 18:28:49 -0800469 public DividerSnapAlgorithm getSnapAlgorithm() {
Evan Rosky89c285e2020-06-17 21:21:53 -0700470 return mDockedStackMinimized ? mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000471 : mSplitLayout.getSnapAlgorithm();
Jorim Jaggidc249c42015-12-15 14:57:31 -0800472 }
473
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800474 public int getCurrentPosition() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000475 return isHorizontalDivision() ? mDividerPositionY : mDividerPositionX;
476 }
477
478 public boolean isMinimized() {
479 return mDockedStackMinimized;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800480 }
481
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100482 @Override
483 public boolean onTouch(View v, MotionEvent event) {
484 convertToScreenCoordinates(event);
485 final int action = event.getAction() & MotionEvent.ACTION_MASK;
486 switch (action) {
487 case MotionEvent.ACTION_DOWN:
488 mVelocityTracker = VelocityTracker.obtain();
489 mVelocityTracker.addMovement(event);
490 mStartX = (int) event.getX();
491 mStartY = (int) event.getY();
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800492 boolean result = startDragging(true /* animate */, true /* touching */);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -0800493 if (!result) {
494
495 // Weren't able to start dragging successfully, so cancel it again.
496 stopDragging();
497 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800498 mStartPosition = getCurrentPosition();
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100499 mMoving = false;
Jorim Jaggidd98d412015-11-18 15:57:38 -0800500 return result;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100501 case MotionEvent.ACTION_MOVE:
502 mVelocityTracker.addMovement(event);
503 int x = (int) event.getX();
504 int y = (int) event.getY();
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100505 boolean exceededTouchSlop =
506 isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
507 || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
508 if (!mMoving && exceededTouchSlop) {
509 mStartX = x;
510 mStartY = y;
511 mMoving = true;
512 }
513 if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
Matthew Nge15352e2016-12-20 15:36:29 -0800514 SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget(
Wale Ogunwaleef676d82016-03-18 12:51:55 -0700515 mStartPosition, 0 /* velocity */, false /* hardDismiss */);
Evan Rosky36138542020-05-01 18:02:11 -0700516 resizeStackSurfaces(calculatePosition(x, y), mStartPosition, snapTarget,
517 null /* transaction */);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100518 }
519 break;
520 case MotionEvent.ACTION_UP:
521 case MotionEvent.ACTION_CANCEL:
522 mVelocityTracker.addMovement(event);
523
524 x = (int) event.getRawX();
525 y = (int) event.getRawY();
526
527 mVelocityTracker.computeCurrentVelocity(1000);
Jorim Jaggidd98d412015-11-18 15:57:38 -0800528 int position = calculatePosition(x, y);
529 stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700530 : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */,
531 true /* log */);
Jorim Jaggid8fb3ac2016-01-05 15:37:42 +0100532 mMoving = false;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100533 break;
534 }
535 return true;
536 }
537
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700538 private void logResizeEvent(SnapTarget snapTarget) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000539 if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissStartTarget()) {
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700540 MetricsLogger.action(
541 mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideTopLeft(mDockSide)
542 ? LOG_VALUE_UNDOCK_MAX_OTHER
543 : LOG_VALUE_UNDOCK_MAX_DOCKED);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000544 } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissEndTarget()) {
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700545 MetricsLogger.action(
546 mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideBottomRight(mDockSide)
547 ? LOG_VALUE_UNDOCK_MAX_OTHER
548 : LOG_VALUE_UNDOCK_MAX_DOCKED);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000549 } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getMiddleTarget()) {
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700550 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
551 LOG_VALUE_RESIZE_50_50);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000552 } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getFirstSplitTarget()) {
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700553 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
554 dockSideTopLeft(mDockSide)
555 ? LOG_VALUE_RESIZE_DOCKED_SMALLER
556 : LOG_VALUE_RESIZE_DOCKED_LARGER);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000557 } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getLastSplitTarget()) {
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700558 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
559 dockSideTopLeft(mDockSide)
560 ? LOG_VALUE_RESIZE_DOCKED_LARGER
561 : LOG_VALUE_RESIZE_DOCKED_SMALLER);
562 }
563 }
564
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100565 private void convertToScreenCoordinates(MotionEvent event) {
566 event.setLocation(event.getRawX(), event.getRawY());
567 }
568
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700569 private void fling(int position, float velocity, boolean avoidDismissStart,
570 boolean logMetrics) {
Matthew Nge15352e2016-12-20 15:36:29 -0800571 DividerSnapAlgorithm currentSnapAlgorithm = getSnapAlgorithm();
572 SnapTarget snapTarget = currentSnapAlgorithm.calculateSnapTarget(position, velocity);
573 if (avoidDismissStart && snapTarget == currentSnapAlgorithm.getDismissStartTarget()) {
574 snapTarget = currentSnapAlgorithm.getFirstSplitTarget();
Jorim Jaggidf012d52016-01-15 22:40:13 -0800575 }
Jorim Jaggi29379ec2016-04-11 23:43:42 -0700576 if (logMetrics) {
577 logResizeEvent(snapTarget);
578 }
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700579 ValueAnimator anim = getFlingAnimator(position, snapTarget, 0 /* endDelay */);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800580 mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
581 anim.start();
582 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100583
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800584 private void flingTo(int position, SnapTarget target, long duration, long startDelay,
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700585 long endDelay, Interpolator interpolator) {
586 ValueAnimator anim = getFlingAnimator(position, target, endDelay);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800587 anim.setDuration(duration);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800588 anim.setStartDelay(startDelay);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800589 anim.setInterpolator(interpolator);
590 anim.start();
591 }
592
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700593 private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget,
594 final long endDelay) {
Matthew Nge15352e2016-12-20 15:36:29 -0800595 if (mCurrentAnimator != null) {
596 cancelFlingAnimation();
597 updateDockSide();
598 }
Evan Roskyfdc71c42020-03-13 18:23:08 -0700599 if (DEBUG) Slog.d(TAG, "Getting fling " + position + "->" + snapTarget.position);
Jorim Jaggi069dfe62016-05-04 17:24:47 -0700600 final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100601 ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
Tony Huang89d580c2020-03-26 14:10:26 +0800602 anim.addUpdateListener(animation -> resizeStackSurfaces((int) animation.getAnimatedValue(),
Jorim Jaggi069dfe62016-05-04 17:24:47 -0700603 taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f
604 ? TASK_POSITION_SAME
Jorim Jaggidbe6fdb2016-07-29 17:16:03 +0200605 : snapTarget.taskPosition,
Evan Rosky36138542020-05-01 18:02:11 -0700606 snapTarget, null /* transaction */));
Evan Roskyc0eec052020-03-06 18:54:55 -0800607 Consumer<Boolean> endAction = cancelled -> {
Evan Roskyfdc71c42020-03-13 18:23:08 -0700608 if (DEBUG) Slog.d(TAG, "End Fling " + cancelled + " min:" + mIsInMinimizeInteraction);
Evan Roskyc0eec052020-03-06 18:54:55 -0800609 final boolean wasMinimizeInteraction = mIsInMinimizeInteraction;
610 // Reset minimized divider position after unminimized state animation finishes.
611 if (!cancelled && !mDockedStackMinimized && mIsInMinimizeInteraction) {
612 mIsInMinimizeInteraction = false;
613 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000614 boolean dismissed = commitSnapFlags(snapTarget);
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700615 mWindowManagerProxy.setResizing(false);
Matthew Ngd411f6c2017-07-26 11:09:35 -0700616 updateDockSide();
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700617 mCurrentAnimator = null;
618 mEntranceAnimationRunning = false;
619 mExitAnimationRunning = false;
Evan Roskyc0eec052020-03-06 18:54:55 -0800620 if (!dismissed && !wasMinimizeInteraction) {
621 WindowManagerProxy.applyResizeSplits(snapTarget.position, mSplitLayout);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000622 }
Winson Chung67f5c8b2018-09-24 12:09:19 -0700623 if (mCallback != null) {
624 mCallback.onDraggingEnd();
625 }
Matthew Ng597bcbb2017-09-07 17:17:38 -0700626
627 // Record last snap target the divider moved to
Evan Rosky89c285e2020-06-17 21:21:53 -0700628 if (!mIsInMinimizeInteraction) {
chaviwee947f22018-03-27 16:49:27 -0700629 // The last snapTarget position can be negative when the last divider position was
630 // offscreen. In that case, save the middle (default) SnapTarget so calculating next
631 // position isn't negative.
632 final SnapTarget saveTarget;
633 if (snapTarget.position < 0) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000634 saveTarget = mSplitLayout.getSnapAlgorithm().getMiddleTarget();
chaviwee947f22018-03-27 16:49:27 -0700635 } else {
636 saveTarget = snapTarget;
637 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000638 final DividerSnapAlgorithm snapAlgo = mSplitLayout.getSnapAlgorithm();
639 if (saveTarget.position != snapAlgo.getDismissEndTarget().position
640 && saveTarget.position != snapAlgo.getDismissStartTarget().position) {
Matthew Ng30307122018-04-13 11:36:34 -0700641 saveSnapTargetBeforeMinimized(saveTarget);
642 }
Matthew Ng597bcbb2017-09-07 17:17:38 -0700643 }
Sunny Goyal21482542020-05-05 16:34:17 -0700644 notifySplitScreenBoundsChanged();
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700645 };
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100646 anim.addListener(new AnimatorListenerAdapter() {
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700647
648 private boolean mCancelled;
649
650 @Override
651 public void onAnimationCancel(Animator animation) {
652 mCancelled = true;
653 }
654
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100655 @Override
656 public void onAnimationEnd(Animator animation) {
Jorim Jaggidbe6fdb2016-07-29 17:16:03 +0200657 long delay = 0;
658 if (endDelay != 0) {
659 delay = endDelay;
660 } else if (mCancelled) {
661 delay = 0;
Jorim Jaggidbe6fdb2016-07-29 17:16:03 +0200662 }
663 if (delay == 0) {
Evan Roskyc0eec052020-03-06 18:54:55 -0800664 endAction.accept(mCancelled);
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700665 } else {
Evan Roskyc0eec052020-03-06 18:54:55 -0800666 final Boolean cancelled = mCancelled;
Evan Roskyfdc71c42020-03-13 18:23:08 -0700667 if (DEBUG) Slog.d(TAG, "Posting endFling " + cancelled + " d:" + delay + "ms");
Evan Roskyc0eec052020-03-06 18:54:55 -0800668 mHandler.postDelayed(() -> endAction.accept(cancelled), delay);
Jorim Jaggi545c5c22016-04-12 18:59:45 -0700669 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100670 }
671 });
Tony Huang89d580c2020-03-26 14:10:26 +0800672 anim.setAnimationHandler(mAnimationHandler);
Jorim Jaggi0c790412016-02-19 16:38:49 -0800673 mCurrentAnimator = anim;
Jorim Jaggi11cc01d2016-01-22 19:39:23 -0800674 return anim;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100675 }
676
Sunny Goyal21482542020-05-05 16:34:17 -0700677 private void notifySplitScreenBoundsChanged() {
678 mOtherTaskRect.set(mSplitLayout.mSecondary);
679
Evan Rosky27634c42020-06-22 10:46:05 -0700680 mTmpRect.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(), mHandle.getBottom());
681 if (isHorizontalDivision()) {
682 mTmpRect.offsetTo(0, mDividerPositionY);
683 } else {
684 mTmpRect.offsetTo(mDividerPositionX, 0);
685 }
686 mWindowManagerProxy.setTouchRegion(mTmpRect);
687
Sunny Goyal21482542020-05-05 16:34:17 -0700688 mTmpRect.set(mSplitLayout.mDisplayLayout.stableInsets());
689 switch (mSplitLayout.getPrimarySplitSide()) {
690 case WindowManager.DOCKED_LEFT:
691 mTmpRect.left = 0;
692 break;
693 case WindowManager.DOCKED_RIGHT:
694 mTmpRect.right = 0;
695 break;
696 case WindowManager.DOCKED_TOP:
697 mTmpRect.top = 0;
698 break;
699 }
700 Dependency.get(OverviewProxyService.class)
701 .notifySplitScreenBoundsChanged(mOtherTaskRect, mTmpRect);
702 }
703
Jorim Jaggi0c790412016-02-19 16:38:49 -0800704 private void cancelFlingAnimation() {
705 if (mCurrentAnimator != null) {
706 mCurrentAnimator.cancel();
707 }
708 }
709
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000710 private boolean commitSnapFlags(SnapTarget target) {
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100711 if (target.flag == SnapTarget.FLAG_NONE) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000712 return false;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100713 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000714 final boolean dismissOrMaximize;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100715 if (target.flag == SnapTarget.FLAG_DISMISS_START) {
716 dismissOrMaximize = mDockSide == WindowManager.DOCKED_LEFT
717 || mDockSide == WindowManager.DOCKED_TOP;
718 } else {
719 dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT
720 || mDockSide == WindowManager.DOCKED_BOTTOM;
721 }
Evan Rosky36138542020-05-01 18:02:11 -0700722 mWindowManagerProxy.dismissOrMaximizeDocked(mTiles, mSplitLayout, dismissOrMaximize);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000723 Transaction t = mTiles.getTransaction();
724 setResizeDimLayer(t, true /* primary */, 0f);
725 setResizeDimLayer(t, false /* primary */, 0f);
726 t.apply();
727 mTiles.releaseTransaction(t);
728 return true;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100729 }
730
731 private void liftBackground() {
Jorim Jaggie161f082016-02-05 14:26:16 -0800732 if (mBackgroundLifted) {
733 return;
734 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100735 if (isHorizontalDivision()) {
Jorim Jaggi79b39f02015-12-17 20:04:31 -0800736 mBackground.animate().scaleY(1.4f);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100737 } else {
Jorim Jaggi79b39f02015-12-17 20:04:31 -0800738 mBackground.animate().scaleX(1.4f);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100739 }
740 mBackground.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800741 .setInterpolator(Interpolators.TOUCH_RESPONSE)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100742 .setDuration(TOUCH_ANIMATION_DURATION)
743 .translationZ(mTouchElevation)
744 .start();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100745
746 // Lift handle as well so it doesn't get behind the background, even though it doesn't
747 // cast shadow.
748 mHandle.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800749 .setInterpolator(Interpolators.TOUCH_RESPONSE)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100750 .setDuration(TOUCH_ANIMATION_DURATION)
751 .translationZ(mTouchElevation)
752 .start();
Jorim Jaggie161f082016-02-05 14:26:16 -0800753 mBackgroundLifted = true;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100754 }
755
756 private void releaseBackground() {
Jorim Jaggie161f082016-02-05 14:26:16 -0800757 if (!mBackgroundLifted) {
758 return;
759 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100760 mBackground.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800761 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100762 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100763 .translationZ(0)
764 .scaleX(1f)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100765 .scaleY(1f)
766 .start();
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100767 mHandle.animate()
Jorim Jaggiea4a19f2016-02-03 21:31:27 -0800768 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
Jorim Jaggi514b2cf2016-01-04 13:06:34 +0100769 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
770 .translationZ(0)
771 .start();
Jorim Jaggie161f082016-02-05 14:26:16 -0800772 mBackgroundLifted = false;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100773 }
774
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000775 private void initializeSurfaceState() {
776 int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
777 // Recalculate the split-layout's internal tile bounds
778 mSplitLayout.resizeSplits(midPos);
779 Transaction t = mTiles.getTransaction();
780 if (mDockedStackMinimized) {
Evan Rosky89c285e2020-06-17 21:21:53 -0700781 int position = mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
782 .getMiddleTarget().position;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000783 calculateBoundsForPosition(position, mDockSide, mDockedRect);
784 calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
785 mOtherRect);
786 mDividerPositionX = mDividerPositionY = position;
787 resizeSplitSurfaces(t, mDockedRect, mSplitLayout.mPrimary,
788 mOtherRect, mSplitLayout.mSecondary);
789 } else {
790 resizeSplitSurfaces(t, mSplitLayout.mPrimary, null,
791 mSplitLayout.mSecondary, null);
792 }
793 setResizeDimLayer(t, true /* primary */, 0.f /* alpha */);
794 setResizeDimLayer(t, false /* secondary */, 0.f /* alpha */);
795 t.apply();
796 mTiles.releaseTransaction(t);
Evan Rosky12837282020-04-27 19:12:25 -0700797
798 // Get the actually-visible bar dimensions (relative to full window). This is a thin
799 // bar going through the center.
800 final Rect dividerBar = isHorizontalDivision()
801 ? new Rect(0, mDividerInsets, mSplitLayout.mDisplayLayout.width(),
802 mDividerInsets + mDividerSize)
803 : new Rect(mDividerInsets, 0, mDividerInsets + mDividerSize,
804 mSplitLayout.mDisplayLayout.height());
805 final Region touchRegion = new Region(dividerBar);
806 // Add in the "draggable" portion. While not visible, this is an expanded area that the
807 // user can interact with.
808 touchRegion.union(new Rect(mHandle.getLeft(), mHandle.getTop(),
809 mHandle.getRight(), mHandle.getBottom()));
810 mWindowManager.setTouchRegion(touchRegion);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000811 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800812
Evan Rosky36138542020-05-01 18:02:11 -0700813 void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable,
814 Transaction t) {
Matthew Nge15352e2016-12-20 15:36:29 -0800815 mHomeStackResizable = isHomeStackResizable;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800816 updateDockSide();
Jorim Jaggie661f402016-03-25 19:11:35 -0700817 if (!minimized) {
818 resetBackground();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800819 }
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700820 mMinimizedShadow.setAlpha(minimized ? 1f : 0f);
Evan Rosky89c285e2020-06-17 21:21:53 -0700821 if (mDockedStackMinimized != minimized) {
Matthew Ngaa2b6202017-02-10 14:48:21 -0800822 mDockedStackMinimized = minimized;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000823 if (mSplitLayout.mDisplayLayout.rotation() != mDefaultDisplay.getRotation()) {
Matthew Ng4c76a1c2018-05-14 12:45:08 -0700824 // Splitscreen to minimize is about to starts after rotating landscape to seascape,
Sunny Goyal21482542020-05-05 16:34:17 -0700825 // update display info and snap algorithm targets
Matthew Ng4c76a1c2018-05-14 12:45:08 -0700826 repositionSnapTargetBeforeMinimized();
Matthew Ng4c76a1c2018-05-14 12:45:08 -0700827 }
Matthew Nga51dcaa2018-05-07 15:36:06 -0700828 if (mIsInMinimizeInteraction != minimized || mCurrentAnimator != null) {
829 cancelFlingAnimation();
Matthew Ng04f34302017-04-27 16:28:49 -0700830 if (minimized) {
Matthew Ng30307122018-04-13 11:36:34 -0700831 // Relayout to recalculate the divider shadow when minimizing
832 requestLayout();
Matthew Ng04f34302017-04-27 16:28:49 -0700833 mIsInMinimizeInteraction = true;
Evan Rosky89c285e2020-06-17 21:21:53 -0700834 resizeStackSurfaces(mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
835 .getMiddleTarget(), t);
Matthew Ng04f34302017-04-27 16:28:49 -0700836 } else {
Evan Rosky36138542020-05-01 18:02:11 -0700837 resizeStackSurfaces(mSnapTargetBeforeMinimized, t);
Matthew Ng04f34302017-04-27 16:28:49 -0700838 mIsInMinimizeInteraction = false;
839 }
Matthew Nge15352e2016-12-20 15:36:29 -0800840 }
Matthew Nge15352e2016-12-20 15:36:29 -0800841 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800842 }
843
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000844 void enterSplitMode(boolean isHomeStackResizable) {
845 post(() -> {
846 final SurfaceControl sc = getWindowSurfaceControl();
847 if (sc == null) {
848 return;
849 }
850 Transaction t = mTiles.getTransaction();
851 t.show(sc).apply();
852 mTiles.releaseTransaction(t);
853 });
Evan Rosky89c285e2020-06-17 21:21:53 -0700854
855 SnapTarget miniMid =
856 mSplitLayout.getMinimizedSnapAlgorithm(isHomeStackResizable).getMiddleTarget();
857 if (mDockedStackMinimized) {
858 mDividerPositionY = mDividerPositionX = miniMid.position;
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000859 }
860 }
861
862 /**
863 * Tries to grab a surface control from ViewRootImpl. If this isn't available for some reason
864 * (ie. the window isn't ready yet), it will get the surfacecontrol that the WindowlessWM has
865 * assigned to it.
866 */
867 private SurfaceControl getWindowSurfaceControl() {
Evan Rosky36138542020-05-01 18:02:11 -0700868 final ViewRootImpl root = getViewRootImpl();
869 if (root == null) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000870 return null;
871 }
Evan Rosky36138542020-05-01 18:02:11 -0700872 SurfaceControl out = root.getSurfaceControl();
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000873 if (out != null && out.isValid()) {
874 return out;
875 }
876 return mWindowManager.mSystemWindows.getViewSurface(this);
877 }
878
879 void exitSplitMode() {
880 // Reset tile bounds
Evan Rosky36138542020-05-01 18:02:11 -0700881 final SurfaceControl sc = getWindowSurfaceControl();
882 if (sc == null) {
883 return;
884 }
885 Transaction t = mTiles.getTransaction();
886 t.hide(sc).apply();
887 mTiles.releaseTransaction(t);
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000888 int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
889 WindowManagerProxy.applyResizeSplits(midPos, mSplitLayout);
890 }
891
Matthew Nge15352e2016-12-20 15:36:29 -0800892 public void setMinimizedDockStack(boolean minimized, long animDuration,
893 boolean isHomeStackResizable) {
Evan Roskyfdc71c42020-03-13 18:23:08 -0700894 if (DEBUG) Slog.d(TAG, "setMinDock: " + mDockedStackMinimized + "->" + minimized);
Matthew Nge15352e2016-12-20 15:36:29 -0800895 mHomeStackResizable = isHomeStackResizable;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800896 updateDockSide();
Evan Rosky89c285e2020-06-17 21:21:53 -0700897 if (mDockedStackMinimized != minimized) {
Matthew Nge15352e2016-12-20 15:36:29 -0800898 mIsInMinimizeInteraction = true;
Matthew Nge15352e2016-12-20 15:36:29 -0800899 mDockedStackMinimized = minimized;
Matthew Ngf9989e22017-04-24 17:14:14 -0700900 stopDragging(minimized
Matthew Ng597bcbb2017-09-07 17:17:38 -0700901 ? mSnapTargetBeforeMinimized.position
Matthew Ngf9989e22017-04-24 17:14:14 -0700902 : getCurrentPosition(),
903 minimized
Evan Rosky89c285e2020-06-17 21:21:53 -0700904 ? mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable)
905 .getMiddleTarget()
Matthew Ng597bcbb2017-09-07 17:17:38 -0700906 : mSnapTargetBeforeMinimized,
Matthew Nge15352e2016-12-20 15:36:29 -0800907 animDuration, Interpolators.FAST_OUT_SLOW_IN, 0);
Matthew Ngf9989e22017-04-24 17:14:14 -0700908 setAdjustedForIme(false, animDuration);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800909 }
Jorim Jaggie661f402016-03-25 19:11:35 -0700910 if (!minimized) {
911 mBackground.animate().withEndAction(mResetBackgroundRunnable);
912 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800913 mBackground.animate()
914 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
915 .setDuration(animDuration)
916 .start();
917 }
918
Evan Roskyc0eec052020-03-06 18:54:55 -0800919 // Needed to end any currently playing animations when they might compete with other anims
920 // (specifically, IME adjust animation immediately after leaving minimized). Someday maybe
921 // these can be unified, but not today.
922 void finishAnimations() {
923 if (mCurrentAnimator != null) {
924 mCurrentAnimator.end();
925 }
926 }
927
Jorim Jaggi698e7632016-04-13 21:02:22 -0700928 public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
Evan Rosky95729202020-02-21 10:16:08 -0800929 if (mAdjustedForIme == adjustedForIme) {
930 return;
931 }
Jorim Jaggi698e7632016-04-13 21:02:22 -0700932 updateDockSide();
933 mHandle.animate()
Jorim Jaggi7b458392016-04-20 16:42:06 -0700934 .setInterpolator(IME_ADJUST_INTERPOLATOR)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700935 .setDuration(animDuration)
936 .alpha(adjustedForIme ? 0f : 1f)
937 .start();
938 if (mDockSide == WindowManager.DOCKED_TOP) {
939 mBackground.setPivotY(0);
940 mBackground.animate()
Jorim Jaggi7b458392016-04-20 16:42:06 -0700941 .scaleY(adjustedForIme ? ADJUSTED_FOR_IME_SCALE : 1f);
Jorim Jaggi698e7632016-04-13 21:02:22 -0700942 }
943 if (!adjustedForIme) {
944 mBackground.animate().withEndAction(mResetBackgroundRunnable);
945 }
946 mBackground.animate()
Jorim Jaggi7b458392016-04-20 16:42:06 -0700947 .setInterpolator(IME_ADJUST_INTERPOLATOR)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700948 .setDuration(animDuration)
949 .start();
950 mAdjustedForIme = adjustedForIme;
951 }
952
Matthew Ng597bcbb2017-09-07 17:17:38 -0700953 private void saveSnapTargetBeforeMinimized(SnapTarget target) {
954 mSnapTargetBeforeMinimized = target;
955 mState.mRatioPositionBeforeMinimized = (float) target.position /
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000956 (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
957 : mSplitLayout.mDisplayLayout.width());
Matthew Ngca3168b2017-05-24 16:40:31 -0700958 }
959
Jorim Jaggie661f402016-03-25 19:11:35 -0700960 private void resetBackground() {
961 mBackground.setPivotX(mBackground.getWidth() / 2);
962 mBackground.setPivotY(mBackground.getHeight() / 2);
963 mBackground.setScaleX(1f);
964 mBackground.setScaleY(1f);
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700965 mMinimizedShadow.setAlpha(0f);
Jorim Jaggie661f402016-03-25 19:11:35 -0700966 }
967
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100968 @Override
969 protected void onConfigurationChanged(Configuration newConfig) {
970 super.onConfigurationChanged(newConfig);
Matthew Ng62c78462018-04-09 14:43:21 -0700971 }
972
973 private void repositionSnapTargetBeforeMinimized() {
974 int position = (int) (mState.mRatioPositionBeforeMinimized *
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000975 (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
976 : mSplitLayout.mDisplayLayout.width()));
Matthew Ng62c78462018-04-09 14:43:21 -0700977
978 // Set the snap target before minimized but do not save until divider is attached and not
979 // minimized because it does not know its minimized state yet.
Evan Roskyaf9f27c2020-02-18 18:58:35 +0000980 mSnapTargetBeforeMinimized =
981 mSplitLayout.getSnapAlgorithm().calculateNonDismissingSnapTarget(position);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100982 }
983
984 private int calculatePosition(int touchX, int touchY) {
985 return isHorizontalDivision() ? calculateYPosition(touchY) : calculateXPosition(touchX);
986 }
987
Jorim Jaggidd98d412015-11-18 15:57:38 -0800988 public boolean isHorizontalDivision() {
989 return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100990 }
991
992 private int calculateXPosition(int touchX) {
993 return mStartPosition + touchX - mStartX;
994 }
995
996 private int calculateYPosition(int touchY) {
997 return mStartPosition + touchY - mStartY;
998 }
999
Jorim Jaggidc249c42015-12-15 14:57:31 -08001000 private void alignTopLeft(Rect containingRect, Rect rect) {
1001 int width = rect.width();
1002 int height = rect.height();
1003 rect.set(containingRect.left, containingRect.top,
1004 containingRect.left + width, containingRect.top + height);
1005 }
1006
1007 private void alignBottomRight(Rect containingRect, Rect rect) {
1008 int width = rect.width();
1009 int height = rect.height();
1010 rect.set(containingRect.right - width, containingRect.bottom - height,
1011 containingRect.right, containingRect.bottom);
1012 }
1013
Jorim Jaggi737af722015-12-31 10:42:27 +01001014 public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001015 DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect,
1016 mSplitLayout.mDisplayLayout.width(), mSplitLayout.mDisplayLayout.height(),
1017 mDividerSize);
Jorim Jaggi737af722015-12-31 10:42:27 +01001018 }
1019
Evan Rosky36138542020-05-01 18:02:11 -07001020 private void resizeStackSurfaces(SnapTarget taskSnapTarget, Transaction t) {
1021 resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget, t);
Matthew Ng597bcbb2017-09-07 17:17:38 -07001022 }
1023
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001024 void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect otherRect) {
1025 resizeSplitSurfaces(t, dockedRect, null, otherRect, null);
1026 }
1027
1028 private void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect dockedTaskRect,
1029 Rect otherRect, Rect otherTaskRect) {
1030 dockedTaskRect = dockedTaskRect == null ? dockedRect : dockedTaskRect;
1031 otherTaskRect = otherTaskRect == null ? otherRect : otherTaskRect;
1032
Tony Huang0bbb7ef2020-03-24 18:24:54 +08001033 mDividerPositionX = mSplitLayout.getPrimarySplitSide() == DOCKED_RIGHT
1034 ? otherRect.right : dockedRect.right;
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001035 mDividerPositionY = dockedRect.bottom;
1036
Evan Roskyfdc71c42020-03-13 18:23:08 -07001037 if (DEBUG) {
1038 Slog.d(TAG, "Resizing split surfaces: " + dockedRect + " " + dockedTaskRect
1039 + " " + otherRect + " " + otherTaskRect);
1040 }
1041
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001042 t.setPosition(mTiles.mPrimarySurface, dockedTaskRect.left, dockedTaskRect.top);
1043 Rect crop = new Rect(dockedRect);
1044 crop.offsetTo(-Math.min(dockedTaskRect.left - dockedRect.left, 0),
1045 -Math.min(dockedTaskRect.top - dockedRect.top, 0));
1046 t.setWindowCrop(mTiles.mPrimarySurface, crop);
1047 t.setPosition(mTiles.mSecondarySurface, otherTaskRect.left, otherTaskRect.top);
1048 crop.set(otherRect);
1049 crop.offsetTo(-(otherTaskRect.left - otherRect.left),
1050 -(otherTaskRect.top - otherRect.top));
1051 t.setWindowCrop(mTiles.mSecondarySurface, crop);
1052 final SurfaceControl dividerCtrl = getWindowSurfaceControl();
1053 if (dividerCtrl != null) {
1054 if (isHorizontalDivision()) {
1055 t.setPosition(dividerCtrl, 0, mDividerPositionY - mDividerInsets);
1056 } else {
1057 t.setPosition(dividerCtrl, mDividerPositionX - mDividerInsets, 0);
1058 }
1059 }
Evan Rosky0f4db1b2020-04-28 16:20:00 -07001060 if (getViewRootImpl() != null) {
1061 mHandler.removeCallbacks(mUpdateEmbeddedMatrix);
1062 mHandler.post(mUpdateEmbeddedMatrix);
1063 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001064 }
1065
1066 void setResizeDimLayer(Transaction t, boolean primary, float alpha) {
1067 SurfaceControl dim = primary ? mTiles.mPrimaryDim : mTiles.mSecondaryDim;
Evan Roskye5fb45a2020-03-09 10:51:27 -07001068 if (alpha <= 0.001f) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001069 t.hide(dim);
1070 } else {
1071 t.setAlpha(dim, alpha);
1072 t.show(dim);
1073 }
1074 }
1075
Evan Rosky36138542020-05-01 18:02:11 -07001076 void resizeStackSurfaces(int position, int taskPosition, SnapTarget taskSnapTarget,
1077 Transaction transaction) {
Wale Ogunwale15ba1512017-06-06 08:31:17 -07001078 if (mRemoved) {
1079 // This divider view has been removed so shouldn't have any additional influence.
1080 return;
1081 }
Jorim Jaggidc249c42015-12-15 14:57:31 -08001082 calculateBoundsForPosition(position, mDockSide, mDockedRect);
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001083 calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
1084 mOtherRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -08001085
Jorim Jaggie370e152016-04-15 14:13:33 -07001086 if (mDockedRect.equals(mLastResizeRect) && !mEntranceAnimationRunning) {
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001087 return;
1088 }
Jorim Jaggic97ba492015-11-06 22:00:18 +01001089
1090 // Make sure shadows are updated
Jorim Jaggie161f082016-02-05 14:26:16 -08001091 if (mBackground.getZ() > 0f) {
1092 mBackground.invalidate();
1093 }
Jorim Jaggic97ba492015-11-06 22:00:18 +01001094
Evan Rosky36138542020-05-01 18:02:11 -07001095 final boolean ownTransaction = transaction == null;
1096 final Transaction t = ownTransaction ? mTiles.getTransaction() : transaction;
Jorim Jaggidc249c42015-12-15 14:57:31 -08001097 mLastResizeRect.set(mDockedRect);
Evan Rosky89c285e2020-06-17 21:21:53 -07001098 if (mIsInMinimizeInteraction) {
Matthew Ng597bcbb2017-09-07 17:17:38 -07001099 calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
1100 mDockedTaskRect);
Matthew Ng30307122018-04-13 11:36:34 -07001101 calculateBoundsForPosition(mSnapTargetBeforeMinimized.position,
1102 DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
Matthew Ng62c78462018-04-09 14:43:21 -07001103
1104 // Move a right-docked-app to line up with the divider while dragging it
1105 if (mDockSide == DOCKED_RIGHT) {
Sunny Goyal21482542020-05-05 16:34:17 -07001106 mDockedTaskRect.offset(Math.max(position, -mDividerSize)
Matthew Ng62c78462018-04-09 14:43:21 -07001107 - mDockedTaskRect.left + mDividerSize, 0);
1108 }
Evan Rosky89c285e2020-06-17 21:21:53 -07001109 resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
Evan Rosky36138542020-05-01 18:02:11 -07001110 if (ownTransaction) {
1111 t.apply();
1112 mTiles.releaseTransaction(t);
1113 }
Matthew Nge15352e2016-12-20 15:36:29 -08001114 return;
1115 }
1116
Jorim Jaggi899327f2016-02-25 20:44:18 -05001117 if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) {
Matthew Ng30307122018-04-13 11:36:34 -07001118 calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
Matthew Ng62c78462018-04-09 14:43:21 -07001119
1120 // Move a docked app if from the right in position with the divider up to insets
1121 if (mDockSide == DOCKED_RIGHT) {
Sunny Goyal21482542020-05-05 16:34:17 -07001122 mDockedTaskRect.offset(Math.max(position, -mDividerSize)
Matthew Ng30307122018-04-13 11:36:34 -07001123 - mDockedTaskRect.left + mDividerSize, 0);
Matthew Ng62c78462018-04-09 14:43:21 -07001124 }
Jorim Jaggi899327f2016-02-25 20:44:18 -05001125 calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
1126 mOtherTaskRect);
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001127 resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -07001128 } else if (mExitAnimationRunning && taskPosition != TASK_POSITION_SAME) {
Matthew Ng30307122018-04-13 11:36:34 -07001129 calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
1130 mDockedInsetRect.set(mDockedTaskRect);
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -07001131 calculateBoundsForPosition(mExitStartPosition,
1132 DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001133 mOtherInsetRect.set(mOtherTaskRect);
1134 applyExitAnimationParallax(mOtherTaskRect, position);
Matthew Ng30307122018-04-13 11:36:34 -07001135
1136 // Move a right-docked-app to line up with the divider while dragging it
1137 if (mDockSide == DOCKED_RIGHT) {
Sunny Goyal21482542020-05-05 16:34:17 -07001138 mDockedTaskRect.offset(position + mDividerSize, 0);
Matthew Ng30307122018-04-13 11:36:34 -07001139 }
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001140 resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
Jorim Jaggi899327f2016-02-25 20:44:18 -05001141 } else if (taskPosition != TASK_POSITION_SAME) {
Winson3e874742016-01-07 10:08:17 -08001142 calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
1143 mOtherRect);
1144 int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide);
Jorim Jaggie435e982015-12-30 13:54:32 +01001145 int taskPositionDocked =
1146 restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
1147 int taskPositionOther =
1148 restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
1149 calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
1150 calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001151 mTmpRect.set(0, 0, mSplitLayout.mDisplayLayout.width(),
1152 mSplitLayout.mDisplayLayout.height());
Jorim Jaggidc249c42015-12-15 14:57:31 -08001153 alignTopLeft(mDockedRect, mDockedTaskRect);
1154 alignTopLeft(mOtherRect, mOtherTaskRect);
1155 mDockedInsetRect.set(mDockedTaskRect);
1156 mOtherInsetRect.set(mOtherTaskRect);
Jorim Jaggie435e982015-12-30 13:54:32 +01001157 if (dockSideTopLeft(mDockSide)) {
Matthew Ng30307122018-04-13 11:36:34 -07001158 alignTopLeft(mTmpRect, mDockedInsetRect);
1159 alignBottomRight(mTmpRect, mOtherInsetRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -08001160 } else {
Matthew Ng30307122018-04-13 11:36:34 -07001161 alignBottomRight(mTmpRect, mDockedInsetRect);
1162 alignTopLeft(mTmpRect, mOtherInsetRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -08001163 }
Jorim Jaggie435e982015-12-30 13:54:32 +01001164 applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
1165 taskPositionDocked);
1166 applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
1167 taskPositionOther);
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001168 resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect);
Jorim Jaggidc249c42015-12-15 14:57:31 -08001169 } else {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001170 resizeSplitSurfaces(t, mDockedRect, null, mOtherRect, null);
Jorim Jaggidc249c42015-12-15 14:57:31 -08001171 }
Matthew Nge15352e2016-12-20 15:36:29 -08001172 SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position);
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001173 float dimFraction = getDimFraction(position, closestDismissTarget);
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001174 setResizeDimLayer(t, isDismissTargetPrimary(closestDismissTarget), dimFraction);
Evan Rosky36138542020-05-01 18:02:11 -07001175 if (ownTransaction) {
1176 t.apply();
1177 mTiles.releaseTransaction(t);
1178 }
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001179 }
1180
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001181 private void applyExitAnimationParallax(Rect taskRect, int position) {
1182 if (mDockSide == WindowManager.DOCKED_TOP) {
1183 taskRect.offset(0, (int) ((position - mExitStartPosition) * 0.25f));
1184 } else if (mDockSide == WindowManager.DOCKED_LEFT) {
1185 taskRect.offset((int) ((position - mExitStartPosition) * 0.25f), 0);
1186 } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
1187 taskRect.offset((int) ((mExitStartPosition - position) * 0.25f), 0);
1188 }
1189 }
1190
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001191 private float getDimFraction(int position, SnapTarget dismissTarget) {
Jorim Jaggi899327f2016-02-25 20:44:18 -05001192 if (mEntranceAnimationRunning) {
1193 return 0f;
1194 }
Matthew Nge15352e2016-12-20 15:36:29 -08001195 float fraction = getSnapAlgorithm().calculateDismissingFraction(position);
Jorim Jaggi8f8155b2016-01-25 19:45:42 -08001196 fraction = Math.max(0, Math.min(fraction, 1f));
1197 fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001198 return fraction;
1199 }
1200
1201 /**
Jorim Jaggie435e982015-12-30 13:54:32 +01001202 * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
1203 * 0 size.
1204 */
1205 private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
1206 SnapTarget snapTarget) {
1207 if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001208 return Math.max(mSplitLayout.getSnapAlgorithm().getFirstSplitTarget().position,
1209 mStartPosition);
Jorim Jaggie435e982015-12-30 13:54:32 +01001210 } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
1211 && dockSideBottomRight(dockSide)) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001212 return Math.min(mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position,
1213 mStartPosition);
Jorim Jaggie435e982015-12-30 13:54:32 +01001214 } else {
1215 return taskPosition;
1216 }
1217 }
1218
1219 /**
1220 * Applies a parallax to the task when dismissing.
1221 */
1222 private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
1223 int position, int taskPosition) {
1224 float fraction = Math.min(1, Math.max(0,
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001225 mSplitLayout.getSnapAlgorithm().calculateDismissingFraction(position)));
Jorim Jaggie435e982015-12-30 13:54:32 +01001226 SnapTarget dismissTarget = null;
1227 SnapTarget splitTarget = null;
Jorim Jaggi8dccd232016-03-25 18:10:14 -07001228 int start = 0;
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001229 if (position <= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position
Jorim Jaggie435e982015-12-30 13:54:32 +01001230 && dockSideTopLeft(dockSide)) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001231 dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissStartTarget();
1232 splitTarget = mSplitLayout.getSnapAlgorithm().getFirstSplitTarget();
Jorim Jaggi8dccd232016-03-25 18:10:14 -07001233 start = taskPosition;
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001234 } else if (position >= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position
Jorim Jaggie435e982015-12-30 13:54:32 +01001235 && dockSideBottomRight(dockSide)) {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001236 dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissEndTarget();
1237 splitTarget = mSplitLayout.getSnapAlgorithm().getLastSplitTarget();
Jorim Jaggi8dccd232016-03-25 18:10:14 -07001238 start = splitTarget.position;
Jorim Jaggie435e982015-12-30 13:54:32 +01001239 }
1240 if (dismissTarget != null && fraction > 0f
1241 && isDismissing(splitTarget, position, dockSide)) {
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001242 fraction = calculateParallaxDismissingFraction(fraction, dockSide);
Jorim Jaggi8dccd232016-03-25 18:10:14 -07001243 int offsetPosition = (int) (start +
Jorim Jaggie435e982015-12-30 13:54:32 +01001244 fraction * (dismissTarget.position - splitTarget.position));
1245 int width = taskRect.width();
1246 int height = taskRect.height();
1247 switch (dockSide) {
1248 case WindowManager.DOCKED_LEFT:
1249 taskRect.left = offsetPosition - width;
1250 taskRect.right = offsetPosition;
1251 break;
1252 case WindowManager.DOCKED_RIGHT:
1253 taskRect.left = offsetPosition + mDividerSize;
1254 taskRect.right = offsetPosition + width + mDividerSize;
1255 break;
1256 case WindowManager.DOCKED_TOP:
1257 taskRect.top = offsetPosition - height;
1258 taskRect.bottom = offsetPosition;
1259 break;
1260 case WindowManager.DOCKED_BOTTOM:
1261 taskRect.top = offsetPosition + mDividerSize;
1262 taskRect.bottom = offsetPosition + height + mDividerSize;
1263 break;
1264 }
1265 }
1266 }
1267
1268 /**
1269 * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
1270 * slowing down parallax effect
1271 */
Jorim Jaggi1b12ef52016-01-29 16:49:55 -08001272 private static float calculateParallaxDismissingFraction(float fraction, int dockSide) {
1273 float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
1274
1275 // Less parallax at the top, just because.
1276 if (dockSide == WindowManager.DOCKED_TOP) {
1277 result /= 2f;
1278 }
1279 return result;
Jorim Jaggie435e982015-12-30 13:54:32 +01001280 }
1281
1282 private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
1283 if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
1284 return position < snapTarget.position;
1285 } else {
1286 return position > snapTarget.position;
1287 }
1288 }
1289
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001290 private boolean isDismissTargetPrimary(SnapTarget dismissTarget) {
1291 return (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
Jorim Jaggi8dccd232016-03-25 18:10:14 -07001292 || (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001293 && dockSideBottomRight(mDockSide));
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001294 }
1295
Jorim Jaggie435e982015-12-30 13:54:32 +01001296 /**
1297 * @return true if and only if {@code dockSide} is top or left
1298 */
1299 private static boolean dockSideTopLeft(int dockSide) {
1300 return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
1301 }
1302
1303 /**
1304 * @return true if and only if {@code dockSide} is bottom or right
1305 */
1306 private static boolean dockSideBottomRight(int dockSide) {
1307 return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
1308 }
1309
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001310 @Override
1311 public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
1312 inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
1313 inoutInfo.touchableRegion.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(),
1314 mHandle.getBottom());
1315 inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(),
1316 mBackground.getRight(), mBackground.getBottom(), Op.UNION);
1317 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001318
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001319 /**
1320 * Checks whether recents will grow when invoked. This happens in multi-window when recents is
1321 * very small. When invoking recents, we shrink the docked stack so recents has more space.
1322 *
1323 * @return the position of the divider when recents grows, or
1324 * {@link #INVALID_RECENTS_GROW_TARGET} if recents won't grow
1325 */
1326 public int growsRecents() {
1327 boolean result = mGrowRecents
Jorim Jaggiddb449e2017-05-12 16:32:58 +02001328 && mDockSide == WindowManager.DOCKED_TOP
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001329 && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position;
1330 if (result) {
1331 return getSnapAlgorithm().getMiddleTarget().position;
1332 } else {
1333 return INVALID_RECENTS_GROW_TARGET;
1334 }
1335 }
1336
Winson Chung67f5c8b2018-09-24 12:09:19 -07001337 void onRecentsActivityStarting() {
Jorim Jaggief496ea2017-05-13 23:16:44 +02001338 if (mGrowRecents && mDockSide == WindowManager.DOCKED_TOP
Qiushi.Han9170ca82016-10-10 13:31:48 +08001339 && getSnapAlgorithm().getMiddleTarget() != getSnapAlgorithm().getLastSplitTarget()
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001340 && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
Jorim Jaggia6c05d52016-05-27 00:31:21 -07001341 mState.growAfterRecentsDrawn = true;
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001342 startDragging(false /* animate */, false /* touching */);
1343 }
1344 }
1345
Winson Chung67f5c8b2018-09-24 12:09:19 -07001346 void onDockedFirstAnimationFrame() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001347 saveSnapTargetBeforeMinimized(mSplitLayout.getSnapAlgorithm().getMiddleTarget());
Winson Chung37b20242017-09-26 11:51:08 -07001348 }
1349
Winson Chung67f5c8b2018-09-24 12:09:19 -07001350 void onDockedTopTask() {
1351 mState.growAfterRecentsDrawn = false;
1352 mState.animateAfterRecentsDrawn = true;
1353 startDragging(false /* animate */, false /* touching */);
Jorim Jaggi899327f2016-02-25 20:44:18 -05001354 updateDockSide();
Jorim Jaggi899327f2016-02-25 20:44:18 -05001355 mEntranceAnimationRunning = true;
Jorim Jaggie525a352016-05-27 16:56:55 -07001356
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001357 resizeStackSurfaces(calculatePositionForInsetBounds(),
1358 mSplitLayout.getSnapAlgorithm().getMiddleTarget().position,
Evan Rosky36138542020-05-01 18:02:11 -07001359 mSplitLayout.getSnapAlgorithm().getMiddleTarget(),
1360 null /* transaction */);
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001361 }
1362
Winson Chung67f5c8b2018-09-24 12:09:19 -07001363 void onRecentsDrawn() {
Matthew Ng30307122018-04-13 11:36:34 -07001364 updateDockSide();
1365 final int position = calculatePositionForInsetBounds();
Jorim Jaggia6c05d52016-05-27 00:31:21 -07001366 if (mState.animateAfterRecentsDrawn) {
1367 mState.animateAfterRecentsDrawn = false;
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001368
Jorim Jaggia6c05d52016-05-27 00:31:21 -07001369 mHandler.post(() -> {
Jorim Jaggic5887ea2016-05-13 18:21:48 -07001370 // Delay switching resizing mode because this might cause jank in recents animation
1371 // that's longer than this animation.
Matthew Ng30307122018-04-13 11:36:34 -07001372 stopDragging(position, getSnapAlgorithm().getMiddleTarget(),
Jorim Jaggic5887ea2016-05-13 18:21:48 -07001373 mLongPressEntraceAnimDuration, Interpolators.FAST_OUT_SLOW_IN,
1374 200 /* endDelay */);
1375 });
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001376 }
Jorim Jaggia6c05d52016-05-27 00:31:21 -07001377 if (mState.growAfterRecentsDrawn) {
1378 mState.growAfterRecentsDrawn = false;
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001379 updateDockSide();
Winson Chung67f5c8b2018-09-24 12:09:19 -07001380 if (mCallback != null) {
1381 mCallback.growRecents();
1382 }
Matthew Ng30307122018-04-13 11:36:34 -07001383 stopDragging(position, getSnapAlgorithm().getMiddleTarget(), 336,
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001384 Interpolators.FAST_OUT_SLOW_IN);
Jorim Jaggiea4a19f2016-02-03 21:31:27 -08001385 }
1386 }
1387
Winson Chung67f5c8b2018-09-24 12:09:19 -07001388 void onUndockingTask() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001389 int dockSide = mSplitLayout.getPrimarySplitSide();
Evan Rosky89c285e2020-06-17 21:21:53 -07001390 if (inSplitMode()) {
Jorim Jaggiea4a19f2016-02-03 21:31:27 -08001391 startDragging(false /* animate */, false /* touching */);
1392 SnapTarget target = dockSideTopLeft(dockSide)
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001393 ? mSplitLayout.getSnapAlgorithm().getDismissEndTarget()
1394 : mSplitLayout.getSnapAlgorithm().getDismissStartTarget();
Jorim Jaggiea4a19f2016-02-03 21:31:27 -08001395
1396 // Don't start immediately - give a little bit time to settle the drag resize change.
Jorim Jaggi47ee9ad2016-04-11 21:51:11 -07001397 mExitAnimationRunning = true;
1398 mExitStartPosition = getCurrentPosition();
1399 stopDragging(mExitStartPosition, target, 336 /* duration */, 100 /* startDelay */,
Jorim Jaggi545c5c22016-04-12 18:59:45 -07001400 0 /* endDelay */, Interpolators.FAST_OUT_SLOW_IN);
Jorim Jaggicdb06ca2016-01-25 19:15:12 -08001401 }
Jorim Jaggi11cc01d2016-01-22 19:39:23 -08001402 }
Matthew Ng30307122018-04-13 11:36:34 -07001403
1404 private int calculatePositionForInsetBounds() {
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001405 mSplitLayout.mDisplayLayout.getStableBounds(mTmpRect);
Matthew Ng30307122018-04-13 11:36:34 -07001406 return DockedDividerUtils.calculatePositionForBounds(mTmpRect, mDockSide, mDividerSize);
1407 }
Jorim Jaggi1fcbab62015-11-04 16:39:50 +01001408}