blob: 1d76a71aaea17d79777569c7112bf02841365a47 [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;
Wale Ogunwalec69694a2016-10-18 13:51:15 -070039import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010040
Filip Gruszczynski466f3212015-09-21 17:57:57 -070041import android.content.Context;
Jorim Jaggi85639432016-05-06 17:27:55 -070042import android.content.res.Configuration;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070043import android.graphics.Rect;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010044import android.os.RemoteCallbackList;
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080045import android.os.RemoteException;
Jorim Jaggi936aaeb2016-08-26 19:02:11 -070046import android.util.ArraySet;
Filip Gruszczynski77049052015-11-09 14:01:21 -080047import android.util.Slog;
Steven Timotiusaf03df62017-07-18 16:56:43 -070048import android.util.proto.ProtoOutputStream;
Adrian Roos11c25582018-02-19 18:06:36 +010049import android.view.DisplayCutout;
Jorim Jaggi50981592015-12-29 17:54:12 +010050import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010051import android.view.IDockedStackListener;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080052import android.view.animation.AnimationUtils;
53import android.view.animation.Interpolator;
Jorim Jaggieb88d832016-04-13 20:17:43 -070054import android.view.animation.PathInterpolator;
Jorim Jaggi50981592015-12-29 17:54:12 +010055
Tiger Huang7c610aa2018-10-27 00:01:01 +080056import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggi85639432016-05-06 17:27:55 -070057import com.android.internal.policy.DividerSnapAlgorithm;
58import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070059import com.android.server.LocalServices;
Yohei Yukawac3de83e2018-08-28 16:09:34 -070060import com.android.server.inputmethod.InputMethodManagerInternal;
Jorim Jaggiff71d202016-04-14 13:12:36 -070061import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010062
Jorim Jaggi31f71702016-05-04 16:43:04 -070063import java.io.PrintWriter;
Chong Zhangbaba7832016-03-24 10:21:26 -070064
Filip Gruszczynski466f3212015-09-21 17:57:57 -070065/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010066 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070067 */
Robert Carrf59b8dd2017-10-02 18:58:36 -070068public class DockedStackDividerController {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010069
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080070 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010071
Jorim Jaggif97ed922016-02-18 18:57:07 -080072 /**
73 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
74 * revealing surface at the earliest.
75 */
76 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
77
78 /**
79 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
80 * revealing surface at the latest.
81 */
82 private static final float CLIP_REVEAL_MEET_LAST = 1f;
83
84 /**
85 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
86 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
87 */
88 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
89
90 /**
91 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
92 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
93 */
94 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
95
Jorim Jaggieb88d832016-04-13 20:17:43 -070096 private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
Jorim Jaggiff71d202016-04-14 13:12:36 -070097 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggieb88d832016-04-13 20:17:43 -070098
Jorim Jaggi698e7632016-04-13 21:02:22 -070099 private static final long IME_ADJUST_ANIM_DURATION = 280;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700100
Jorim Jaggiff71d202016-04-14 13:12:36 -0700101 private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
102
Chong Zhang198afac2016-04-15 12:03:11 -0700103 private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
104
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800105 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700106 private final DisplayContent mDisplayContent;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700107 private int mDividerWindowWidth;
Chong Zhang198afac2016-04-15 12:03:11 -0700108 private int mDividerWindowWidthInactive;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700109 private int mDividerInsets;
Matthew Nge15352e2016-12-20 15:36:29 -0800110 private int mTaskHeightInMinimizedMode;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100111 private boolean mResizing;
112 private WindowState mWindow;
113 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800114 private final Rect mTmpRect2 = new Rect();
Jorim Jaggi85639432016-05-06 17:27:55 -0700115 private final Rect mTmpRect3 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -0800116 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800117 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100118 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
119 = new RemoteCallbackList<>();
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700120
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800121 private boolean mMinimizedDock;
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700122 private int mOriginalDockedSide = DOCKED_INVALID;
Chong Zhangbaba7832016-03-24 10:21:26 -0700123 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800124 private boolean mAnimationStarted;
125 private long mAnimationStartTime;
126 private float mAnimationStart;
127 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800128 private long mAnimationDuration;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700129 private boolean mAnimationStartDelayed;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800130 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800131 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100132 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700133 private boolean mAnimatingForIme;
134 private boolean mAdjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700135 private int mImeHeight;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700136 private WindowState mDelayedImeWin;
Chong Zhangf347ab52016-04-18 21:02:01 -0700137 private boolean mAdjustedForDivider;
138 private float mDividerAnimationStart;
139 private float mDividerAnimationTarget;
Wale Ogunwale10124582016-09-15 20:25:50 -0700140 float mLastAnimationProgress;
141 float mLastDividerProgress;
Jorim Jaggi85639432016-05-06 17:27:55 -0700142 private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700143 private boolean mImeHideRequested;
Jorim Jaggif93ac2b2017-10-25 15:20:24 +0200144 private final Rect mLastDimLayerRect = new Rect();
145 private float mLastDimLayerAlpha;
Robert Carrf59b8dd2017-10-02 18:58:36 -0700146 private TaskStack mDimmedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800147
148 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
149 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700150 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800151 final Context context = service.mContext;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800152 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
153 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700154 loadDimens();
155 }
156
Jorim Jaggi85639432016-05-06 17:27:55 -0700157 int getSmallestWidthDpForBounds(Rect bounds) {
158 final DisplayInfo di = mDisplayContent.getDisplayInfo();
159
Jorim Jaggi85639432016-05-06 17:27:55 -0700160 final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
161 final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
162 int minWidth = Integer.MAX_VALUE;
163
164 // Go through all screen orientations and find the orientation in which the task has the
165 // smallest width.
166 for (int rotation = 0; rotation < 4; rotation++) {
167 mTmpRect.set(bounds);
168 mDisplayContent.rotateBounds(di.rotation, rotation, mTmpRect);
169 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
170 mTmpRect2.set(0, 0,
171 rotated ? baseDisplayHeight : baseDisplayWidth,
172 rotated ? baseDisplayWidth : baseDisplayHeight);
173 final int orientation = mTmpRect2.width() <= mTmpRect2.height()
174 ? ORIENTATION_PORTRAIT
175 : ORIENTATION_LANDSCAPE;
Evan Rosky39b6f232018-10-30 18:35:41 -0700176 final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation, rotation);
Jorim Jaggi85639432016-05-06 17:27:55 -0700177 final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
178 getContentWidth());
179
Adrian Roos2aa0fcd2018-02-19 18:07:49 +0100180 final DisplayCutout displayCutout = mDisplayContent.calculateDisplayCutoutForRotation(
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100181 rotation).getDisplayCutout();
Adrian Roos11c25582018-02-19 18:06:36 +0100182
Jorim Jaggi85639432016-05-06 17:27:55 -0700183 // Since we only care about feasible states, snap to the closest snap target, like it
184 // would happen when actually rotating the screen.
185 final int snappedPosition = mSnapAlgorithmForRotation[rotation]
186 .calculateNonDismissingSnapTarget(position).position;
187 DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, mTmpRect,
188 mTmpRect2.width(), mTmpRect2.height(), getContentWidth());
Tiger Huang7c610aa2018-10-27 00:01:01 +0800189 mDisplayContent.getDisplayPolicy().getStableInsetsLw(rotation, mTmpRect2.width(),
190 mTmpRect2.height(), displayCutout, mTmpRect3);
Winson Chungbdc646f2017-02-13 12:12:22 -0800191 mService.intersectDisplayInsetBounds(mTmpRect2, mTmpRect3, mTmpRect);
Jorim Jaggi85639432016-05-06 17:27:55 -0700192 minWidth = Math.min(mTmpRect.width(), minWidth);
193 }
194 return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
195 }
196
Matthew Ng62c78462018-04-09 14:43:21 -0700197 /**
198 * Get the current docked side. Determined by its location of {@param bounds} within
199 * {@param displayRect} but if both are the same, it will try to dock to each side and determine
200 * if allowed in its respected {@param orientation}.
201 *
202 * @param bounds bounds of the docked task to get which side is docked
203 * @param displayRect bounds of the display that contains the docked task
204 * @param orientation the origination of device
205 * @return current docked side
206 */
Evan Rosky39b6f232018-10-30 18:35:41 -0700207 int getDockSide(Rect bounds, Rect displayRect, int orientation, int rotation) {
Matthew Ng62c78462018-04-09 14:43:21 -0700208 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
209 // Portrait mode, docked either at the top or the bottom.
210 final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
211 if (diff > 0) {
212 return DOCKED_TOP;
213 } else if (diff < 0) {
214 return DOCKED_BOTTOM;
215 }
Evan Rosky39b6f232018-10-30 18:35:41 -0700216 return canPrimaryStackDockTo(DOCKED_TOP, displayRect, rotation)
217 ? DOCKED_TOP : DOCKED_BOTTOM;
Matthew Ng62c78462018-04-09 14:43:21 -0700218 } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
219 // Landscape mode, docked either on the left or on the right.
220 final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
221 if (diff > 0) {
222 return DOCKED_LEFT;
223 } else if (diff < 0) {
224 return DOCKED_RIGHT;
225 }
Evan Rosky39b6f232018-10-30 18:35:41 -0700226 return canPrimaryStackDockTo(DOCKED_LEFT, displayRect, rotation)
227 ? DOCKED_LEFT : DOCKED_RIGHT;
Matthew Ng62c78462018-04-09 14:43:21 -0700228 }
229 return DOCKED_INVALID;
230 }
231
Evan Roskyc5abbd82018-10-05 16:02:19 -0700232 void getHomeStackBoundsInDockedMode(Configuration parentConfig, int dockSide, Rect outBounds) {
233 final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout;
234 final int displayWidth = parentConfig.windowConfiguration.getBounds().width();
235 final int displayHeight = parentConfig.windowConfiguration.getBounds().height();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800236 mDisplayContent.getDisplayPolicy().getStableInsetsLw(
237 parentConfig.windowConfiguration.getRotation(), displayWidth, displayHeight,
238 displayCutout, mTmpRect);
Matthew Nge15352e2016-12-20 15:36:29 -0800239 int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
Matthew Nga9e173d2017-05-17 15:03:18 -0700240 // The offset in the left (landscape)/top (portrait) is calculated with the minimized
241 // offset value with the divider size and any system insets in that direction.
Evan Roskyc5abbd82018-10-05 16:02:19 -0700242 if (parentConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
Matthew Nge15352e2016-12-20 15:36:29 -0800243 outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
Evan Roskyc5abbd82018-10-05 16:02:19 -0700244 displayWidth, displayHeight);
Matthew Nge15352e2016-12-20 15:36:29 -0800245 } else {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800246 // In landscape also inset the left/right side with the status bar height to match the
Matthew Nga9e173d2017-05-17 15:03:18 -0700247 // minimized size height in portrait mode.
Matthew Ng62c78462018-04-09 14:43:21 -0700248 final int primaryTaskWidth = mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top;
249 int left = mTmpRect.left;
Evan Roskyc5abbd82018-10-05 16:02:19 -0700250 int right = displayWidth - mTmpRect.right;
251 if (dockSide == DOCKED_LEFT) {
252 left += primaryTaskWidth;
253 } else if (dockSide == DOCKED_RIGHT) {
254 right -= primaryTaskWidth;
Matthew Ng62c78462018-04-09 14:43:21 -0700255 }
Evan Roskyc5abbd82018-10-05 16:02:19 -0700256 outBounds.set(left, 0, right, displayHeight);
Matthew Nge15352e2016-12-20 15:36:29 -0800257 }
258 }
259
260 boolean isHomeStackResizable() {
261 final TaskStack homeStack = mDisplayContent.getHomeStack();
262 if (homeStack == null) {
263 return false;
264 }
265 final Task homeTask = homeStack.findHomeTask();
266 return homeTask != null && homeTask.isResizeable();
267 }
268
Jorim Jaggi85639432016-05-06 17:27:55 -0700269 private void initSnapAlgorithmForRotations() {
Andrii Kulian441e4492016-09-29 15:25:00 -0700270 final Configuration baseConfig = mDisplayContent.getConfiguration();
Jorim Jaggi85639432016-05-06 17:27:55 -0700271
272 // Initialize the snap algorithms for all 4 screen orientations.
273 final Configuration config = new Configuration();
274 for (int rotation = 0; rotation < 4; rotation++) {
275 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
276 final int dw = rotated
277 ? mDisplayContent.mBaseDisplayHeight
278 : mDisplayContent.mBaseDisplayWidth;
279 final int dh = rotated
280 ? mDisplayContent.mBaseDisplayWidth
281 : mDisplayContent.mBaseDisplayHeight;
Adrian Roos11c25582018-02-19 18:06:36 +0100282 final DisplayCutout displayCutout =
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100283 mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800284 final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
285 displayPolicy.getStableInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
Andrii Kulianb10330d2016-09-16 13:51:46 -0700286 config.unset();
Jorim Jaggi85639432016-05-06 17:27:55 -0700287 config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
Bryce Lee7566d762017-03-30 09:34:15 -0700288
Tiger Huang7c610aa2018-10-27 00:01:01 +0800289 final int appWidth = displayPolicy.getNonDecorDisplayWidth(dw, dh, rotation,
290 baseConfig.uiMode, displayCutout);
291 final int appHeight = displayPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
292 baseConfig.uiMode, displayCutout);
293 displayPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
Bryce Lee7566d762017-03-30 09:34:15 -0700294 final int leftInset = mTmpRect.left;
295 final int topInset = mTmpRect.top;
296
Wale Ogunwale822e5122017-07-26 06:02:24 -0700297 config.windowConfiguration.setAppBounds(leftInset /*left*/, topInset /*top*/,
298 leftInset + appWidth /*right*/, topInset + appHeight /*bottom*/);
Bryce Lee7566d762017-03-30 09:34:15 -0700299
Adrian Roos11c25582018-02-19 18:06:36 +0100300 final float density = mDisplayContent.getDisplayMetrics().density;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800301 config.screenWidthDp = (int) (displayPolicy.getConfigDisplayWidth(dw, dh, rotation,
302 baseConfig.uiMode, displayCutout) / density);
303 config.screenHeightDp = (int) (displayPolicy.getConfigDisplayHeight(dw, dh, rotation,
304 baseConfig.uiMode, displayCutout) / density);
Jorim Jaggi85639432016-05-06 17:27:55 -0700305 final Context rotationContext = mService.mContext.createConfigurationContext(config);
306 mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
307 rotationContext.getResources(), dw, dh, getContentWidth(),
308 config.orientation == ORIENTATION_PORTRAIT, mTmpRect);
309 }
310 }
311
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700312 private void loadDimens() {
313 final Context context = mService.mContext;
314 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
315 com.android.internal.R.dimen.docked_stack_divider_thickness);
316 mDividerInsets = context.getResources().getDimensionPixelSize(
317 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700318 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
319 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Matthew Nge15352e2016-12-20 15:36:29 -0800320 mTaskHeightInMinimizedMode = context.getResources().getDimensionPixelSize(
321 com.android.internal.R.dimen.task_height_of_minimized_mode);
Jorim Jaggi85639432016-05-06 17:27:55 -0700322 initSnapAlgorithmForRotations();
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700323 }
324
325 void onConfigurationChanged() {
326 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700327 }
328
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100329 boolean isResizing() {
330 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700331 }
332
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100333 int getContentWidth() {
334 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700335 }
336
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800337 int getContentInsets() {
338 return mDividerInsets;
339 }
340
Chong Zhang198afac2016-04-15 12:03:11 -0700341 int getContentWidthInactive() {
342 return mDividerWindowWidthInactive;
343 }
344
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100345 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800346 if (mResizing != resizing) {
347 mResizing = resizing;
348 resetDragResizingChangeReported();
349 }
350 }
351
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100352 void setTouchRegion(Rect touchRegion) {
353 mTouchRegion.set(touchRegion);
354 }
355
356 void getTouchRegion(Rect outRegion) {
357 outRegion.set(mTouchRegion);
358 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
359 }
360
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800361 private void resetDragResizingChangeReported() {
Wale Ogunwaled1880962016-11-08 10:31:59 -0800362 mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
363 true /* traverseTopToBottom */ );
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100364 }
365
366 void setWindow(WindowState window) {
367 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800368 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100369 }
370
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800371 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800372 if (mWindow == null) {
373 return;
374 }
Matthew Ng64e77cf2017-10-31 14:01:31 -0700375 TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Jorim Jaggi7998e482016-02-12 18:47:06 -0800376
377 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
378 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800379 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800380 return;
381 }
382 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100383 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100384 if (!visible) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700385 setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f);
Jorim Jaggi50981592015-12-29 17:54:12 +0100386 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100387 }
388
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700389 private boolean wasVisible() {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100390 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100391 }
392
Chong Zhangf347ab52016-04-18 21:02:01 -0700393 void setAdjustedForIme(
394 boolean adjustedForIme, boolean adjustedForDivider,
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700395 boolean animate, WindowState imeWin, int imeHeight) {
396 if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
397 || mAdjustedForDivider != adjustedForDivider) {
Jorim Jaggi3070e772016-05-17 16:41:32 -0700398 if (animate && !mAnimatingForMinimizedDockedStack) {
lumarkbcc316e2018-12-25 21:37:05 +0800399 // Notify SystemUI to set the target docked stack size according current docked
400 // state without animation when calling startImeAdjustAnimation.
401 notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
402 isHomeStackResizable());
Chong Zhangf347ab52016-04-18 21:02:01 -0700403 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700404 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700405 // Animation might be delayed, so only notify if we don't run an animation.
Chong Zhangf347ab52016-04-18 21:02:01 -0700406 notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700407 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700408 mAdjustedForIme = adjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700409 mImeHeight = imeHeight;
Chong Zhangf347ab52016-04-18 21:02:01 -0700410 mAdjustedForDivider = adjustedForDivider;
Chong Zhangbaba7832016-03-24 10:21:26 -0700411 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700412 }
413
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700414 int getImeHeightAdjustedFor() {
415 return mImeHeight;
416 }
417
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700418 void positionDockedStackedDivider(Rect frame) {
Matthew Ng0808af32018-05-07 12:11:13 -0700419 TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700420 if (stack == null) {
421 // Unfortunately we might end up with still having a divider, even though the underlying
422 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800423 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
424 // keep putting it in the same place it was before the stack was removed to have
425 // continuity and prevent it from jumping to the center. It will get hidden soon.
426 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700427 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800428 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800429 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700430 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100431 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700432 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700433 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100434 frame.set(mTmpRect.right - mDividerInsets, frame.top,
435 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700436 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700437 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100438 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
439 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700440 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700441 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100442 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
443 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700444 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700445 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100446 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
447 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700448 break;
449 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800450 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700451 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800452
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700453 private void notifyDockedDividerVisibilityChanged(boolean visible) {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100454 final int size = mDockedStackListeners.beginBroadcast();
455 for (int i = 0; i < size; ++i) {
456 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
457 try {
458 listener.onDividerVisibilityChanged(visible);
459 } catch (RemoteException e) {
460 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
461 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800462 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100463 mDockedStackListeners.finishBroadcast();
464 }
465
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700466 /**
467 * Checks if the primary stack is allowed to dock to a specific side based on its original dock
468 * side.
469 *
470 * @param dockSide the side to see if it is valid
471 * @return true if the side provided is valid
472 */
Evan Rosky39b6f232018-10-30 18:35:41 -0700473 boolean canPrimaryStackDockTo(int dockSide, Rect parentRect, int rotation) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800474 final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
475 return isDockSideAllowed(dockSide, mOriginalDockedSide,
476 policy.navigationBarPosition(parentRect.width(), parentRect.height(), rotation),
477 policy.navigationBarCanMove());
478 }
479
480 @VisibleForTesting
481 static boolean isDockSideAllowed(int dockSide, int originalDockSide, int navBarPosition,
482 boolean navigationBarCanMove) {
483 if (dockSide == DOCKED_TOP) {
484 return true;
485 }
486
487 if (navigationBarCanMove) {
488 // Only allow the dockside opposite to the nav bar position in landscape
489 return dockSide == DOCKED_LEFT && navBarPosition == NAV_BAR_RIGHT
490 || dockSide == DOCKED_RIGHT && navBarPosition == NAV_BAR_LEFT;
491 }
492
493 // Side is the same as original side
494 if (dockSide == originalDockSide) {
495 return true;
496 }
497
498 // Only if original docked side was top in portrait will allow left for landscape
499 return dockSide == DOCKED_LEFT && originalDockSide == DOCKED_TOP;
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700500 }
501
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100502 void notifyDockedStackExistsChanged(boolean exists) {
Andrii Kulian5406e7a2016-10-21 11:55:23 -0700503 // TODO(multi-display): Perform all actions only for current display.
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100504 final int size = mDockedStackListeners.beginBroadcast();
505 for (int i = 0; i < size; ++i) {
506 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
507 try {
508 listener.onDockedStackExistsChanged(exists);
509 } catch (RemoteException e) {
510 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
511 }
512 }
513 mDockedStackListeners.finishBroadcast();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700514 if (exists) {
515 InputMethodManagerInternal inputMethodManagerInternal =
516 LocalServices.getService(InputMethodManagerInternal.class);
517 if (inputMethodManagerInternal != null) {
518
519 // Hide the current IME to avoid problems with animations from IME adjustment when
520 // attaching the docked stack.
521 inputMethodManagerInternal.hideCurrentInputMethod();
522 mImeHideRequested = true;
523 }
Matthew Nge8b052a2018-01-16 14:33:47 -0800524
525 // If a primary stack was just created, it will not have access to display content at
526 // this point so pass it from here to get a valid dock side.
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700527 final TaskStack stack = 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) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700562 final TaskStack 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 }
Yunfan Chencafc7062019-01-22 17:21:32 +0900572 mService.mAtmInternal.notifyDockedStackMinimizedChanged(minimizedDock);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800573 final int size = mDockedStackListeners.beginBroadcast();
574 for (int i = 0; i < size; ++i) {
575 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
576 try {
Matthew Nge15352e2016-12-20 15:36:29 -0800577 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration,
578 isHomeStackResizable);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800579 } catch (RemoteException e) {
580 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
581 }
582 }
583 mDockedStackListeners.finishBroadcast();
584 }
585
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700586 void notifyDockSideChanged(int newDockSide) {
587 final int size = mDockedStackListeners.beginBroadcast();
588 for (int i = 0; i < size; ++i) {
589 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
590 try {
591 listener.onDockSideChanged(newDockSide);
592 } catch (RemoteException e) {
593 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
594 }
595 }
596 mDockedStackListeners.finishBroadcast();
597 }
598
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700599 private void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
Jorim Jaggi698e7632016-04-13 21:02:22 -0700600 final int size = mDockedStackListeners.beginBroadcast();
601 for (int i = 0; i < size; ++i) {
602 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
603 try {
604 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
605 } catch (RemoteException e) {
606 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
607 }
608 }
609 mDockedStackListeners.finishBroadcast();
610 }
611
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100612 void registerDockedStackListener(IDockedStackListener listener) {
613 mDockedStackListeners.register(listener);
614 notifyDockedDividerVisibilityChanged(wasVisible());
Wale Ogunwale61911492017-10-11 08:50:50 -0700615 notifyDockedStackExistsChanged(
Matthew Ng64e77cf2017-10-31 14:01:31 -0700616 mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null);
Matthew Nge15352e2016-12-20 15:36:29 -0800617 notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
618 isHomeStackResizable());
Jorim Jaggi698e7632016-04-13 21:02:22 -0700619 notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
620
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800621 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100622
Wale Ogunwale68278562017-09-23 17:13:55 -0700623 /**
624 * Shows a dim layer with {@param alpha} if {@param visible} is true and
625 * {@param targetWindowingMode} isn't
626 * {@link android.app.WindowConfiguration#WINDOWING_MODE_UNDEFINED} and there is a stack on the
627 * display in that windowing mode.
628 */
629 void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700630 // TODO: Maybe only allow split-screen windowing modes?
631 final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800632 ? mDisplayContent.getTopStackInWindowingMode(targetWindowingMode)
Wale Ogunwale68278562017-09-23 17:13:55 -0700633 : null;
Matthew Ng64e77cf2017-10-31 14:01:31 -0700634 final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStack();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100635 boolean visibleAndValid = visible && stack != null && dockedStack != null;
chaviw783729c2018-01-25 15:14:10 -0800636
637 // Ensure an old dim that was shown for the docked stack divider is removed so we don't end
638 // up with dim layers that can no longer be removed.
639 if (mDimmedStack != null && mDimmedStack != stack) {
640 mDimmedStack.stopDimming();
641 mDimmedStack = null;
642 }
643
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100644 if (visibleAndValid) {
Robert Carrf59b8dd2017-10-02 18:58:36 -0700645 mDimmedStack = stack;
646 stack.dim(alpha);
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100647 }
Robert Carrf59b8dd2017-10-02 18:58:36 -0700648 if (!visibleAndValid && stack != null) {
649 mDimmedStack = null;
650 stack.stopDimming();
Jorim Jaggi50981592015-12-29 17:54:12 +0100651 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100652 }
653
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800654 /**
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700655 * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
656 * above all application surfaces.
657 */
658 private int getResizeDimLayer() {
659 return (mWindow != null) ? mWindow.mLayer - 1 : LAYER_OFFSET_DIM;
660 }
661
662 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800663 * Notifies the docked stack divider controller of a visibility change that happens without
664 * an animation.
665 */
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700666 void notifyAppVisibilityChanged() {
667 checkMinimizeChanged(false /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800668 }
669
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200670 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps, int appTransition) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700671 final boolean wasMinimized = mMinimizedDock;
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700672 checkMinimizeChanged(true /* animate */);
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700673
674 // We were minimized, and now we are still minimized, but somebody is trying to launch an
Matthew Ng8e265522017-02-13 11:09:37 -0800675 // app in docked stack, better show recent apps so we actually get unminimized! However do
676 // not do this if keyguard is dismissed such as when the device is unlocking. This catches
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700677 // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
678 // we couldn't retrace the launch of the app in the docked stack to the launch from
679 // homescreen.
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200680 if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
Matthew Ng8e265522017-02-13 11:09:37 -0800681 && appTransition != TRANSIT_NONE &&
682 !AppTransition.isKeyguardGoingAwayTransit(appTransition)) {
Wale Ogunwale6767eae2018-05-03 15:52:51 -0700683 if (mService.mAtmInternal.isRecentsComponentHomeActivity(mService.mCurrentUserId)) {
Winson Chungc1674272018-02-21 10:15:17 -0800684 // When the home activity is the recents component and we are already minimized,
685 // then there is nothing to do here since home is already visible
686 } else {
687 mService.showRecentApps();
688 }
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700689 }
690 }
691
692 /**
693 * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
694 */
695 private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
696 for (int i = apps.size() - 1; i >= 0; i--) {
697 final AppWindowToken token = apps.valueAt(i);
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700698 if (token.getTask() != null && token.inSplitScreenPrimaryWindowingMode()) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700699 return true;
700 }
701 }
702 return false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800703 }
704
Jorim Jaggi1ae68bf2016-05-09 18:44:34 -0700705 boolean isMinimizedDock() {
706 return mMinimizedDock;
707 }
708
Winson Chungc1674272018-02-21 10:15:17 -0800709 void checkMinimizeChanged(boolean animate) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700710 if (mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() == null) {
Jorim Jaggi817a5242016-05-06 15:45:00 -0700711 return;
712 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700713 final TaskStack homeStack = mDisplayContent.getHomeStack();
714 if (homeStack == null) {
715 return;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800716 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700717 final Task homeTask = homeStack.findHomeTask();
718 if (homeTask == null || !isWithinDisplay(homeTask)) {
719 return;
720 }
Matthew Ng8e265522017-02-13 11:09:37 -0800721
722 // Do not minimize when dock is already minimized while keyguard is showing and not
723 // occluded such as unlocking the screen
Adrian Roosb56b3c32018-05-17 17:32:26 +0200724 if (mMinimizedDock && mService.mKeyguardOrAodShowingOnDefaultDisplay) {
Matthew Ng8e265522017-02-13 11:09:37 -0800725 return;
726 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800727 final TaskStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700728 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Winson Chungf557c3b2018-03-16 10:55:20 -0700729 final RecentsAnimationController recentsAnim = mService.getRecentsAnimationController();
730 final boolean minimizedForRecentsAnimation = recentsAnim != null &&
731 recentsAnim.isSplitScreenMinimized();
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800732 boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
733 if (homeVisible && topSecondaryStack != null) {
734 // Home should only be considered visible if it is greater or equal to the top secondary
735 // stack in terms of z-order.
736 homeVisible = homeStack.compareTo(topSecondaryStack) >= 0;
737 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700738 setMinimizedDockedStack(homeVisible || minimizedForRecentsAnimation, animate);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800739 }
740
741 private boolean isWithinDisplay(Task task) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800742 task.getBounds(mTmpRect);
743 mDisplayContent.getBounds(mTmpRect2);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800744 return mTmpRect.intersect(mTmpRect2);
745 }
746
747 /**
748 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
749 * docked stack are heavily clipped so you can only see a minimal peek state.
750 *
751 * @param minimizedDock Whether the docked stack is currently minimized.
752 * @param animate Whether to animate the change.
753 */
754 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700755 final boolean wasMinimized = mMinimizedDock;
756 mMinimizedDock = minimizedDock;
Jorim Jaggi817a5242016-05-06 15:45:00 -0700757 if (minimizedDock == wasMinimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800758 return;
759 }
760
Chong Zhang22eff0a2016-07-01 14:48:11 -0700761 final boolean imeChanged = clearImeAdjustAnimation();
762 boolean minimizedChange = false;
Matthew Nge15352e2016-12-20 15:36:29 -0800763 if (isHomeStackResizable()) {
Winson Chungc1674272018-02-21 10:15:17 -0800764 notifyDockedStackMinimizedChanged(minimizedDock, animate,
Matthew Nge15352e2016-12-20 15:36:29 -0800765 true /* isHomeStackResizable */);
766 minimizedChange = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800767 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800768 if (minimizedDock) {
769 if (animate) {
770 startAdjustAnimation(0f, 1f);
771 } else {
772 minimizedChange |= setMinimizedDockedStack(true);
773 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800774 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800775 if (animate) {
776 startAdjustAnimation(1f, 0f);
777 } else {
778 minimizedChange |= setMinimizedDockedStack(false);
779 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800780 }
781 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700782 if (imeChanged || minimizedChange) {
783 if (imeChanged && !minimizedChange) {
784 Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing,"
785 + " minimizedDock=" + minimizedDock
786 + " minimizedChange=" + minimizedChange);
787 }
788 mService.mWindowPlacerLocked.performSurfacePlacement();
789 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800790 }
791
Chong Zhang22eff0a2016-07-01 14:48:11 -0700792 private boolean clearImeAdjustAnimation() {
Wale Ogunwale10124582016-09-15 20:25:50 -0700793 final boolean changed = mDisplayContent.clearImeAdjustAnimation();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700794 mAnimatingForIme = false;
Chong Zhang22eff0a2016-07-01 14:48:11 -0700795 return changed;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700796 }
797
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800798 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700799 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800800 mAnimationStarted = false;
801 mAnimationStart = from;
802 mAnimationTarget = to;
803 }
804
Chong Zhangf347ab52016-04-18 21:02:01 -0700805 private void startImeAdjustAnimation(
806 boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700807
808 // If we're not in an animation, the starting point depends on whether we're adjusted
809 // or not. If we're already in an animation, we start from where the current animation
810 // left off, so that the motion doesn't look discontinuous.
811 if (!mAnimatingForIme) {
812 mAnimationStart = mAdjustedForIme ? 1 : 0;
813 mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
814 mLastAnimationProgress = mAnimationStart;
815 mLastDividerProgress = mDividerAnimationStart;
816 } else {
817 mAnimationStart = mLastAnimationProgress;
818 mDividerAnimationStart = mLastDividerProgress;
819 }
Jorim Jaggi3070e772016-05-17 16:41:32 -0700820 mAnimatingForIme = true;
821 mAnimationStarted = false;
Chong Zhangf347ab52016-04-18 21:02:01 -0700822 mAnimationTarget = adjustedForIme ? 1 : 0;
823 mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700824
Wale Ogunwale10124582016-09-15 20:25:50 -0700825 mDisplayContent.beginImeAdjustAnimation();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700826
827 // We put all tasks into drag resizing mode - wait until all of them have completed the
828 // drag resizing switch.
829 if (!mService.mWaitingForDrawn.isEmpty()) {
830 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
831 mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
832 IME_ADJUST_DRAWN_TIMEOUT);
833 mAnimationStartDelayed = true;
834 if (imeWin != null) {
835
836 // There might be an old window delaying the animation start - clear it.
837 if (mDelayedImeWin != null) {
Jorim Jaggia5e10572017-11-15 14:36:26 +0100838 mDelayedImeWin.endDelayingAnimationStart();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700839 }
840 mDelayedImeWin = imeWin;
Jorim Jaggia5e10572017-11-15 14:36:26 +0100841 imeWin.startDelayingAnimationStart();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700842 }
Jorim Jaggi31883862016-11-04 15:45:30 -0700843
844 // If we are already waiting for something to be drawn, clear out the old one so it
845 // still gets executed.
846 // TODO: Have a real system where we can wait on different windows to be drawn with
847 // different callbacks.
848 if (mService.mWaitingForDrawnCallback != null) {
849 mService.mWaitingForDrawnCallback.run();
850 }
Jorim Jaggiff71d202016-04-14 13:12:36 -0700851 mService.mWaitingForDrawnCallback = () -> {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700852 synchronized (mService.mGlobalLock) {
Jorim Jaggia5e10572017-11-15 14:36:26 +0100853 mAnimationStartDelayed = false;
854 if (mDelayedImeWin != null) {
855 mDelayedImeWin.endDelayingAnimationStart();
856 }
857 // If the adjust status changed since this was posted, only notify
858 // the new states and don't animate.
859 long duration = 0;
860 if (mAdjustedForIme == adjustedForIme
861 && mAdjustedForDivider == adjustedForDivider) {
862 duration = IME_ADJUST_ANIM_DURATION;
863 } else {
864 Slog.w(TAG, "IME adjust changed while waiting for drawn:"
865 + " adjustedForIme=" + adjustedForIme
866 + " adjustedForDivider=" + adjustedForDivider
867 + " mAdjustedForIme=" + mAdjustedForIme
868 + " mAdjustedForDivider=" + mAdjustedForDivider);
869 }
870 notifyAdjustedForImeChanged(
871 mAdjustedForIme || mAdjustedForDivider, duration);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700872 }
Jorim Jaggiff71d202016-04-14 13:12:36 -0700873 };
874 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700875 notifyAdjustedForImeChanged(
876 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700877 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700878 }
879
Chong Zhang22eff0a2016-07-01 14:48:11 -0700880 private boolean setMinimizedDockedStack(boolean minimized) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700881 final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Matthew Nge15352e2016-12-20 15:36:29 -0800882 notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
Chong Zhang22eff0a2016-07-01 14:48:11 -0700883 return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800884 }
885
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800886 private boolean isAnimationMaximizing() {
887 return mAnimationTarget == 0f;
888 }
889
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800890 public boolean animate(long now) {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700891 if (mWindow == null) {
892 return false;
893 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700894 if (mAnimatingForMinimizedDockedStack) {
895 return animateForMinimizedDockedStack(now);
lumarkbcc316e2018-12-25 21:37:05 +0800896 } else if (mAnimatingForIme && !mDisplayContent.mAppTransition.isRunning()) {
897 // To prevent task stack resize animation may flicking when playing app transition
898 // animation & IME window enter animation in parallel, make sure app transition is done
899 // and then start to animate for IME.
Jorim Jaggieb88d832016-04-13 20:17:43 -0700900 return animateForIme(now);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800901 }
Robert Carrf59b8dd2017-10-02 18:58:36 -0700902 return false;
Chong Zhangbaba7832016-03-24 10:21:26 -0700903 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800904
Jorim Jaggieb88d832016-04-13 20:17:43 -0700905 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700906 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700907 mAnimationStarted = true;
908 mAnimationStartTime = now;
909 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700910 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700911 }
912 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
913 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
914 .getInterpolation(t);
Wale Ogunwale10124582016-09-15 20:25:50 -0700915 final boolean updated =
916 mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700917 if (updated) {
918 mService.mWindowPlacerLocked.performSurfacePlacement();
919 }
920 if (t >= 1.0f) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700921 mLastAnimationProgress = mAnimationTarget;
922 mLastDividerProgress = mDividerAnimationTarget;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700923 mAnimatingForIme = false;
924 return false;
925 } else {
926 return true;
927 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700928 }
929
930 private boolean animateForMinimizedDockedStack(long now) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700931 final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800932 if (!mAnimationStarted) {
933 mAnimationStarted = true;
934 mAnimationStartTime = now;
Matthew Nge15352e2016-12-20 15:36:29 -0800935 notifyDockedStackMinimizedChanged(mMinimizedDock, true /* animate */,
936 isHomeStackResizable() /* isHomeStackResizable */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800937 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800938 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
939 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
940 .getInterpolation(t);
Chong Zhang741c0ba2016-05-27 12:52:11 -0700941 if (stack != null) {
942 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
943 mService.mWindowPlacerLocked.performSurfacePlacement();
944 }
945 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800946 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700947 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800948 return false;
949 } else {
950 return true;
951 }
952 }
953
Wale Ogunwale10124582016-09-15 20:25:50 -0700954 float getInterpolatedAnimationValue(float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700955 return t * mAnimationTarget + (1 - t) * mAnimationStart;
956 }
957
Wale Ogunwale10124582016-09-15 20:25:50 -0700958 float getInterpolatedDividerValue(float t) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700959 return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
960 }
961
Jorim Jaggif97ed922016-02-18 18:57:07 -0800962 /**
963 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
964 */
965 private float getMinimizeAmount(TaskStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700966 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800967 if (isAnimationMaximizing()) {
968 return adjustMaximizeAmount(stack, t, naturalAmount);
969 } else {
970 return naturalAmount;
971 }
972 }
973
974 /**
975 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
976 * during the transition such that the edge of the clip reveal rect is met earlier in the
977 * transition so we don't create a visible "hole", but only if both the clip reveal and the
978 * docked stack divider start from about the same portion on the screen.
979 */
980 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
981 if (mMaximizeMeetFraction == 1f) {
982 return naturalAmount;
983 }
984 final int minimizeDistance = stack.getMinimizeDistance();
lumark588a3e82018-07-20 18:53:54 +0800985 final float startPrime = mDisplayContent.mAppTransition.getLastClipRevealMaxTranslation()
Jorim Jaggif97ed922016-02-18 18:57:07 -0800986 / (float) minimizeDistance;
987 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
988 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
989 return amountPrime * t2 + naturalAmount * (1 - t2);
990 }
991
992 /**
993 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
994 * edge. See {@link #adjustMaximizeAmount}.
995 */
996 private float getClipRevealMeetFraction(TaskStack stack) {
997 if (!isAnimationMaximizing() || stack == null ||
lumark588a3e82018-07-20 18:53:54 +0800998 !mDisplayContent.mAppTransition.hadClipRevealAnimation()) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800999 return 1f;
1000 }
1001 final int minimizeDistance = stack.getMinimizeDistance();
lumark588a3e82018-07-20 18:53:54 +08001002 final float fraction = Math.abs(mDisplayContent.mAppTransition
1003 .getLastClipRevealMaxTranslation()) / (float) minimizeDistance;
Jorim Jaggif97ed922016-02-18 18:57:07 -08001004 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
1005 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
1006 return CLIP_REVEAL_MEET_EARLIEST
1007 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
1008 }
1009
Jorim Jaggi50981592015-12-29 17:54:12 +01001010 public String toShortString() {
1011 return TAG;
1012 }
Robert Carre63e01a2016-04-18 20:27:34 -07001013
1014 WindowState getWindow() {
1015 return mWindow;
1016 }
Jorim Jaggi31f71702016-05-04 16:43:04 -07001017
1018 void dump(String prefix, PrintWriter pw) {
1019 pw.println(prefix + "DockedStackDividerController");
1020 pw.println(prefix + " mLastVisibility=" + mLastVisibility);
1021 pw.println(prefix + " mMinimizedDock=" + mMinimizedDock);
1022 pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme);
1023 pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider);
Jorim Jaggi31f71702016-05-04 16:43:04 -07001024 }
Steven Timotiusaf03df62017-07-18 16:56:43 -07001025
1026 void writeToProto(ProtoOutputStream proto, long fieldId) {
1027 final long token = proto.start(fieldId);
1028 proto.write(MINIMIZED_DOCK, mMinimizedDock);
1029 proto.end(token);
1030 }
Robert Carre63e01a2016-04-18 20:27:34 -07001031}