blob: 1a1a7d4d8e0cb775b0b34e65b8bf4ce80672eac9 [file] [log] [blame]
Filip Gruszczynski466f3212015-09-21 17:57:57 -07001/*
2 * Copyright (C) 2012 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.server.wm;
18
Wale Ogunwaleb62139d2017-09-20 15:37:35 -070019import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Wale Ogunwale68278562017-09-23 17:13:55 -070020import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Jorim Jaggi85639432016-05-06 17:27:55 -070021import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
22import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
23import static android.view.Surface.ROTATION_270;
24import static android.view.Surface.ROTATION_90;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010025import static android.view.WindowManager.DOCKED_BOTTOM;
Matthew Ngcb1b8e42017-10-20 16:29:23 -070026import static android.view.WindowManager.DOCKED_INVALID;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010027import static android.view.WindowManager.DOCKED_LEFT;
28import static android.view.WindowManager.DOCKED_RIGHT;
29import static android.view.WindowManager.DOCKED_TOP;
Evan Rosky35630df2018-10-31 10:22:08 -070030import static android.view.WindowManager.TRANSIT_NONE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080031import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
32import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
Evan Rosky35630df2018-10-31 10:22:08 -070033
Jorim Jaggibc5425c2016-03-01 13:51:16 +010034import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
35import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
Evan Rosky35630df2018-10-31 10:22:08 -070036import static com.android.server.wm.DockedStackDividerControllerProto.MINIMIZED_DOCK;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010037import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
38import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
39
Filip Gruszczynski466f3212015-09-21 17:57:57 -070040import android.content.Context;
Jorim Jaggi85639432016-05-06 17:27:55 -070041import android.content.res.Configuration;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070042import android.graphics.Rect;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010043import android.os.RemoteCallbackList;
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080044import android.os.RemoteException;
Jorim Jaggi936aaeb2016-08-26 19:02:11 -070045import android.util.ArraySet;
Filip Gruszczynski77049052015-11-09 14:01:21 -080046import android.util.Slog;
Steven Timotiusaf03df62017-07-18 16:56:43 -070047import android.util.proto.ProtoOutputStream;
Adrian Roos11c25582018-02-19 18:06:36 +010048import android.view.DisplayCutout;
Jorim Jaggi50981592015-12-29 17:54:12 +010049import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010050import android.view.IDockedStackListener;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080051import android.view.animation.AnimationUtils;
52import android.view.animation.Interpolator;
Jorim Jaggieb88d832016-04-13 20:17:43 -070053import android.view.animation.PathInterpolator;
Jorim Jaggi50981592015-12-29 17:54:12 +010054
Tiger Huang7c610aa2018-10-27 00:01:01 +080055import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggi85639432016-05-06 17:27:55 -070056import com.android.internal.policy.DividerSnapAlgorithm;
57import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070058import com.android.server.LocalServices;
Yohei Yukawac3de83e2018-08-28 16:09:34 -070059import com.android.server.inputmethod.InputMethodManagerInternal;
Jorim Jaggiff71d202016-04-14 13:12:36 -070060import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010061
Jorim Jaggi31f71702016-05-04 16:43:04 -070062import java.io.PrintWriter;
Chong Zhangbaba7832016-03-24 10:21:26 -070063
Filip Gruszczynski466f3212015-09-21 17:57:57 -070064/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010065 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070066 */
Robert Carrf59b8dd2017-10-02 18:58:36 -070067public class DockedStackDividerController {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010068
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080069 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010070
Jorim Jaggif97ed922016-02-18 18:57:07 -080071 /**
72 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
73 * revealing surface at the earliest.
74 */
75 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
76
77 /**
78 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
79 * revealing surface at the latest.
80 */
81 private static final float CLIP_REVEAL_MEET_LAST = 1f;
82
83 /**
84 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
85 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
86 */
87 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
88
89 /**
90 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
91 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
92 */
93 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
94
Jorim Jaggieb88d832016-04-13 20:17:43 -070095 private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
Jorim Jaggiff71d202016-04-14 13:12:36 -070096 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggieb88d832016-04-13 20:17:43 -070097
Jorim Jaggi698e7632016-04-13 21:02:22 -070098 private static final long IME_ADJUST_ANIM_DURATION = 280;
Jorim Jaggieb88d832016-04-13 20:17:43 -070099
Jorim Jaggiff71d202016-04-14 13:12:36 -0700100 private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
101
Chong Zhang198afac2016-04-15 12:03:11 -0700102 private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
103
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800104 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700105 private final DisplayContent mDisplayContent;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700106 private int mDividerWindowWidth;
Chong Zhang198afac2016-04-15 12:03:11 -0700107 private int mDividerWindowWidthInactive;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700108 private int mDividerInsets;
Matthew Nge15352e2016-12-20 15:36:29 -0800109 private int mTaskHeightInMinimizedMode;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100110 private boolean mResizing;
111 private WindowState mWindow;
112 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800113 private final Rect mTmpRect2 = new Rect();
Jorim Jaggi85639432016-05-06 17:27:55 -0700114 private final Rect mTmpRect3 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -0800115 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800116 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100117 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
118 = new RemoteCallbackList<>();
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700119
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800120 private boolean mMinimizedDock;
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700121 private int mOriginalDockedSide = DOCKED_INVALID;
Chong Zhangbaba7832016-03-24 10:21:26 -0700122 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800123 private boolean mAnimationStarted;
124 private long mAnimationStartTime;
125 private float mAnimationStart;
126 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800127 private long mAnimationDuration;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700128 private boolean mAnimationStartDelayed;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800129 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800130 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100131 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700132 private boolean mAnimatingForIme;
133 private boolean mAdjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700134 private int mImeHeight;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700135 private WindowState mDelayedImeWin;
Chong Zhangf347ab52016-04-18 21:02:01 -0700136 private boolean mAdjustedForDivider;
137 private float mDividerAnimationStart;
138 private float mDividerAnimationTarget;
Wale Ogunwale10124582016-09-15 20:25:50 -0700139 float mLastAnimationProgress;
140 float mLastDividerProgress;
Jorim Jaggi85639432016-05-06 17:27:55 -0700141 private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700142 private boolean mImeHideRequested;
Louis Changdc077272019-11-12 16:52:56 +0800143 private ActivityStack mDimmedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800144
145 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
146 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700147 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800148 final Context context = service.mContext;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800149 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
150 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700151 loadDimens();
152 }
153
Jorim Jaggi85639432016-05-06 17:27:55 -0700154 int getSmallestWidthDpForBounds(Rect bounds) {
155 final DisplayInfo di = mDisplayContent.getDisplayInfo();
156
Jorim Jaggi85639432016-05-06 17:27:55 -0700157 final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
158 final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
159 int minWidth = Integer.MAX_VALUE;
160
161 // Go through all screen orientations and find the orientation in which the task has the
162 // smallest width.
163 for (int rotation = 0; rotation < 4; rotation++) {
164 mTmpRect.set(bounds);
165 mDisplayContent.rotateBounds(di.rotation, rotation, mTmpRect);
166 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
167 mTmpRect2.set(0, 0,
168 rotated ? baseDisplayHeight : baseDisplayWidth,
169 rotated ? baseDisplayWidth : baseDisplayHeight);
170 final int orientation = mTmpRect2.width() <= mTmpRect2.height()
171 ? ORIENTATION_PORTRAIT
172 : ORIENTATION_LANDSCAPE;
Evan Rosky39b6f232018-10-30 18:35:41 -0700173 final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation, rotation);
Jorim Jaggi85639432016-05-06 17:27:55 -0700174 final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
175 getContentWidth());
176
Adrian Roos2aa0fcd2018-02-19 18:07:49 +0100177 final DisplayCutout displayCutout = mDisplayContent.calculateDisplayCutoutForRotation(
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100178 rotation).getDisplayCutout();
Adrian Roos11c25582018-02-19 18:06:36 +0100179
Jorim Jaggi85639432016-05-06 17:27:55 -0700180 // Since we only care about feasible states, snap to the closest snap target, like it
181 // would happen when actually rotating the screen.
182 final int snappedPosition = mSnapAlgorithmForRotation[rotation]
183 .calculateNonDismissingSnapTarget(position).position;
184 DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, mTmpRect,
185 mTmpRect2.width(), mTmpRect2.height(), getContentWidth());
Tiger Huang7c610aa2018-10-27 00:01:01 +0800186 mDisplayContent.getDisplayPolicy().getStableInsetsLw(rotation, mTmpRect2.width(),
187 mTmpRect2.height(), displayCutout, mTmpRect3);
Winson Chungbdc646f2017-02-13 12:12:22 -0800188 mService.intersectDisplayInsetBounds(mTmpRect2, mTmpRect3, mTmpRect);
Jorim Jaggi85639432016-05-06 17:27:55 -0700189 minWidth = Math.min(mTmpRect.width(), minWidth);
190 }
191 return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
192 }
193
Matthew Ng62c78462018-04-09 14:43:21 -0700194 /**
195 * Get the current docked side. Determined by its location of {@param bounds} within
196 * {@param displayRect} but if both are the same, it will try to dock to each side and determine
197 * if allowed in its respected {@param orientation}.
198 *
199 * @param bounds bounds of the docked task to get which side is docked
200 * @param displayRect bounds of the display that contains the docked task
201 * @param orientation the origination of device
202 * @return current docked side
203 */
Evan Rosky39b6f232018-10-30 18:35:41 -0700204 int getDockSide(Rect bounds, Rect displayRect, int orientation, int rotation) {
Matthew Ng62c78462018-04-09 14:43:21 -0700205 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
206 // Portrait mode, docked either at the top or the bottom.
207 final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
208 if (diff > 0) {
209 return DOCKED_TOP;
210 } else if (diff < 0) {
211 return DOCKED_BOTTOM;
212 }
Evan Rosky39b6f232018-10-30 18:35:41 -0700213 return canPrimaryStackDockTo(DOCKED_TOP, displayRect, rotation)
214 ? DOCKED_TOP : DOCKED_BOTTOM;
Matthew Ng62c78462018-04-09 14:43:21 -0700215 } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
216 // Landscape mode, docked either on the left or on the right.
217 final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
218 if (diff > 0) {
219 return DOCKED_LEFT;
220 } else if (diff < 0) {
221 return DOCKED_RIGHT;
222 }
Evan Rosky39b6f232018-10-30 18:35:41 -0700223 return canPrimaryStackDockTo(DOCKED_LEFT, displayRect, rotation)
224 ? DOCKED_LEFT : DOCKED_RIGHT;
Matthew Ng62c78462018-04-09 14:43:21 -0700225 }
226 return DOCKED_INVALID;
227 }
228
Evan Roskyc5abbd82018-10-05 16:02:19 -0700229 void getHomeStackBoundsInDockedMode(Configuration parentConfig, int dockSide, Rect outBounds) {
230 final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout;
231 final int displayWidth = parentConfig.windowConfiguration.getBounds().width();
232 final int displayHeight = parentConfig.windowConfiguration.getBounds().height();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800233 mDisplayContent.getDisplayPolicy().getStableInsetsLw(
234 parentConfig.windowConfiguration.getRotation(), displayWidth, displayHeight,
235 displayCutout, mTmpRect);
Matthew Nge15352e2016-12-20 15:36:29 -0800236 int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
Matthew Nga9e173d2017-05-17 15:03:18 -0700237 // The offset in the left (landscape)/top (portrait) is calculated with the minimized
238 // offset value with the divider size and any system insets in that direction.
Evan Roskyc5abbd82018-10-05 16:02:19 -0700239 if (parentConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
Matthew Nge15352e2016-12-20 15:36:29 -0800240 outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
Evan Roskyc5abbd82018-10-05 16:02:19 -0700241 displayWidth, displayHeight);
Matthew Nge15352e2016-12-20 15:36:29 -0800242 } else {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800243 // In landscape also inset the left/right side with the status bar height to match the
Matthew Nga9e173d2017-05-17 15:03:18 -0700244 // minimized size height in portrait mode.
Matthew Ng62c78462018-04-09 14:43:21 -0700245 final int primaryTaskWidth = mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top;
246 int left = mTmpRect.left;
Evan Roskyc5abbd82018-10-05 16:02:19 -0700247 int right = displayWidth - mTmpRect.right;
248 if (dockSide == DOCKED_LEFT) {
249 left += primaryTaskWidth;
250 } else if (dockSide == DOCKED_RIGHT) {
251 right -= primaryTaskWidth;
Matthew Ng62c78462018-04-09 14:43:21 -0700252 }
Evan Roskyc5abbd82018-10-05 16:02:19 -0700253 outBounds.set(left, 0, right, displayHeight);
Matthew Nge15352e2016-12-20 15:36:29 -0800254 }
255 }
256
257 boolean isHomeStackResizable() {
Louis Changdc077272019-11-12 16:52:56 +0800258 final ActivityStack homeStack = mDisplayContent.getHomeStack();
Matthew Nge15352e2016-12-20 15:36:29 -0800259 if (homeStack == null) {
260 return false;
261 }
262 final Task homeTask = homeStack.findHomeTask();
263 return homeTask != null && homeTask.isResizeable();
264 }
265
Jorim Jaggi85639432016-05-06 17:27:55 -0700266 private void initSnapAlgorithmForRotations() {
Andrii Kulian441e4492016-09-29 15:25:00 -0700267 final Configuration baseConfig = mDisplayContent.getConfiguration();
Jorim Jaggi85639432016-05-06 17:27:55 -0700268
269 // Initialize the snap algorithms for all 4 screen orientations.
270 final Configuration config = new Configuration();
271 for (int rotation = 0; rotation < 4; rotation++) {
272 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
273 final int dw = rotated
274 ? mDisplayContent.mBaseDisplayHeight
275 : mDisplayContent.mBaseDisplayWidth;
276 final int dh = rotated
277 ? mDisplayContent.mBaseDisplayWidth
278 : mDisplayContent.mBaseDisplayHeight;
Adrian Roos11c25582018-02-19 18:06:36 +0100279 final DisplayCutout displayCutout =
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100280 mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800281 final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
282 displayPolicy.getStableInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
Andrii Kulianb10330d2016-09-16 13:51:46 -0700283 config.unset();
Jorim Jaggi85639432016-05-06 17:27:55 -0700284 config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
Bryce Lee7566d762017-03-30 09:34:15 -0700285
Tiger Huang7c610aa2018-10-27 00:01:01 +0800286 final int appWidth = displayPolicy.getNonDecorDisplayWidth(dw, dh, rotation,
287 baseConfig.uiMode, displayCutout);
288 final int appHeight = displayPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
289 baseConfig.uiMode, displayCutout);
290 displayPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
Bryce Lee7566d762017-03-30 09:34:15 -0700291 final int leftInset = mTmpRect.left;
292 final int topInset = mTmpRect.top;
293
Wale Ogunwale822e5122017-07-26 06:02:24 -0700294 config.windowConfiguration.setAppBounds(leftInset /*left*/, topInset /*top*/,
295 leftInset + appWidth /*right*/, topInset + appHeight /*bottom*/);
Bryce Lee7566d762017-03-30 09:34:15 -0700296
Adrian Roos11c25582018-02-19 18:06:36 +0100297 final float density = mDisplayContent.getDisplayMetrics().density;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800298 config.screenWidthDp = (int) (displayPolicy.getConfigDisplayWidth(dw, dh, rotation,
299 baseConfig.uiMode, displayCutout) / density);
300 config.screenHeightDp = (int) (displayPolicy.getConfigDisplayHeight(dw, dh, rotation,
301 baseConfig.uiMode, displayCutout) / density);
Jorim Jaggi85639432016-05-06 17:27:55 -0700302 final Context rotationContext = mService.mContext.createConfigurationContext(config);
303 mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
304 rotationContext.getResources(), dw, dh, getContentWidth(),
305 config.orientation == ORIENTATION_PORTRAIT, mTmpRect);
306 }
307 }
308
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700309 private void loadDimens() {
310 final Context context = mService.mContext;
311 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
312 com.android.internal.R.dimen.docked_stack_divider_thickness);
313 mDividerInsets = context.getResources().getDimensionPixelSize(
314 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700315 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
316 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Matthew Nge15352e2016-12-20 15:36:29 -0800317 mTaskHeightInMinimizedMode = context.getResources().getDimensionPixelSize(
318 com.android.internal.R.dimen.task_height_of_minimized_mode);
Jorim Jaggi85639432016-05-06 17:27:55 -0700319 initSnapAlgorithmForRotations();
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700320 }
321
322 void onConfigurationChanged() {
323 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700324 }
325
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100326 boolean isResizing() {
327 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700328 }
329
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100330 int getContentWidth() {
331 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700332 }
333
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800334 int getContentInsets() {
335 return mDividerInsets;
336 }
337
Chong Zhang198afac2016-04-15 12:03:11 -0700338 int getContentWidthInactive() {
339 return mDividerWindowWidthInactive;
340 }
341
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100342 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800343 if (mResizing != resizing) {
344 mResizing = resizing;
345 resetDragResizingChangeReported();
346 }
347 }
348
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100349 void setTouchRegion(Rect touchRegion) {
350 mTouchRegion.set(touchRegion);
351 }
352
353 void getTouchRegion(Rect outRegion) {
354 outRegion.set(mTouchRegion);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700355 if (mWindow != null) {
356 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
357 }
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100358 }
359
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800360 private void resetDragResizingChangeReported() {
Wale Ogunwaled1880962016-11-08 10:31:59 -0800361 mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
362 true /* traverseTopToBottom */ );
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100363 }
364
365 void setWindow(WindowState window) {
366 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800367 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100368 }
369
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800370 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800371 if (mWindow == null) {
372 return;
373 }
Louis Changdc077272019-11-12 16:52:56 +0800374 ActivityStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Jorim Jaggi7998e482016-02-12 18:47:06 -0800375
376 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
377 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800378 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800379 return;
380 }
381 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100382 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100383 if (!visible) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700384 setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f);
Jorim Jaggi50981592015-12-29 17:54:12 +0100385 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100386 }
387
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700388 private boolean wasVisible() {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100389 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100390 }
391
Chong Zhangf347ab52016-04-18 21:02:01 -0700392 void setAdjustedForIme(
393 boolean adjustedForIme, boolean adjustedForDivider,
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700394 boolean animate, WindowState imeWin, int imeHeight) {
395 if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
396 || mAdjustedForDivider != adjustedForDivider) {
Jorim Jaggi3070e772016-05-17 16:41:32 -0700397 if (animate && !mAnimatingForMinimizedDockedStack) {
lumarkbcc316e2018-12-25 21:37:05 +0800398 // Notify SystemUI to set the target docked stack size according current docked
399 // state without animation when calling startImeAdjustAnimation.
400 notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
401 isHomeStackResizable());
Chong Zhangf347ab52016-04-18 21:02:01 -0700402 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700403 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700404 // Animation might be delayed, so only notify if we don't run an animation.
Chong Zhangf347ab52016-04-18 21:02:01 -0700405 notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700406 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700407 mAdjustedForIme = adjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700408 mImeHeight = imeHeight;
Chong Zhangf347ab52016-04-18 21:02:01 -0700409 mAdjustedForDivider = adjustedForDivider;
Chong Zhangbaba7832016-03-24 10:21:26 -0700410 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700411 }
412
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700413 int getImeHeightAdjustedFor() {
414 return mImeHeight;
415 }
416
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700417 void positionDockedStackedDivider(Rect frame) {
Louis Changdc077272019-11-12 16:52:56 +0800418 ActivityStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700419 if (stack == null) {
420 // Unfortunately we might end up with still having a divider, even though the underlying
421 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800422 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
423 // keep putting it in the same place it was before the stack was removed to have
424 // continuity and prevent it from jumping to the center. It will get hidden soon.
425 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700426 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800427 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800428 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700429 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100430 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700431 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700432 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100433 frame.set(mTmpRect.right - mDividerInsets, frame.top,
434 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700435 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700436 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100437 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
438 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700439 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700440 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100441 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
442 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700443 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700444 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100445 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
446 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700447 break;
448 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800449 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700450 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800451
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700452 private void notifyDockedDividerVisibilityChanged(boolean visible) {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100453 final int size = mDockedStackListeners.beginBroadcast();
454 for (int i = 0; i < size; ++i) {
455 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
456 try {
457 listener.onDividerVisibilityChanged(visible);
458 } catch (RemoteException e) {
459 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
460 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800461 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100462 mDockedStackListeners.finishBroadcast();
463 }
464
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700465 /**
466 * Checks if the primary stack is allowed to dock to a specific side based on its original dock
467 * side.
468 *
469 * @param dockSide the side to see if it is valid
470 * @return true if the side provided is valid
471 */
Evan Rosky39b6f232018-10-30 18:35:41 -0700472 boolean canPrimaryStackDockTo(int dockSide, Rect parentRect, int rotation) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800473 final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
474 return isDockSideAllowed(dockSide, mOriginalDockedSide,
475 policy.navigationBarPosition(parentRect.width(), parentRect.height(), rotation),
476 policy.navigationBarCanMove());
477 }
478
479 @VisibleForTesting
480 static boolean isDockSideAllowed(int dockSide, int originalDockSide, int navBarPosition,
481 boolean navigationBarCanMove) {
482 if (dockSide == DOCKED_TOP) {
483 return true;
484 }
485
486 if (navigationBarCanMove) {
487 // Only allow the dockside opposite to the nav bar position in landscape
488 return dockSide == DOCKED_LEFT && navBarPosition == NAV_BAR_RIGHT
489 || dockSide == DOCKED_RIGHT && navBarPosition == NAV_BAR_LEFT;
490 }
491
492 // Side is the same as original side
493 if (dockSide == originalDockSide) {
494 return true;
495 }
496
497 // Only if original docked side was top in portrait will allow left for landscape
498 return dockSide == DOCKED_LEFT && originalDockSide == DOCKED_TOP;
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700499 }
500
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100501 void notifyDockedStackExistsChanged(boolean exists) {
Andrii Kulian5406e7a2016-10-21 11:55:23 -0700502 // TODO(multi-display): Perform all actions only for current display.
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100503 final int size = mDockedStackListeners.beginBroadcast();
504 for (int i = 0; i < size; ++i) {
505 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
506 try {
507 listener.onDockedStackExistsChanged(exists);
508 } catch (RemoteException e) {
509 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
510 }
511 }
512 mDockedStackListeners.finishBroadcast();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700513 if (exists) {
514 InputMethodManagerInternal inputMethodManagerInternal =
515 LocalServices.getService(InputMethodManagerInternal.class);
516 if (inputMethodManagerInternal != null) {
517
518 // Hide the current IME to avoid problems with animations from IME adjustment when
519 // attaching the docked stack.
520 inputMethodManagerInternal.hideCurrentInputMethod();
521 mImeHideRequested = true;
522 }
Matthew Nge8b052a2018-01-16 14:33:47 -0800523
524 // If a primary stack was just created, it will not have access to display content at
525 // this point so pass it from here to get a valid dock side.
Louis Changdc077272019-11-12 16:52:56 +0800526 final ActivityStack stack =
527 mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Matthew Nge8b052a2018-01-16 14:33:47 -0800528 mOriginalDockedSide = stack.getDockSideForDisplay(mDisplayContent);
Matthew Ngbc527a32017-06-19 16:42:31 -0700529 return;
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700530 }
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700531 mOriginalDockedSide = DOCKED_INVALID;
Matthew Ngbc527a32017-06-19 16:42:31 -0700532 setMinimizedDockedStack(false /* minimizedDock */, false /* animate */);
Robert Carrf59b8dd2017-10-02 18:58:36 -0700533
534 if (mDimmedStack != null) {
535 mDimmedStack.stopDimming();
536 mDimmedStack = null;
537 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100538 }
539
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700540 /**
541 * Resets the state that IME hide has been requested. See {@link #isImeHideRequested}.
542 */
543 void resetImeHideRequested() {
544 mImeHideRequested = false;
545 }
546
547 /**
548 * The docked stack divider controller makes sure the IME gets hidden when attaching the docked
549 * stack, to avoid animation problems. This flag indicates whether the request to hide the IME
550 * has been sent in an asynchronous manner, and the IME should be treated as hidden already.
551 *
552 * @return whether IME hide request has been sent
553 */
554 boolean isImeHideRequested() {
555 return mImeHideRequested;
556 }
557
Matthew Nge15352e2016-12-20 15:36:29 -0800558 private void notifyDockedStackMinimizedChanged(boolean minimizedDock, boolean animate,
559 boolean isHomeStackResizable) {
560 long animDuration = 0;
561 if (animate) {
Louis Changdc077272019-11-12 16:52:56 +0800562 final ActivityStack stack =
Matthew Ng64e77cf2017-10-31 14:01:31 -0700563 mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Matthew Nge15352e2016-12-20 15:36:29 -0800564 final long transitionDuration = isAnimationMaximizing()
lumark588a3e82018-07-20 18:53:54 +0800565 ? mDisplayContent.mAppTransition.getLastClipRevealTransitionDuration()
Matthew Nge15352e2016-12-20 15:36:29 -0800566 : DEFAULT_APP_TRANSITION_DURATION;
567 mAnimationDuration = (long)
568 (transitionDuration * mService.getTransitionAnimationScaleLocked());
569 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
570 animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
571 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800572 final int size = mDockedStackListeners.beginBroadcast();
573 for (int i = 0; i < size; ++i) {
574 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
575 try {
Matthew Nge15352e2016-12-20 15:36:29 -0800576 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration,
577 isHomeStackResizable);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800578 } catch (RemoteException e) {
579 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
580 }
581 }
582 mDockedStackListeners.finishBroadcast();
Winson Chungd4c96f92019-06-27 13:37:18 -0700583 // Only notify ATM after we update the remote listeners, otherwise it may trigger another
584 // minimize change, which would lead to an inversion of states send to the listeners
585 mService.mAtmInternal.notifyDockedStackMinimizedChanged(minimizedDock);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800586 }
587
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700588 void notifyDockSideChanged(int newDockSide) {
589 final int size = mDockedStackListeners.beginBroadcast();
590 for (int i = 0; i < size; ++i) {
591 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
592 try {
593 listener.onDockSideChanged(newDockSide);
594 } catch (RemoteException e) {
595 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
596 }
597 }
598 mDockedStackListeners.finishBroadcast();
599 }
600
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700601 private void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
Jorim Jaggi698e7632016-04-13 21:02:22 -0700602 final int size = mDockedStackListeners.beginBroadcast();
603 for (int i = 0; i < size; ++i) {
604 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
605 try {
606 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
607 } catch (RemoteException e) {
608 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
609 }
610 }
611 mDockedStackListeners.finishBroadcast();
612 }
613
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100614 void registerDockedStackListener(IDockedStackListener listener) {
615 mDockedStackListeners.register(listener);
616 notifyDockedDividerVisibilityChanged(wasVisible());
Wale Ogunwale61911492017-10-11 08:50:50 -0700617 notifyDockedStackExistsChanged(
Matthew Ng64e77cf2017-10-31 14:01:31 -0700618 mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null);
Matthew Nge15352e2016-12-20 15:36:29 -0800619 notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
620 isHomeStackResizable());
Jorim Jaggi698e7632016-04-13 21:02:22 -0700621 notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
622
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800623 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100624
Wale Ogunwale68278562017-09-23 17:13:55 -0700625 /**
626 * Shows a dim layer with {@param alpha} if {@param visible} is true and
627 * {@param targetWindowingMode} isn't
628 * {@link android.app.WindowConfiguration#WINDOWING_MODE_UNDEFINED} and there is a stack on the
629 * display in that windowing mode.
630 */
631 void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700632 // TODO: Maybe only allow split-screen windowing modes?
Louis Changdc077272019-11-12 16:52:56 +0800633 final ActivityStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800634 ? mDisplayContent.getTopStackInWindowingMode(targetWindowingMode)
Wale Ogunwale68278562017-09-23 17:13:55 -0700635 : null;
Louis Changdc077272019-11-12 16:52:56 +0800636 final ActivityStack dockedStack = mDisplayContent.getSplitScreenPrimaryStack();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100637 boolean visibleAndValid = visible && stack != null && dockedStack != null;
chaviw783729c2018-01-25 15:14:10 -0800638
639 // Ensure an old dim that was shown for the docked stack divider is removed so we don't end
640 // up with dim layers that can no longer be removed.
641 if (mDimmedStack != null && mDimmedStack != stack) {
642 mDimmedStack.stopDimming();
643 mDimmedStack = null;
644 }
645
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100646 if (visibleAndValid) {
Robert Carrf59b8dd2017-10-02 18:58:36 -0700647 mDimmedStack = stack;
648 stack.dim(alpha);
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100649 }
Robert Carrf59b8dd2017-10-02 18:58:36 -0700650 if (!visibleAndValid && stack != null) {
651 mDimmedStack = null;
652 stack.stopDimming();
Jorim Jaggi50981592015-12-29 17:54:12 +0100653 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100654 }
655
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800656 /**
657 * Notifies the docked stack divider controller of a visibility change that happens without
658 * an animation.
659 */
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700660 void notifyAppVisibilityChanged() {
661 checkMinimizeChanged(false /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800662 }
663
Garfield Tane8d84ab2019-10-11 09:49:40 -0700664 void notifyAppTransitionStarting(ArraySet<ActivityRecord> openingApps, int appTransition) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700665 final boolean wasMinimized = mMinimizedDock;
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700666 checkMinimizeChanged(true /* animate */);
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700667
668 // We were minimized, and now we are still minimized, but somebody is trying to launch an
Matthew Ng8e265522017-02-13 11:09:37 -0800669 // app in docked stack, better show recent apps so we actually get unminimized! However do
670 // not do this if keyguard is dismissed such as when the device is unlocking. This catches
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700671 // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
672 // we couldn't retrace the launch of the app in the docked stack to the launch from
673 // homescreen.
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200674 if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
Matthew Ng8e265522017-02-13 11:09:37 -0800675 && appTransition != TRANSIT_NONE &&
676 !AppTransition.isKeyguardGoingAwayTransit(appTransition)) {
Wale Ogunwale6767eae2018-05-03 15:52:51 -0700677 if (mService.mAtmInternal.isRecentsComponentHomeActivity(mService.mCurrentUserId)) {
Winson Chungc1674272018-02-21 10:15:17 -0800678 // When the home activity is the recents component and we are already minimized,
679 // then there is nothing to do here since home is already visible
680 } else {
681 mService.showRecentApps();
682 }
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700683 }
684 }
685
686 /**
687 * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
688 */
Garfield Tane8d84ab2019-10-11 09:49:40 -0700689 private boolean containsAppInDockedStack(ArraySet<ActivityRecord> apps) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700690 for (int i = apps.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700691 final ActivityRecord activity = apps.valueAt(i);
692 if (activity.getTask() != null && activity.inSplitScreenPrimaryWindowingMode()) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700693 return true;
694 }
695 }
696 return false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800697 }
698
Jorim Jaggi1ae68bf2016-05-09 18:44:34 -0700699 boolean isMinimizedDock() {
700 return mMinimizedDock;
701 }
702
Winson Chungc1674272018-02-21 10:15:17 -0800703 void checkMinimizeChanged(boolean animate) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700704 if (mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() == null) {
Jorim Jaggi817a5242016-05-06 15:45:00 -0700705 return;
706 }
Louis Changdc077272019-11-12 16:52:56 +0800707 final ActivityStack homeStack = mDisplayContent.getHomeStack();
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700708 if (homeStack == null) {
709 return;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800710 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700711 final Task homeTask = homeStack.findHomeTask();
712 if (homeTask == null || !isWithinDisplay(homeTask)) {
713 return;
714 }
Matthew Ng8e265522017-02-13 11:09:37 -0800715
716 // Do not minimize when dock is already minimized while keyguard is showing and not
717 // occluded such as unlocking the screen
Adrian Roosb56b3c32018-05-17 17:32:26 +0200718 if (mMinimizedDock && mService.mKeyguardOrAodShowingOnDefaultDisplay) {
Matthew Ng8e265522017-02-13 11:09:37 -0800719 return;
720 }
Louis Changdc077272019-11-12 16:52:56 +0800721 final ActivityStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700722 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Winson Chungf557c3b2018-03-16 10:55:20 -0700723 final RecentsAnimationController recentsAnim = mService.getRecentsAnimationController();
724 final boolean minimizedForRecentsAnimation = recentsAnim != null &&
725 recentsAnim.isSplitScreenMinimized();
Garfield Tane8d84ab2019-10-11 09:49:40 -0700726 boolean homeVisible = homeTask.getTopVisibleActivity() != null;
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800727 if (homeVisible && topSecondaryStack != null) {
728 // Home should only be considered visible if it is greater or equal to the top secondary
729 // stack in terms of z-order.
730 homeVisible = homeStack.compareTo(topSecondaryStack) >= 0;
731 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700732 setMinimizedDockedStack(homeVisible || minimizedForRecentsAnimation, animate);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800733 }
734
735 private boolean isWithinDisplay(Task task) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800736 task.getBounds(mTmpRect);
737 mDisplayContent.getBounds(mTmpRect2);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800738 return mTmpRect.intersect(mTmpRect2);
739 }
740
741 /**
742 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
743 * docked stack are heavily clipped so you can only see a minimal peek state.
744 *
745 * @param minimizedDock Whether the docked stack is currently minimized.
746 * @param animate Whether to animate the change.
747 */
748 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700749 final boolean wasMinimized = mMinimizedDock;
750 mMinimizedDock = minimizedDock;
Jorim Jaggi817a5242016-05-06 15:45:00 -0700751 if (minimizedDock == wasMinimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800752 return;
753 }
754
Chong Zhang22eff0a2016-07-01 14:48:11 -0700755 final boolean imeChanged = clearImeAdjustAnimation();
756 boolean minimizedChange = false;
Matthew Nge15352e2016-12-20 15:36:29 -0800757 if (isHomeStackResizable()) {
Winson Chungc1674272018-02-21 10:15:17 -0800758 notifyDockedStackMinimizedChanged(minimizedDock, animate,
Matthew Nge15352e2016-12-20 15:36:29 -0800759 true /* isHomeStackResizable */);
760 minimizedChange = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800761 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800762 if (minimizedDock) {
763 if (animate) {
764 startAdjustAnimation(0f, 1f);
765 } else {
766 minimizedChange |= setMinimizedDockedStack(true);
767 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800768 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800769 if (animate) {
770 startAdjustAnimation(1f, 0f);
771 } else {
772 minimizedChange |= setMinimizedDockedStack(false);
773 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800774 }
775 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700776 if (imeChanged || minimizedChange) {
777 if (imeChanged && !minimizedChange) {
778 Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing,"
779 + " minimizedDock=" + minimizedDock
780 + " minimizedChange=" + minimizedChange);
781 }
782 mService.mWindowPlacerLocked.performSurfacePlacement();
783 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800784 }
785
Chong Zhang22eff0a2016-07-01 14:48:11 -0700786 private boolean clearImeAdjustAnimation() {
Wale Ogunwale10124582016-09-15 20:25:50 -0700787 final boolean changed = mDisplayContent.clearImeAdjustAnimation();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700788 mAnimatingForIme = false;
Chong Zhang22eff0a2016-07-01 14:48:11 -0700789 return changed;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700790 }
791
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800792 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700793 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800794 mAnimationStarted = false;
795 mAnimationStart = from;
796 mAnimationTarget = to;
797 }
798
Chong Zhangf347ab52016-04-18 21:02:01 -0700799 private void startImeAdjustAnimation(
800 boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700801
802 // If we're not in an animation, the starting point depends on whether we're adjusted
803 // or not. If we're already in an animation, we start from where the current animation
804 // left off, so that the motion doesn't look discontinuous.
805 if (!mAnimatingForIme) {
806 mAnimationStart = mAdjustedForIme ? 1 : 0;
807 mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
808 mLastAnimationProgress = mAnimationStart;
809 mLastDividerProgress = mDividerAnimationStart;
810 } else {
811 mAnimationStart = mLastAnimationProgress;
812 mDividerAnimationStart = mLastDividerProgress;
813 }
Jorim Jaggi3070e772016-05-17 16:41:32 -0700814 mAnimatingForIme = true;
815 mAnimationStarted = false;
Chong Zhangf347ab52016-04-18 21:02:01 -0700816 mAnimationTarget = adjustedForIme ? 1 : 0;
817 mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700818
Wale Ogunwale10124582016-09-15 20:25:50 -0700819 mDisplayContent.beginImeAdjustAnimation();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700820
821 // We put all tasks into drag resizing mode - wait until all of them have completed the
822 // drag resizing switch.
Yunfan Chen87b5a242019-10-01 17:53:59 +0900823 final Runnable existingWaitingForDrwanCallback =
824 mService.mWaitingForDrawnCallbacks.get(mService.mRoot);
825 if (existingWaitingForDrwanCallback != null) {
826 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, mService.mRoot);
827 mService.mH.sendMessageDelayed(mService.mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT,
828 mService.mRoot),
Jorim Jaggiff71d202016-04-14 13:12:36 -0700829 IME_ADJUST_DRAWN_TIMEOUT);
830 mAnimationStartDelayed = true;
831 if (imeWin != null) {
832
833 // There might be an old window delaying the animation start - clear it.
834 if (mDelayedImeWin != null) {
Jorim Jaggia5e10572017-11-15 14:36:26 +0100835 mDelayedImeWin.endDelayingAnimationStart();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700836 }
837 mDelayedImeWin = imeWin;
Jorim Jaggia5e10572017-11-15 14:36:26 +0100838 imeWin.startDelayingAnimationStart();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700839 }
Jorim Jaggi31883862016-11-04 15:45:30 -0700840
841 // If we are already waiting for something to be drawn, clear out the old one so it
842 // still gets executed.
843 // TODO: Have a real system where we can wait on different windows to be drawn with
844 // different callbacks.
Yunfan Chen87b5a242019-10-01 17:53:59 +0900845 existingWaitingForDrwanCallback.run();
846 mService.mWaitingForDrawnCallbacks.put(mService.mRoot, () -> {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700847 synchronized (mService.mGlobalLock) {
Jorim Jaggia5e10572017-11-15 14:36:26 +0100848 mAnimationStartDelayed = false;
849 if (mDelayedImeWin != null) {
850 mDelayedImeWin.endDelayingAnimationStart();
851 }
852 // If the adjust status changed since this was posted, only notify
853 // the new states and don't animate.
854 long duration = 0;
855 if (mAdjustedForIme == adjustedForIme
856 && mAdjustedForDivider == adjustedForDivider) {
857 duration = IME_ADJUST_ANIM_DURATION;
858 } else {
859 Slog.w(TAG, "IME adjust changed while waiting for drawn:"
860 + " adjustedForIme=" + adjustedForIme
861 + " adjustedForDivider=" + adjustedForDivider
862 + " mAdjustedForIme=" + mAdjustedForIme
863 + " mAdjustedForDivider=" + mAdjustedForDivider);
864 }
865 notifyAdjustedForImeChanged(
866 mAdjustedForIme || mAdjustedForDivider, duration);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700867 }
Yunfan Chen87b5a242019-10-01 17:53:59 +0900868 });
Jorim Jaggiff71d202016-04-14 13:12:36 -0700869 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700870 notifyAdjustedForImeChanged(
871 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700872 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700873 }
874
Chong Zhang22eff0a2016-07-01 14:48:11 -0700875 private boolean setMinimizedDockedStack(boolean minimized) {
Louis Changdc077272019-11-12 16:52:56 +0800876 final ActivityStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Matthew Nge15352e2016-12-20 15:36:29 -0800877 notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
Chong Zhang22eff0a2016-07-01 14:48:11 -0700878 return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800879 }
880
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800881 private boolean isAnimationMaximizing() {
882 return mAnimationTarget == 0f;
883 }
884
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800885 public boolean animate(long now) {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700886 if (mWindow == null) {
887 return false;
888 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700889 if (mAnimatingForMinimizedDockedStack) {
890 return animateForMinimizedDockedStack(now);
lumarkbcc316e2018-12-25 21:37:05 +0800891 } else if (mAnimatingForIme && !mDisplayContent.mAppTransition.isRunning()) {
892 // To prevent task stack resize animation may flicking when playing app transition
893 // animation & IME window enter animation in parallel, make sure app transition is done
894 // and then start to animate for IME.
Jorim Jaggieb88d832016-04-13 20:17:43 -0700895 return animateForIme(now);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800896 }
Robert Carrf59b8dd2017-10-02 18:58:36 -0700897 return false;
Chong Zhangbaba7832016-03-24 10:21:26 -0700898 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800899
Jorim Jaggieb88d832016-04-13 20:17:43 -0700900 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700901 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700902 mAnimationStarted = true;
903 mAnimationStartTime = now;
904 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700905 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700906 }
907 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
908 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
909 .getInterpolation(t);
Wale Ogunwale10124582016-09-15 20:25:50 -0700910 final boolean updated =
911 mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700912 if (updated) {
913 mService.mWindowPlacerLocked.performSurfacePlacement();
914 }
915 if (t >= 1.0f) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700916 mLastAnimationProgress = mAnimationTarget;
917 mLastDividerProgress = mDividerAnimationTarget;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700918 mAnimatingForIme = false;
919 return false;
920 } else {
921 return true;
922 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700923 }
924
925 private boolean animateForMinimizedDockedStack(long now) {
Louis Changdc077272019-11-12 16:52:56 +0800926 final ActivityStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800927 if (!mAnimationStarted) {
928 mAnimationStarted = true;
929 mAnimationStartTime = now;
Matthew Nge15352e2016-12-20 15:36:29 -0800930 notifyDockedStackMinimizedChanged(mMinimizedDock, true /* animate */,
931 isHomeStackResizable() /* isHomeStackResizable */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800932 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800933 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
934 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
935 .getInterpolation(t);
Chong Zhang741c0ba2016-05-27 12:52:11 -0700936 if (stack != null) {
937 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
938 mService.mWindowPlacerLocked.performSurfacePlacement();
939 }
940 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800941 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700942 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800943 return false;
944 } else {
945 return true;
946 }
947 }
948
Wale Ogunwale10124582016-09-15 20:25:50 -0700949 float getInterpolatedAnimationValue(float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700950 return t * mAnimationTarget + (1 - t) * mAnimationStart;
951 }
952
Wale Ogunwale10124582016-09-15 20:25:50 -0700953 float getInterpolatedDividerValue(float t) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700954 return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
955 }
956
Jorim Jaggif97ed922016-02-18 18:57:07 -0800957 /**
958 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
959 */
Louis Changdc077272019-11-12 16:52:56 +0800960 private float getMinimizeAmount(ActivityStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700961 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800962 if (isAnimationMaximizing()) {
963 return adjustMaximizeAmount(stack, t, naturalAmount);
964 } else {
965 return naturalAmount;
966 }
967 }
968
969 /**
970 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
971 * during the transition such that the edge of the clip reveal rect is met earlier in the
972 * transition so we don't create a visible "hole", but only if both the clip reveal and the
973 * docked stack divider start from about the same portion on the screen.
974 */
Louis Changdc077272019-11-12 16:52:56 +0800975 private float adjustMaximizeAmount(ActivityStack stack, float t, float naturalAmount) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800976 if (mMaximizeMeetFraction == 1f) {
977 return naturalAmount;
978 }
979 final int minimizeDistance = stack.getMinimizeDistance();
lumark588a3e82018-07-20 18:53:54 +0800980 final float startPrime = mDisplayContent.mAppTransition.getLastClipRevealMaxTranslation()
Jorim Jaggif97ed922016-02-18 18:57:07 -0800981 / (float) minimizeDistance;
982 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
983 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
984 return amountPrime * t2 + naturalAmount * (1 - t2);
985 }
986
987 /**
988 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
989 * edge. See {@link #adjustMaximizeAmount}.
990 */
Louis Changdc077272019-11-12 16:52:56 +0800991 private float getClipRevealMeetFraction(ActivityStack stack) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800992 if (!isAnimationMaximizing() || stack == null ||
lumark588a3e82018-07-20 18:53:54 +0800993 !mDisplayContent.mAppTransition.hadClipRevealAnimation()) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800994 return 1f;
995 }
996 final int minimizeDistance = stack.getMinimizeDistance();
lumark588a3e82018-07-20 18:53:54 +0800997 final float fraction = Math.abs(mDisplayContent.mAppTransition
998 .getLastClipRevealMaxTranslation()) / (float) minimizeDistance;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800999 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
1000 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
1001 return CLIP_REVEAL_MEET_EARLIEST
1002 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
1003 }
1004
Jorim Jaggi50981592015-12-29 17:54:12 +01001005 public String toShortString() {
1006 return TAG;
1007 }
Robert Carre63e01a2016-04-18 20:27:34 -07001008
1009 WindowState getWindow() {
1010 return mWindow;
1011 }
Jorim Jaggi31f71702016-05-04 16:43:04 -07001012
1013 void dump(String prefix, PrintWriter pw) {
1014 pw.println(prefix + "DockedStackDividerController");
1015 pw.println(prefix + " mLastVisibility=" + mLastVisibility);
1016 pw.println(prefix + " mMinimizedDock=" + mMinimizedDock);
1017 pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme);
1018 pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider);
Jorim Jaggi31f71702016-05-04 16:43:04 -07001019 }
Steven Timotiusaf03df62017-07-18 16:56:43 -07001020
Jeffrey Huangcb782852019-12-05 11:28:11 -08001021 void dumpDebug(ProtoOutputStream proto, long fieldId) {
Steven Timotiusaf03df62017-07-18 16:56:43 -07001022 final long token = proto.start(fieldId);
1023 proto.write(MINIMIZED_DOCK, mMinimizedDock);
1024 proto.end(token);
1025 }
Robert Carre63e01a2016-04-18 20:27:34 -07001026}