blob: cd8d677c306c599ff3c8c2a35be47dd6bda3619a [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;
30import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
31import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010032import static android.view.WindowManager.TRANSIT_NONE;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010033import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
34import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Tony Mak853304c2016-04-18 15:17:41 +010035import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
Wale Ogunwalec69694a2016-10-18 13:51:15 -070036import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070037import static com.android.server.wm.DockedStackDividerControllerProto.MINIMIZED_DOCK;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010038
Filip Gruszczynski466f3212015-09-21 17:57:57 -070039import android.content.Context;
Jorim Jaggi85639432016-05-06 17:27:55 -070040import android.content.res.Configuration;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070041import android.graphics.Rect;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010042import android.os.RemoteCallbackList;
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080043import android.os.RemoteException;
Jorim Jaggi936aaeb2016-08-26 19:02:11 -070044import android.util.ArraySet;
Filip Gruszczynski77049052015-11-09 14:01:21 -080045import android.util.Slog;
Steven Timotiusaf03df62017-07-18 16:56:43 -070046import android.util.proto.ProtoOutputStream;
Adrian Roos11c25582018-02-19 18:06:36 +010047import android.view.DisplayCutout;
Jorim Jaggi50981592015-12-29 17:54:12 +010048import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010049import android.view.IDockedStackListener;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080050import android.view.animation.AnimationUtils;
51import android.view.animation.Interpolator;
Jorim Jaggieb88d832016-04-13 20:17:43 -070052import android.view.animation.PathInterpolator;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070053import android.view.inputmethod.InputMethodManagerInternal;
Jorim Jaggi50981592015-12-29 17:54:12 +010054
Jorim Jaggi85639432016-05-06 17:27:55 -070055import com.android.internal.policy.DividerSnapAlgorithm;
56import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070057import com.android.server.LocalServices;
Jorim Jaggiff71d202016-04-14 13:12:36 -070058import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010059
Jorim Jaggi31f71702016-05-04 16:43:04 -070060import java.io.PrintWriter;
Chong Zhangbaba7832016-03-24 10:21:26 -070061
Filip Gruszczynski466f3212015-09-21 17:57:57 -070062/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010063 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070064 */
Robert Carrf59b8dd2017-10-02 18:58:36 -070065public class DockedStackDividerController {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010066
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080067 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010068
Jorim Jaggif97ed922016-02-18 18:57:07 -080069 /**
70 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
71 * revealing surface at the earliest.
72 */
73 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
74
75 /**
76 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
77 * revealing surface at the latest.
78 */
79 private static final float CLIP_REVEAL_MEET_LAST = 1f;
80
81 /**
82 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
83 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
84 */
85 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
86
87 /**
88 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
89 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
90 */
91 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
92
Jorim Jaggieb88d832016-04-13 20:17:43 -070093 private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
Jorim Jaggiff71d202016-04-14 13:12:36 -070094 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggieb88d832016-04-13 20:17:43 -070095
Jorim Jaggi698e7632016-04-13 21:02:22 -070096 private static final long IME_ADJUST_ANIM_DURATION = 280;
Jorim Jaggieb88d832016-04-13 20:17:43 -070097
Jorim Jaggiff71d202016-04-14 13:12:36 -070098 private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
99
Chong Zhang198afac2016-04-15 12:03:11 -0700100 private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
101
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800102 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700103 private final DisplayContent mDisplayContent;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700104 private int mDividerWindowWidth;
Chong Zhang198afac2016-04-15 12:03:11 -0700105 private int mDividerWindowWidthInactive;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700106 private int mDividerInsets;
Matthew Nge15352e2016-12-20 15:36:29 -0800107 private int mTaskHeightInMinimizedMode;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100108 private boolean mResizing;
109 private WindowState mWindow;
110 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800111 private final Rect mTmpRect2 = new Rect();
Jorim Jaggi85639432016-05-06 17:27:55 -0700112 private final Rect mTmpRect3 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -0800113 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800114 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100115 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
116 = new RemoteCallbackList<>();
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700117
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800118 private boolean mMinimizedDock;
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700119 private int mOriginalDockedSide = DOCKED_INVALID;
Chong Zhangbaba7832016-03-24 10:21:26 -0700120 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800121 private boolean mAnimationStarted;
122 private long mAnimationStartTime;
123 private float mAnimationStart;
124 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800125 private long mAnimationDuration;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700126 private boolean mAnimationStartDelayed;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800127 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800128 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100129 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700130 private boolean mAnimatingForIme;
131 private boolean mAdjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700132 private int mImeHeight;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700133 private WindowState mDelayedImeWin;
Chong Zhangf347ab52016-04-18 21:02:01 -0700134 private boolean mAdjustedForDivider;
135 private float mDividerAnimationStart;
136 private float mDividerAnimationTarget;
Wale Ogunwale10124582016-09-15 20:25:50 -0700137 float mLastAnimationProgress;
138 float mLastDividerProgress;
Jorim Jaggi85639432016-05-06 17:27:55 -0700139 private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700140 private boolean mImeHideRequested;
Jorim Jaggif93ac2b2017-10-25 15:20:24 +0200141 private final Rect mLastDimLayerRect = new Rect();
142 private float mLastDimLayerAlpha;
Robert Carrf59b8dd2017-10-02 18:58:36 -0700143 private TaskStack 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;
Matthew Ng62c78462018-04-09 14:43:21 -0700173 final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation);
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());
186 mService.mPolicy.getStableInsetsLw(rotation, mTmpRect2.width(), mTmpRect2.height(),
Adrian Roos11c25582018-02-19 18:06:36 +0100187 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 */
204 int getDockSide(Rect bounds, Rect displayRect, int orientation) {
205 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 }
213 return canPrimaryStackDockTo(DOCKED_TOP) ? DOCKED_TOP : DOCKED_BOTTOM;
214 } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
215 // Landscape mode, docked either on the left or on the right.
216 final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
217 if (diff > 0) {
218 return DOCKED_LEFT;
219 } else if (diff < 0) {
220 return DOCKED_RIGHT;
221 }
222 return canPrimaryStackDockTo(DOCKED_LEFT) ? DOCKED_LEFT : DOCKED_RIGHT;
223 }
224 return DOCKED_INVALID;
225 }
226
Matthew Nge15352e2016-12-20 15:36:29 -0800227 void getHomeStackBoundsInDockedMode(Rect outBounds) {
228 final DisplayInfo di = mDisplayContent.getDisplayInfo();
229 mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
Adrian Roos11c25582018-02-19 18:06:36 +0100230 di.displayCutout, mTmpRect);
Matthew Nge15352e2016-12-20 15:36:29 -0800231 int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
232 Configuration configuration = mDisplayContent.getConfiguration();
Matthew Nga9e173d2017-05-17 15:03:18 -0700233 // The offset in the left (landscape)/top (portrait) is calculated with the minimized
234 // offset value with the divider size and any system insets in that direction.
Matthew Nge15352e2016-12-20 15:36:29 -0800235 if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
236 outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
237 di.logicalWidth, di.logicalHeight);
238 } else {
Matthew Ng62c78462018-04-09 14:43:21 -0700239 // In landscape also inset the left/right side with the statusbar height to match the
Matthew Nga9e173d2017-05-17 15:03:18 -0700240 // minimized size height in portrait mode.
Matthew Ng62c78462018-04-09 14:43:21 -0700241 final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
242 final int primaryTaskWidth = mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top;
243 int left = mTmpRect.left;
244 int right = di.logicalWidth - mTmpRect.right;
245 if (stack != null) {
246 if (stack.getDockSide() == DOCKED_LEFT) {
247 left += primaryTaskWidth;
248 } else if (stack.getDockSide() == DOCKED_RIGHT) {
249 right -= primaryTaskWidth;
250 }
251 }
252 outBounds.set(left, 0, right, di.logicalHeight);
Matthew Nge15352e2016-12-20 15:36:29 -0800253 }
254 }
255
256 boolean isHomeStackResizable() {
257 final TaskStack homeStack = mDisplayContent.getHomeStack();
258 if (homeStack == null) {
259 return false;
260 }
261 final Task homeTask = homeStack.findHomeTask();
262 return homeTask != null && homeTask.isResizeable();
263 }
264
Jorim Jaggi85639432016-05-06 17:27:55 -0700265 private void initSnapAlgorithmForRotations() {
Andrii Kulian441e4492016-09-29 15:25:00 -0700266 final Configuration baseConfig = mDisplayContent.getConfiguration();
Jorim Jaggi85639432016-05-06 17:27:55 -0700267
268 // Initialize the snap algorithms for all 4 screen orientations.
269 final Configuration config = new Configuration();
270 for (int rotation = 0; rotation < 4; rotation++) {
271 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
272 final int dw = rotated
273 ? mDisplayContent.mBaseDisplayHeight
274 : mDisplayContent.mBaseDisplayWidth;
275 final int dh = rotated
276 ? mDisplayContent.mBaseDisplayWidth
277 : mDisplayContent.mBaseDisplayHeight;
Adrian Roos11c25582018-02-19 18:06:36 +0100278 final DisplayCutout displayCutout =
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100279 mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
Adrian Roos11c25582018-02-19 18:06:36 +0100280 mService.mPolicy.getStableInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
Andrii Kulianb10330d2016-09-16 13:51:46 -0700281 config.unset();
Jorim Jaggi85639432016-05-06 17:27:55 -0700282 config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
Bryce Lee7566d762017-03-30 09:34:15 -0700283
284 final int displayId = mDisplayContent.getDisplayId();
285 final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation,
Adrian Roos11c25582018-02-19 18:06:36 +0100286 baseConfig.uiMode, displayId, displayCutout);
Bryce Lee7566d762017-03-30 09:34:15 -0700287 final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
Adrian Roosbed538e2018-02-21 17:50:07 +0100288 baseConfig.uiMode, displayId, displayCutout);
Adrian Roos11c25582018-02-19 18:06:36 +0100289 mService.mPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
Bryce Lee7566d762017-03-30 09:34:15 -0700290 final int leftInset = mTmpRect.left;
291 final int topInset = mTmpRect.top;
292
Wale Ogunwale822e5122017-07-26 06:02:24 -0700293 config.windowConfiguration.setAppBounds(leftInset /*left*/, topInset /*top*/,
294 leftInset + appWidth /*right*/, topInset + appHeight /*bottom*/);
Bryce Lee7566d762017-03-30 09:34:15 -0700295
Adrian Roos11c25582018-02-19 18:06:36 +0100296 final float density = mDisplayContent.getDisplayMetrics().density;
297 config.screenWidthDp = (int) (mService.mPolicy.getConfigDisplayWidth(dw, dh,
298 rotation, baseConfig.uiMode, displayId, displayCutout) / density);
299 config.screenHeightDp = (int) (mService.mPolicy.getConfigDisplayHeight(dw, dh,
300 rotation, baseConfig.uiMode, displayId, displayCutout) / density);
Jorim Jaggi85639432016-05-06 17:27:55 -0700301 final Context rotationContext = mService.mContext.createConfigurationContext(config);
302 mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
303 rotationContext.getResources(), dw, dh, getContentWidth(),
304 config.orientation == ORIENTATION_PORTRAIT, mTmpRect);
305 }
306 }
307
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700308 private void loadDimens() {
309 final Context context = mService.mContext;
310 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
311 com.android.internal.R.dimen.docked_stack_divider_thickness);
312 mDividerInsets = context.getResources().getDimensionPixelSize(
313 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700314 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
315 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Matthew Nge15352e2016-12-20 15:36:29 -0800316 mTaskHeightInMinimizedMode = context.getResources().getDimensionPixelSize(
317 com.android.internal.R.dimen.task_height_of_minimized_mode);
Jorim Jaggi85639432016-05-06 17:27:55 -0700318 initSnapAlgorithmForRotations();
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700319 }
320
321 void onConfigurationChanged() {
322 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700323 }
324
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100325 boolean isResizing() {
326 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700327 }
328
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100329 int getContentWidth() {
330 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700331 }
332
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800333 int getContentInsets() {
334 return mDividerInsets;
335 }
336
Chong Zhang198afac2016-04-15 12:03:11 -0700337 int getContentWidthInactive() {
338 return mDividerWindowWidthInactive;
339 }
340
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100341 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800342 if (mResizing != resizing) {
343 mResizing = resizing;
344 resetDragResizingChangeReported();
345 }
346 }
347
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100348 void setTouchRegion(Rect touchRegion) {
349 mTouchRegion.set(touchRegion);
350 }
351
352 void getTouchRegion(Rect outRegion) {
353 outRegion.set(mTouchRegion);
354 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
355 }
356
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800357 private void resetDragResizingChangeReported() {
Wale Ogunwaled1880962016-11-08 10:31:59 -0800358 mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
359 true /* traverseTopToBottom */ );
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100360 }
361
362 void setWindow(WindowState window) {
363 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800364 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100365 }
366
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800367 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800368 if (mWindow == null) {
369 return;
370 }
Matthew Ng64e77cf2017-10-31 14:01:31 -0700371 TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Jorim Jaggi7998e482016-02-12 18:47:06 -0800372
373 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
374 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800375 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800376 return;
377 }
378 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100379 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100380 if (!visible) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700381 setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f);
Jorim Jaggi50981592015-12-29 17:54:12 +0100382 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100383 }
384
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700385 private boolean wasVisible() {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100386 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100387 }
388
Chong Zhangf347ab52016-04-18 21:02:01 -0700389 void setAdjustedForIme(
390 boolean adjustedForIme, boolean adjustedForDivider,
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700391 boolean animate, WindowState imeWin, int imeHeight) {
392 if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
393 || mAdjustedForDivider != adjustedForDivider) {
Jorim Jaggi3070e772016-05-17 16:41:32 -0700394 if (animate && !mAnimatingForMinimizedDockedStack) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700395 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700396 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700397 // Animation might be delayed, so only notify if we don't run an animation.
Chong Zhangf347ab52016-04-18 21:02:01 -0700398 notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700399 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700400 mAdjustedForIme = adjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700401 mImeHeight = imeHeight;
Chong Zhangf347ab52016-04-18 21:02:01 -0700402 mAdjustedForDivider = adjustedForDivider;
Chong Zhangbaba7832016-03-24 10:21:26 -0700403 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700404 }
405
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700406 int getImeHeightAdjustedFor() {
407 return mImeHeight;
408 }
409
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700410 void positionDockedStackedDivider(Rect frame) {
Matthew Ng0808af32018-05-07 12:11:13 -0700411 TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700412 if (stack == null) {
413 // Unfortunately we might end up with still having a divider, even though the underlying
414 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800415 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
416 // keep putting it in the same place it was before the stack was removed to have
417 // continuity and prevent it from jumping to the center. It will get hidden soon.
418 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700419 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800420 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800421 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700422 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100423 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700424 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700425 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100426 frame.set(mTmpRect.right - mDividerInsets, frame.top,
427 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700428 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700429 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100430 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
431 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700432 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700433 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100434 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
435 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700436 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700437 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100438 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
439 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700440 break;
441 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800442 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700443 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800444
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700445 private void notifyDockedDividerVisibilityChanged(boolean visible) {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100446 final int size = mDockedStackListeners.beginBroadcast();
447 for (int i = 0; i < size; ++i) {
448 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
449 try {
450 listener.onDividerVisibilityChanged(visible);
451 } catch (RemoteException e) {
452 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
453 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800454 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100455 mDockedStackListeners.finishBroadcast();
456 }
457
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700458 /**
459 * Checks if the primary stack is allowed to dock to a specific side based on its original dock
460 * side.
461 *
462 * @param dockSide the side to see if it is valid
463 * @return true if the side provided is valid
464 */
465 boolean canPrimaryStackDockTo(int dockSide) {
Matthew Ng62c78462018-04-09 14:43:21 -0700466 final DisplayInfo di = mDisplayContent.getDisplayInfo();
467 return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide, di.logicalWidth,
468 di.logicalHeight, di.rotation);
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700469 }
470
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100471 void notifyDockedStackExistsChanged(boolean exists) {
Andrii Kulian5406e7a2016-10-21 11:55:23 -0700472 // TODO(multi-display): Perform all actions only for current display.
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100473 final int size = mDockedStackListeners.beginBroadcast();
474 for (int i = 0; i < size; ++i) {
475 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
476 try {
477 listener.onDockedStackExistsChanged(exists);
478 } catch (RemoteException e) {
479 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
480 }
481 }
482 mDockedStackListeners.finishBroadcast();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700483 if (exists) {
484 InputMethodManagerInternal inputMethodManagerInternal =
485 LocalServices.getService(InputMethodManagerInternal.class);
486 if (inputMethodManagerInternal != null) {
487
488 // Hide the current IME to avoid problems with animations from IME adjustment when
489 // attaching the docked stack.
490 inputMethodManagerInternal.hideCurrentInputMethod();
491 mImeHideRequested = true;
492 }
Matthew Nge8b052a2018-01-16 14:33:47 -0800493
494 // If a primary stack was just created, it will not have access to display content at
495 // this point so pass it from here to get a valid dock side.
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700496 final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Matthew Nge8b052a2018-01-16 14:33:47 -0800497 mOriginalDockedSide = stack.getDockSideForDisplay(mDisplayContent);
Matthew Ngbc527a32017-06-19 16:42:31 -0700498 return;
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700499 }
Matthew Ngcb1b8e42017-10-20 16:29:23 -0700500 mOriginalDockedSide = DOCKED_INVALID;
Matthew Ngbc527a32017-06-19 16:42:31 -0700501 setMinimizedDockedStack(false /* minimizedDock */, false /* animate */);
Robert Carrf59b8dd2017-10-02 18:58:36 -0700502
503 if (mDimmedStack != null) {
504 mDimmedStack.stopDimming();
505 mDimmedStack = null;
506 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100507 }
508
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700509 /**
510 * Resets the state that IME hide has been requested. See {@link #isImeHideRequested}.
511 */
512 void resetImeHideRequested() {
513 mImeHideRequested = false;
514 }
515
516 /**
517 * The docked stack divider controller makes sure the IME gets hidden when attaching the docked
518 * stack, to avoid animation problems. This flag indicates whether the request to hide the IME
519 * has been sent in an asynchronous manner, and the IME should be treated as hidden already.
520 *
521 * @return whether IME hide request has been sent
522 */
523 boolean isImeHideRequested() {
524 return mImeHideRequested;
525 }
526
Matthew Nge15352e2016-12-20 15:36:29 -0800527 private void notifyDockedStackMinimizedChanged(boolean minimizedDock, boolean animate,
528 boolean isHomeStackResizable) {
529 long animDuration = 0;
530 if (animate) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700531 final TaskStack stack =
Matthew Ng64e77cf2017-10-31 14:01:31 -0700532 mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Matthew Nge15352e2016-12-20 15:36:29 -0800533 final long transitionDuration = isAnimationMaximizing()
534 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
535 : DEFAULT_APP_TRANSITION_DURATION;
536 mAnimationDuration = (long)
537 (transitionDuration * mService.getTransitionAnimationScaleLocked());
538 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
539 animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
540 }
Tony Mak853304c2016-04-18 15:17:41 +0100541 mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
542 mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
543 minimizedDock ? 1 : 0, 0).sendToTarget();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800544 final int size = mDockedStackListeners.beginBroadcast();
545 for (int i = 0; i < size; ++i) {
546 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
547 try {
Matthew Nge15352e2016-12-20 15:36:29 -0800548 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration,
549 isHomeStackResizable);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800550 } catch (RemoteException e) {
551 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
552 }
553 }
554 mDockedStackListeners.finishBroadcast();
555 }
556
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700557 void notifyDockSideChanged(int newDockSide) {
558 final int size = mDockedStackListeners.beginBroadcast();
559 for (int i = 0; i < size; ++i) {
560 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
561 try {
562 listener.onDockSideChanged(newDockSide);
563 } catch (RemoteException e) {
564 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
565 }
566 }
567 mDockedStackListeners.finishBroadcast();
568 }
569
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700570 private void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
Jorim Jaggi698e7632016-04-13 21:02:22 -0700571 final int size = mDockedStackListeners.beginBroadcast();
572 for (int i = 0; i < size; ++i) {
573 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
574 try {
575 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
576 } catch (RemoteException e) {
577 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
578 }
579 }
580 mDockedStackListeners.finishBroadcast();
581 }
582
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100583 void registerDockedStackListener(IDockedStackListener listener) {
584 mDockedStackListeners.register(listener);
585 notifyDockedDividerVisibilityChanged(wasVisible());
Wale Ogunwale61911492017-10-11 08:50:50 -0700586 notifyDockedStackExistsChanged(
Matthew Ng64e77cf2017-10-31 14:01:31 -0700587 mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null);
Matthew Nge15352e2016-12-20 15:36:29 -0800588 notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
589 isHomeStackResizable());
Jorim Jaggi698e7632016-04-13 21:02:22 -0700590 notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
591
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800592 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100593
Wale Ogunwale68278562017-09-23 17:13:55 -0700594 /**
595 * Shows a dim layer with {@param alpha} if {@param visible} is true and
596 * {@param targetWindowingMode} isn't
597 * {@link android.app.WindowConfiguration#WINDOWING_MODE_UNDEFINED} and there is a stack on the
598 * display in that windowing mode.
599 */
600 void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700601 // TODO: Maybe only allow split-screen windowing modes?
602 final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800603 ? mDisplayContent.getTopStackInWindowingMode(targetWindowingMode)
Wale Ogunwale68278562017-09-23 17:13:55 -0700604 : null;
Matthew Ng64e77cf2017-10-31 14:01:31 -0700605 final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStack();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100606 boolean visibleAndValid = visible && stack != null && dockedStack != null;
chaviw783729c2018-01-25 15:14:10 -0800607
608 // Ensure an old dim that was shown for the docked stack divider is removed so we don't end
609 // up with dim layers that can no longer be removed.
610 if (mDimmedStack != null && mDimmedStack != stack) {
611 mDimmedStack.stopDimming();
612 mDimmedStack = null;
613 }
614
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100615 if (visibleAndValid) {
Robert Carrf59b8dd2017-10-02 18:58:36 -0700616 mDimmedStack = stack;
617 stack.dim(alpha);
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100618 }
Robert Carrf59b8dd2017-10-02 18:58:36 -0700619 if (!visibleAndValid && stack != null) {
620 mDimmedStack = null;
621 stack.stopDimming();
Jorim Jaggi50981592015-12-29 17:54:12 +0100622 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100623 }
624
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800625 /**
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700626 * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
627 * above all application surfaces.
628 */
629 private int getResizeDimLayer() {
630 return (mWindow != null) ? mWindow.mLayer - 1 : LAYER_OFFSET_DIM;
631 }
632
633 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800634 * Notifies the docked stack divider controller of a visibility change that happens without
635 * an animation.
636 */
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700637 void notifyAppVisibilityChanged() {
638 checkMinimizeChanged(false /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800639 }
640
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200641 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps, int appTransition) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700642 final boolean wasMinimized = mMinimizedDock;
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700643 checkMinimizeChanged(true /* animate */);
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700644
645 // We were minimized, and now we are still minimized, but somebody is trying to launch an
Matthew Ng8e265522017-02-13 11:09:37 -0800646 // app in docked stack, better show recent apps so we actually get unminimized! However do
647 // not do this if keyguard is dismissed such as when the device is unlocking. This catches
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700648 // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
649 // we couldn't retrace the launch of the app in the docked stack to the launch from
650 // homescreen.
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200651 if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
Matthew Ng8e265522017-02-13 11:09:37 -0800652 && appTransition != TRANSIT_NONE &&
653 !AppTransition.isKeyguardGoingAwayTransit(appTransition)) {
Winson Chungc1674272018-02-21 10:15:17 -0800654 if (mService.mAmInternal.isRecentsComponentHomeActivity(mService.mCurrentUserId)) {
655 // When the home activity is the recents component and we are already minimized,
656 // then there is nothing to do here since home is already visible
657 } else {
658 mService.showRecentApps();
659 }
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700660 }
661 }
662
663 /**
664 * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
665 */
666 private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
667 for (int i = apps.size() - 1; i >= 0; i--) {
668 final AppWindowToken token = apps.valueAt(i);
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700669 if (token.getTask() != null && token.inSplitScreenPrimaryWindowingMode()) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700670 return true;
671 }
672 }
673 return false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800674 }
675
Jorim Jaggi1ae68bf2016-05-09 18:44:34 -0700676 boolean isMinimizedDock() {
677 return mMinimizedDock;
678 }
679
Winson Chungc1674272018-02-21 10:15:17 -0800680 void checkMinimizeChanged(boolean animate) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700681 if (mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() == null) {
Jorim Jaggi817a5242016-05-06 15:45:00 -0700682 return;
683 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700684 final TaskStack homeStack = mDisplayContent.getHomeStack();
685 if (homeStack == null) {
686 return;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800687 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700688 final Task homeTask = homeStack.findHomeTask();
689 if (homeTask == null || !isWithinDisplay(homeTask)) {
690 return;
691 }
Matthew Ng8e265522017-02-13 11:09:37 -0800692
693 // Do not minimize when dock is already minimized while keyguard is showing and not
694 // occluded such as unlocking the screen
Adrian Roosb56b3c32018-05-17 17:32:26 +0200695 if (mMinimizedDock && mService.mKeyguardOrAodShowingOnDefaultDisplay) {
Matthew Ng8e265522017-02-13 11:09:37 -0800696 return;
697 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800698 final TaskStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700699 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Winson Chungf557c3b2018-03-16 10:55:20 -0700700 final RecentsAnimationController recentsAnim = mService.getRecentsAnimationController();
701 final boolean minimizedForRecentsAnimation = recentsAnim != null &&
702 recentsAnim.isSplitScreenMinimized();
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800703 boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
704 if (homeVisible && topSecondaryStack != null) {
705 // Home should only be considered visible if it is greater or equal to the top secondary
706 // stack in terms of z-order.
707 homeVisible = homeStack.compareTo(topSecondaryStack) >= 0;
708 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700709 setMinimizedDockedStack(homeVisible || minimizedForRecentsAnimation, animate);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800710 }
711
712 private boolean isWithinDisplay(Task task) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800713 task.getBounds(mTmpRect);
714 mDisplayContent.getBounds(mTmpRect2);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800715 return mTmpRect.intersect(mTmpRect2);
716 }
717
718 /**
719 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
720 * docked stack are heavily clipped so you can only see a minimal peek state.
721 *
722 * @param minimizedDock Whether the docked stack is currently minimized.
723 * @param animate Whether to animate the change.
724 */
725 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700726 final boolean wasMinimized = mMinimizedDock;
727 mMinimizedDock = minimizedDock;
Jorim Jaggi817a5242016-05-06 15:45:00 -0700728 if (minimizedDock == wasMinimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800729 return;
730 }
731
Chong Zhang22eff0a2016-07-01 14:48:11 -0700732 final boolean imeChanged = clearImeAdjustAnimation();
733 boolean minimizedChange = false;
Matthew Nge15352e2016-12-20 15:36:29 -0800734 if (isHomeStackResizable()) {
Winson Chungc1674272018-02-21 10:15:17 -0800735 notifyDockedStackMinimizedChanged(minimizedDock, animate,
Matthew Nge15352e2016-12-20 15:36:29 -0800736 true /* isHomeStackResizable */);
737 minimizedChange = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800738 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800739 if (minimizedDock) {
740 if (animate) {
741 startAdjustAnimation(0f, 1f);
742 } else {
743 minimizedChange |= setMinimizedDockedStack(true);
744 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800745 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800746 if (animate) {
747 startAdjustAnimation(1f, 0f);
748 } else {
749 minimizedChange |= setMinimizedDockedStack(false);
750 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800751 }
752 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700753 if (imeChanged || minimizedChange) {
754 if (imeChanged && !minimizedChange) {
755 Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing,"
756 + " minimizedDock=" + minimizedDock
757 + " minimizedChange=" + minimizedChange);
758 }
759 mService.mWindowPlacerLocked.performSurfacePlacement();
760 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800761 }
762
Chong Zhang22eff0a2016-07-01 14:48:11 -0700763 private boolean clearImeAdjustAnimation() {
Wale Ogunwale10124582016-09-15 20:25:50 -0700764 final boolean changed = mDisplayContent.clearImeAdjustAnimation();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700765 mAnimatingForIme = false;
Chong Zhang22eff0a2016-07-01 14:48:11 -0700766 return changed;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700767 }
768
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800769 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700770 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800771 mAnimationStarted = false;
772 mAnimationStart = from;
773 mAnimationTarget = to;
774 }
775
Chong Zhangf347ab52016-04-18 21:02:01 -0700776 private void startImeAdjustAnimation(
777 boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700778
779 // If we're not in an animation, the starting point depends on whether we're adjusted
780 // or not. If we're already in an animation, we start from where the current animation
781 // left off, so that the motion doesn't look discontinuous.
782 if (!mAnimatingForIme) {
783 mAnimationStart = mAdjustedForIme ? 1 : 0;
784 mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
785 mLastAnimationProgress = mAnimationStart;
786 mLastDividerProgress = mDividerAnimationStart;
787 } else {
788 mAnimationStart = mLastAnimationProgress;
789 mDividerAnimationStart = mLastDividerProgress;
790 }
Jorim Jaggi3070e772016-05-17 16:41:32 -0700791 mAnimatingForIme = true;
792 mAnimationStarted = false;
Chong Zhangf347ab52016-04-18 21:02:01 -0700793 mAnimationTarget = adjustedForIme ? 1 : 0;
794 mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700795
Wale Ogunwale10124582016-09-15 20:25:50 -0700796 mDisplayContent.beginImeAdjustAnimation();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700797
798 // We put all tasks into drag resizing mode - wait until all of them have completed the
799 // drag resizing switch.
800 if (!mService.mWaitingForDrawn.isEmpty()) {
801 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
802 mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
803 IME_ADJUST_DRAWN_TIMEOUT);
804 mAnimationStartDelayed = true;
805 if (imeWin != null) {
806
807 // There might be an old window delaying the animation start - clear it.
808 if (mDelayedImeWin != null) {
Jorim Jaggia5e10572017-11-15 14:36:26 +0100809 mDelayedImeWin.endDelayingAnimationStart();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700810 }
811 mDelayedImeWin = imeWin;
Jorim Jaggia5e10572017-11-15 14:36:26 +0100812 imeWin.startDelayingAnimationStart();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700813 }
Jorim Jaggi31883862016-11-04 15:45:30 -0700814
815 // If we are already waiting for something to be drawn, clear out the old one so it
816 // still gets executed.
817 // TODO: Have a real system where we can wait on different windows to be drawn with
818 // different callbacks.
819 if (mService.mWaitingForDrawnCallback != null) {
820 mService.mWaitingForDrawnCallback.run();
821 }
Jorim Jaggiff71d202016-04-14 13:12:36 -0700822 mService.mWaitingForDrawnCallback = () -> {
Jorim Jaggia5e10572017-11-15 14:36:26 +0100823 synchronized (mService.mWindowMap) {
824 mAnimationStartDelayed = false;
825 if (mDelayedImeWin != null) {
826 mDelayedImeWin.endDelayingAnimationStart();
827 }
828 // If the adjust status changed since this was posted, only notify
829 // the new states and don't animate.
830 long duration = 0;
831 if (mAdjustedForIme == adjustedForIme
832 && mAdjustedForDivider == adjustedForDivider) {
833 duration = IME_ADJUST_ANIM_DURATION;
834 } else {
835 Slog.w(TAG, "IME adjust changed while waiting for drawn:"
836 + " adjustedForIme=" + adjustedForIme
837 + " adjustedForDivider=" + adjustedForDivider
838 + " mAdjustedForIme=" + mAdjustedForIme
839 + " mAdjustedForDivider=" + mAdjustedForDivider);
840 }
841 notifyAdjustedForImeChanged(
842 mAdjustedForIme || mAdjustedForDivider, duration);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700843 }
Jorim Jaggiff71d202016-04-14 13:12:36 -0700844 };
845 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700846 notifyAdjustedForImeChanged(
847 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700848 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700849 }
850
Chong Zhang22eff0a2016-07-01 14:48:11 -0700851 private boolean setMinimizedDockedStack(boolean minimized) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700852 final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Matthew Nge15352e2016-12-20 15:36:29 -0800853 notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
Chong Zhang22eff0a2016-07-01 14:48:11 -0700854 return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800855 }
856
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800857 private boolean isAnimationMaximizing() {
858 return mAnimationTarget == 0f;
859 }
860
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800861 public boolean animate(long now) {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700862 if (mWindow == null) {
863 return false;
864 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700865 if (mAnimatingForMinimizedDockedStack) {
866 return animateForMinimizedDockedStack(now);
867 } else if (mAnimatingForIme) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700868 return animateForIme(now);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800869 }
Robert Carrf59b8dd2017-10-02 18:58:36 -0700870 return false;
Chong Zhangbaba7832016-03-24 10:21:26 -0700871 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800872
Jorim Jaggieb88d832016-04-13 20:17:43 -0700873 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700874 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700875 mAnimationStarted = true;
876 mAnimationStartTime = now;
877 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700878 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700879 }
880 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
881 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
882 .getInterpolation(t);
Wale Ogunwale10124582016-09-15 20:25:50 -0700883 final boolean updated =
884 mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700885 if (updated) {
886 mService.mWindowPlacerLocked.performSurfacePlacement();
887 }
888 if (t >= 1.0f) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700889 mLastAnimationProgress = mAnimationTarget;
890 mLastDividerProgress = mDividerAnimationTarget;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700891 mAnimatingForIme = false;
892 return false;
893 } else {
894 return true;
895 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700896 }
897
898 private boolean animateForMinimizedDockedStack(long now) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700899 final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800900 if (!mAnimationStarted) {
901 mAnimationStarted = true;
902 mAnimationStartTime = now;
Matthew Nge15352e2016-12-20 15:36:29 -0800903 notifyDockedStackMinimizedChanged(mMinimizedDock, true /* animate */,
904 isHomeStackResizable() /* isHomeStackResizable */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800905 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800906 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
907 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
908 .getInterpolation(t);
Chong Zhang741c0ba2016-05-27 12:52:11 -0700909 if (stack != null) {
910 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
911 mService.mWindowPlacerLocked.performSurfacePlacement();
912 }
913 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800914 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700915 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800916 return false;
917 } else {
918 return true;
919 }
920 }
921
Wale Ogunwale10124582016-09-15 20:25:50 -0700922 float getInterpolatedAnimationValue(float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700923 return t * mAnimationTarget + (1 - t) * mAnimationStart;
924 }
925
Wale Ogunwale10124582016-09-15 20:25:50 -0700926 float getInterpolatedDividerValue(float t) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700927 return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
928 }
929
Jorim Jaggif97ed922016-02-18 18:57:07 -0800930 /**
931 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
932 */
933 private float getMinimizeAmount(TaskStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700934 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800935 if (isAnimationMaximizing()) {
936 return adjustMaximizeAmount(stack, t, naturalAmount);
937 } else {
938 return naturalAmount;
939 }
940 }
941
942 /**
943 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
944 * during the transition such that the edge of the clip reveal rect is met earlier in the
945 * transition so we don't create a visible "hole", but only if both the clip reveal and the
946 * docked stack divider start from about the same portion on the screen.
947 */
948 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
949 if (mMaximizeMeetFraction == 1f) {
950 return naturalAmount;
951 }
952 final int minimizeDistance = stack.getMinimizeDistance();
953 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
954 / (float) minimizeDistance;
955 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
956 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
957 return amountPrime * t2 + naturalAmount * (1 - t2);
958 }
959
960 /**
961 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
962 * edge. See {@link #adjustMaximizeAmount}.
963 */
964 private float getClipRevealMeetFraction(TaskStack stack) {
965 if (!isAnimationMaximizing() || stack == null ||
966 !mService.mAppTransition.hadClipRevealAnimation()) {
967 return 1f;
968 }
969 final int minimizeDistance = stack.getMinimizeDistance();
970 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
971 / (float) minimizeDistance;
972 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
973 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
974 return CLIP_REVEAL_MEET_EARLIEST
975 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
976 }
977
Jorim Jaggi50981592015-12-29 17:54:12 +0100978 public String toShortString() {
979 return TAG;
980 }
Robert Carre63e01a2016-04-18 20:27:34 -0700981
982 WindowState getWindow() {
983 return mWindow;
984 }
Jorim Jaggi31f71702016-05-04 16:43:04 -0700985
986 void dump(String prefix, PrintWriter pw) {
987 pw.println(prefix + "DockedStackDividerController");
988 pw.println(prefix + " mLastVisibility=" + mLastVisibility);
989 pw.println(prefix + " mMinimizedDock=" + mMinimizedDock);
990 pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme);
991 pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider);
Jorim Jaggi31f71702016-05-04 16:43:04 -0700992 }
Steven Timotiusaf03df62017-07-18 16:56:43 -0700993
994 void writeToProto(ProtoOutputStream proto, long fieldId) {
995 final long token = proto.start(fieldId);
996 proto.write(MINIMIZED_DOCK, mMinimizedDock);
997 proto.end(token);
998 }
Robert Carre63e01a2016-04-18 20:27:34 -0700999}