blob: 6f441b98ea7c874dfaf79a811f266f5d8567350c [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
Jorim Jaggibc5425c2016-03-01 13:51:16 +010019import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
20import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
Wale Ogunwaleb62139d2017-09-20 15:37:35 -070021import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
22import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Wale Ogunwale68278562017-09-23 17:13:55 -070023import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Jorim Jaggi85639432016-05-06 17:27:55 -070024import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
25import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
26import static android.view.Surface.ROTATION_270;
27import static android.view.Surface.ROTATION_90;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010028import static android.view.WindowManager.DOCKED_BOTTOM;
29import static android.view.WindowManager.DOCKED_LEFT;
30import static android.view.WindowManager.DOCKED_RIGHT;
31import static android.view.WindowManager.DOCKED_TOP;
32import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
33import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
Jorim Jaggi84afb1a2016-09-28 14:54:04 +020034import static com.android.server.wm.AppTransition.TRANSIT_NONE;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010035import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
36import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Tony Mak853304c2016-04-18 15:17:41 +010037import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
Wale Ogunwalec69694a2016-10-18 13:51:15 -070038import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
Steven Timotiusaf03df62017-07-18 16:56:43 -070039import static com.android.server.wm.proto.DockedStackDividerControllerProto.MINIMIZED_DOCK;
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;
Jorim Jaggi50981592015-12-29 17:54:12 +010049import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010050import android.view.IDockedStackListener;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080051import android.view.animation.AnimationUtils;
52import android.view.animation.Interpolator;
Jorim Jaggieb88d832016-04-13 20:17:43 -070053import android.view.animation.PathInterpolator;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070054import android.view.inputmethod.InputMethodManagerInternal;
Jorim Jaggi50981592015-12-29 17:54:12 +010055
Jorim Jaggi85639432016-05-06 17:27:55 -070056import com.android.internal.policy.DividerSnapAlgorithm;
57import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070058import com.android.server.LocalServices;
Jorim Jaggi50981592015-12-29 17:54:12 +010059import com.android.server.wm.DimLayer.DimLayerUser;
Jorim Jaggiff71d202016-04-14 13:12:36 -070060import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010061
Jorim Jaggi31f71702016-05-04 16:43:04 -070062import java.io.PrintWriter;
Chong Zhangbaba7832016-03-24 10:21:26 -070063
Filip Gruszczynski466f3212015-09-21 17:57:57 -070064/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010065 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070066 */
Jorim Jaggi50981592015-12-29 17:54:12 +010067public class DockedStackDividerController implements DimLayerUser {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010068
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080069 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010070
Jorim Jaggif97ed922016-02-18 18:57:07 -080071 /**
72 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
73 * revealing surface at the earliest.
74 */
75 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
76
77 /**
78 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
79 * revealing surface at the latest.
80 */
81 private static final float CLIP_REVEAL_MEET_LAST = 1f;
82
83 /**
84 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
85 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
86 */
87 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
88
89 /**
90 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
91 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
92 */
93 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
94
Jorim Jaggieb88d832016-04-13 20:17:43 -070095 private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
Jorim Jaggiff71d202016-04-14 13:12:36 -070096 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggieb88d832016-04-13 20:17:43 -070097
Jorim Jaggi698e7632016-04-13 21:02:22 -070098 private static final long IME_ADJUST_ANIM_DURATION = 280;
Jorim Jaggieb88d832016-04-13 20:17:43 -070099
Jorim Jaggiff71d202016-04-14 13:12:36 -0700100 private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
101
Chong Zhang198afac2016-04-15 12:03:11 -0700102 private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
103
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800104 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700105 private final DisplayContent mDisplayContent;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700106 private int mDividerWindowWidth;
Chong Zhang198afac2016-04-15 12:03:11 -0700107 private int mDividerWindowWidthInactive;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700108 private int mDividerInsets;
Matthew Nge15352e2016-12-20 15:36:29 -0800109 private int mTaskHeightInMinimizedMode;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100110 private boolean mResizing;
111 private WindowState mWindow;
112 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800113 private final Rect mTmpRect2 = new Rect();
Jorim Jaggi85639432016-05-06 17:27:55 -0700114 private final Rect mTmpRect3 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -0800115 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800116 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100117 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
118 = new RemoteCallbackList<>();
Jorim Jaggi50981592015-12-29 17:54:12 +0100119 private final DimLayer mDimLayer;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700120
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800121 private boolean mMinimizedDock;
Chong Zhangbaba7832016-03-24 10:21:26 -0700122 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800123 private boolean mAnimationStarted;
124 private long mAnimationStartTime;
125 private float mAnimationStart;
126 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800127 private long mAnimationDuration;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700128 private boolean mAnimationStartDelayed;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800129 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800130 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100131 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700132 private boolean mAnimatingForIme;
133 private boolean mAdjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700134 private int mImeHeight;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700135 private WindowState mDelayedImeWin;
Chong Zhangf347ab52016-04-18 21:02:01 -0700136 private boolean mAdjustedForDivider;
137 private float mDividerAnimationStart;
138 private float mDividerAnimationTarget;
Wale Ogunwale10124582016-09-15 20:25:50 -0700139 float mLastAnimationProgress;
140 float mLastDividerProgress;
Jorim Jaggi85639432016-05-06 17:27:55 -0700141 private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700142 private boolean mImeHideRequested;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800143
144 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
145 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700146 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800147 final Context context = service.mContext;
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100148 mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
149 "DockedStackDim");
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800150 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
151 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700152 loadDimens();
153 }
154
Jorim Jaggi85639432016-05-06 17:27:55 -0700155 int getSmallestWidthDpForBounds(Rect bounds) {
156 final DisplayInfo di = mDisplayContent.getDisplayInfo();
157
Jorim Jaggi85639432016-05-06 17:27:55 -0700158 final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
159 final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
160 int minWidth = Integer.MAX_VALUE;
161
162 // Go through all screen orientations and find the orientation in which the task has the
163 // smallest width.
164 for (int rotation = 0; rotation < 4; rotation++) {
165 mTmpRect.set(bounds);
166 mDisplayContent.rotateBounds(di.rotation, rotation, mTmpRect);
167 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
168 mTmpRect2.set(0, 0,
169 rotated ? baseDisplayHeight : baseDisplayWidth,
170 rotated ? baseDisplayWidth : baseDisplayHeight);
171 final int orientation = mTmpRect2.width() <= mTmpRect2.height()
172 ? ORIENTATION_PORTRAIT
173 : ORIENTATION_LANDSCAPE;
174 final int dockSide = TaskStack.getDockSideUnchecked(mTmpRect, mTmpRect2, orientation);
175 final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
176 getContentWidth());
177
178 // Since we only care about feasible states, snap to the closest snap target, like it
179 // would happen when actually rotating the screen.
180 final int snappedPosition = mSnapAlgorithmForRotation[rotation]
181 .calculateNonDismissingSnapTarget(position).position;
182 DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, mTmpRect,
183 mTmpRect2.width(), mTmpRect2.height(), getContentWidth());
184 mService.mPolicy.getStableInsetsLw(rotation, mTmpRect2.width(), mTmpRect2.height(),
185 mTmpRect3);
Winson Chungbdc646f2017-02-13 12:12:22 -0800186 mService.intersectDisplayInsetBounds(mTmpRect2, mTmpRect3, mTmpRect);
Jorim Jaggi85639432016-05-06 17:27:55 -0700187 minWidth = Math.min(mTmpRect.width(), minWidth);
188 }
189 return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
190 }
191
Matthew Nge15352e2016-12-20 15:36:29 -0800192 void getHomeStackBoundsInDockedMode(Rect outBounds) {
193 final DisplayInfo di = mDisplayContent.getDisplayInfo();
194 mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
195 mTmpRect);
196 int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
197 Configuration configuration = mDisplayContent.getConfiguration();
Matthew Nga9e173d2017-05-17 15:03:18 -0700198 // The offset in the left (landscape)/top (portrait) is calculated with the minimized
199 // offset value with the divider size and any system insets in that direction.
Matthew Nge15352e2016-12-20 15:36:29 -0800200 if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
201 outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
202 di.logicalWidth, di.logicalHeight);
203 } else {
Matthew Nga9e173d2017-05-17 15:03:18 -0700204 // In landscape append the left position with the statusbar height to match the
205 // minimized size height in portrait mode.
206 outBounds.set(mTaskHeightInMinimizedMode + dividerSize + mTmpRect.left + mTmpRect.top,
207 0, di.logicalWidth, di.logicalHeight);
Matthew Nge15352e2016-12-20 15:36:29 -0800208 }
209 }
210
211 boolean isHomeStackResizable() {
212 final TaskStack homeStack = mDisplayContent.getHomeStack();
213 if (homeStack == null) {
214 return false;
215 }
216 final Task homeTask = homeStack.findHomeTask();
217 return homeTask != null && homeTask.isResizeable();
218 }
219
Jorim Jaggi85639432016-05-06 17:27:55 -0700220 private void initSnapAlgorithmForRotations() {
Andrii Kulian441e4492016-09-29 15:25:00 -0700221 final Configuration baseConfig = mDisplayContent.getConfiguration();
Jorim Jaggi85639432016-05-06 17:27:55 -0700222
223 // Initialize the snap algorithms for all 4 screen orientations.
224 final Configuration config = new Configuration();
225 for (int rotation = 0; rotation < 4; rotation++) {
226 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
227 final int dw = rotated
228 ? mDisplayContent.mBaseDisplayHeight
229 : mDisplayContent.mBaseDisplayWidth;
230 final int dh = rotated
231 ? mDisplayContent.mBaseDisplayWidth
232 : mDisplayContent.mBaseDisplayHeight;
233 mService.mPolicy.getStableInsetsLw(rotation, dw, dh, mTmpRect);
Andrii Kulianb10330d2016-09-16 13:51:46 -0700234 config.unset();
Jorim Jaggi85639432016-05-06 17:27:55 -0700235 config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
Bryce Lee7566d762017-03-30 09:34:15 -0700236
237 final int displayId = mDisplayContent.getDisplayId();
238 final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation,
239 baseConfig.uiMode, displayId);
240 final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
241 baseConfig.uiMode, displayId);
242 mService.mPolicy.getNonDecorInsetsLw(rotation, dw, dh, mTmpRect);
243 final int leftInset = mTmpRect.left;
244 final int topInset = mTmpRect.top;
245
Wale Ogunwale822e5122017-07-26 06:02:24 -0700246 config.windowConfiguration.setAppBounds(leftInset /*left*/, topInset /*top*/,
247 leftInset + appWidth /*right*/, topInset + appHeight /*bottom*/);
Bryce Lee7566d762017-03-30 09:34:15 -0700248
Jorim Jaggi85639432016-05-06 17:27:55 -0700249 config.screenWidthDp = (int)
Andrii Kuliandb8e1062016-11-15 18:30:27 -0800250 (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode,
Bryce Lee7566d762017-03-30 09:34:15 -0700251 displayId) / mDisplayContent.getDisplayMetrics().density);
Jorim Jaggi85639432016-05-06 17:27:55 -0700252 config.screenHeightDp = (int)
Andrii Kuliandb8e1062016-11-15 18:30:27 -0800253 (mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, baseConfig.uiMode,
Bryce Lee7566d762017-03-30 09:34:15 -0700254 displayId) / mDisplayContent.getDisplayMetrics().density);
Jorim Jaggi85639432016-05-06 17:27:55 -0700255 final Context rotationContext = mService.mContext.createConfigurationContext(config);
256 mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
257 rotationContext.getResources(), dw, dh, getContentWidth(),
258 config.orientation == ORIENTATION_PORTRAIT, mTmpRect);
259 }
260 }
261
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700262 private void loadDimens() {
263 final Context context = mService.mContext;
264 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
265 com.android.internal.R.dimen.docked_stack_divider_thickness);
266 mDividerInsets = context.getResources().getDimensionPixelSize(
267 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700268 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
269 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Matthew Nge15352e2016-12-20 15:36:29 -0800270 mTaskHeightInMinimizedMode = context.getResources().getDimensionPixelSize(
271 com.android.internal.R.dimen.task_height_of_minimized_mode);
Jorim Jaggi85639432016-05-06 17:27:55 -0700272 initSnapAlgorithmForRotations();
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700273 }
274
275 void onConfigurationChanged() {
276 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700277 }
278
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100279 boolean isResizing() {
280 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700281 }
282
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100283 int getContentWidth() {
284 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700285 }
286
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800287 int getContentInsets() {
288 return mDividerInsets;
289 }
290
Chong Zhang198afac2016-04-15 12:03:11 -0700291 int getContentWidthInactive() {
292 return mDividerWindowWidthInactive;
293 }
294
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100295 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800296 if (mResizing != resizing) {
297 mResizing = resizing;
298 resetDragResizingChangeReported();
299 }
300 }
301
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100302 void setTouchRegion(Rect touchRegion) {
303 mTouchRegion.set(touchRegion);
304 }
305
306 void getTouchRegion(Rect outRegion) {
307 outRegion.set(mTouchRegion);
308 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
309 }
310
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800311 private void resetDragResizingChangeReported() {
Wale Ogunwaled1880962016-11-08 10:31:59 -0800312 mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
313 true /* traverseTopToBottom */ );
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100314 }
315
316 void setWindow(WindowState window) {
317 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800318 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100319 }
320
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800321 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800322 if (mWindow == null) {
323 return;
324 }
Jorim Jaggife762342016-10-13 14:33:27 +0200325 TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility();
Jorim Jaggi7998e482016-02-12 18:47:06 -0800326
327 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
328 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800329 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800330 return;
331 }
332 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100333 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100334 if (!visible) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700335 setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f);
Jorim Jaggi50981592015-12-29 17:54:12 +0100336 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100337 }
338
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700339 private boolean wasVisible() {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100340 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100341 }
342
Chong Zhangf347ab52016-04-18 21:02:01 -0700343 void setAdjustedForIme(
344 boolean adjustedForIme, boolean adjustedForDivider,
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700345 boolean animate, WindowState imeWin, int imeHeight) {
346 if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
347 || mAdjustedForDivider != adjustedForDivider) {
Jorim Jaggi3070e772016-05-17 16:41:32 -0700348 if (animate && !mAnimatingForMinimizedDockedStack) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700349 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700350 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700351 // Animation might be delayed, so only notify if we don't run an animation.
Chong Zhangf347ab52016-04-18 21:02:01 -0700352 notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700353 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700354 mAdjustedForIme = adjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700355 mImeHeight = imeHeight;
Chong Zhangf347ab52016-04-18 21:02:01 -0700356 mAdjustedForDivider = adjustedForDivider;
Chong Zhangbaba7832016-03-24 10:21:26 -0700357 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700358 }
359
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700360 int getImeHeightAdjustedFor() {
361 return mImeHeight;
362 }
363
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700364 void positionDockedStackedDivider(Rect frame) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700365 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700366 if (stack == null) {
367 // Unfortunately we might end up with still having a divider, even though the underlying
368 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800369 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
370 // keep putting it in the same place it was before the stack was removed to have
371 // continuity and prevent it from jumping to the center. It will get hidden soon.
372 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700373 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800374 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800375 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700376 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100377 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700378 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700379 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100380 frame.set(mTmpRect.right - mDividerInsets, frame.top,
381 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700382 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700383 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100384 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
385 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700386 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700387 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100388 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
389 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700390 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700391 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100392 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
393 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700394 break;
395 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800396 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700397 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800398
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700399 private void notifyDockedDividerVisibilityChanged(boolean visible) {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100400 final int size = mDockedStackListeners.beginBroadcast();
401 for (int i = 0; i < size; ++i) {
402 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
403 try {
404 listener.onDividerVisibilityChanged(visible);
405 } catch (RemoteException e) {
406 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
407 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800408 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100409 mDockedStackListeners.finishBroadcast();
410 }
411
412 void notifyDockedStackExistsChanged(boolean exists) {
Andrii Kulian5406e7a2016-10-21 11:55:23 -0700413 // TODO(multi-display): Perform all actions only for current display.
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100414 final int size = mDockedStackListeners.beginBroadcast();
415 for (int i = 0; i < size; ++i) {
416 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
417 try {
418 listener.onDockedStackExistsChanged(exists);
419 } catch (RemoteException e) {
420 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
421 }
422 }
423 mDockedStackListeners.finishBroadcast();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700424 if (exists) {
425 InputMethodManagerInternal inputMethodManagerInternal =
426 LocalServices.getService(InputMethodManagerInternal.class);
427 if (inputMethodManagerInternal != null) {
428
429 // Hide the current IME to avoid problems with animations from IME adjustment when
430 // attaching the docked stack.
431 inputMethodManagerInternal.hideCurrentInputMethod();
432 mImeHideRequested = true;
433 }
Matthew Ngbc527a32017-06-19 16:42:31 -0700434 return;
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700435 }
Matthew Ngbc527a32017-06-19 16:42:31 -0700436 setMinimizedDockedStack(false /* minimizedDock */, false /* animate */);
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100437 }
438
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700439 /**
440 * Resets the state that IME hide has been requested. See {@link #isImeHideRequested}.
441 */
442 void resetImeHideRequested() {
443 mImeHideRequested = false;
444 }
445
446 /**
447 * The docked stack divider controller makes sure the IME gets hidden when attaching the docked
448 * stack, to avoid animation problems. This flag indicates whether the request to hide the IME
449 * has been sent in an asynchronous manner, and the IME should be treated as hidden already.
450 *
451 * @return whether IME hide request has been sent
452 */
453 boolean isImeHideRequested() {
454 return mImeHideRequested;
455 }
456
Matthew Nge15352e2016-12-20 15:36:29 -0800457 private void notifyDockedStackMinimizedChanged(boolean minimizedDock, boolean animate,
458 boolean isHomeStackResizable) {
459 long animDuration = 0;
460 if (animate) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700461 final TaskStack stack =
462 mDisplayContent.getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Matthew Nge15352e2016-12-20 15:36:29 -0800463 final long transitionDuration = isAnimationMaximizing()
464 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
465 : DEFAULT_APP_TRANSITION_DURATION;
466 mAnimationDuration = (long)
467 (transitionDuration * mService.getTransitionAnimationScaleLocked());
468 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
469 animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
470 }
Tony Mak853304c2016-04-18 15:17:41 +0100471 mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
472 mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
473 minimizedDock ? 1 : 0, 0).sendToTarget();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800474 final int size = mDockedStackListeners.beginBroadcast();
475 for (int i = 0; i < size; ++i) {
476 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
477 try {
Matthew Nge15352e2016-12-20 15:36:29 -0800478 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration,
479 isHomeStackResizable);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800480 } catch (RemoteException e) {
481 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
482 }
483 }
484 mDockedStackListeners.finishBroadcast();
485 }
486
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700487 void notifyDockSideChanged(int newDockSide) {
488 final int size = mDockedStackListeners.beginBroadcast();
489 for (int i = 0; i < size; ++i) {
490 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
491 try {
492 listener.onDockSideChanged(newDockSide);
493 } catch (RemoteException e) {
494 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
495 }
496 }
497 mDockedStackListeners.finishBroadcast();
498 }
499
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700500 private void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
Jorim Jaggi698e7632016-04-13 21:02:22 -0700501 final int size = mDockedStackListeners.beginBroadcast();
502 for (int i = 0; i < size; ++i) {
503 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
504 try {
505 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
506 } catch (RemoteException e) {
507 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
508 }
509 }
510 mDockedStackListeners.finishBroadcast();
511 }
512
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100513 void registerDockedStackListener(IDockedStackListener listener) {
514 mDockedStackListeners.register(listener);
515 notifyDockedDividerVisibilityChanged(wasVisible());
Wale Ogunwale1666e312016-12-16 11:27:18 -0800516 notifyDockedStackExistsChanged(mDisplayContent.getDockedStackIgnoringVisibility() != null);
Matthew Nge15352e2016-12-20 15:36:29 -0800517 notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
518 isHomeStackResizable());
Jorim Jaggi698e7632016-04-13 21:02:22 -0700519 notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
520
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800521 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100522
Wale Ogunwale68278562017-09-23 17:13:55 -0700523 /**
524 * Shows a dim layer with {@param alpha} if {@param visible} is true and
525 * {@param targetWindowingMode} isn't
526 * {@link android.app.WindowConfiguration#WINDOWING_MODE_UNDEFINED} and there is a stack on the
527 * display in that windowing mode.
528 */
529 void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
Robert Carr68e5c9e2016-09-14 10:50:09 -0700530 mService.openSurfaceTransaction();
Wale Ogunwale68278562017-09-23 17:13:55 -0700531 // TODO: Maybe only allow split-screen windowing modes?
532 final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
533 ? mDisplayContent.getStack(targetWindowingMode)
534 : null;
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100535 final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
536 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100537 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100538 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100539 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100540 mDimLayer.setBounds(mTmpRect);
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700541 mDimLayer.show(getResizeDimLayer(), alpha, 0 /* duration */);
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100542 } else {
543 visibleAndValid = false;
544 }
545 }
546 if (!visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100547 mDimLayer.hide();
548 }
Robert Carr68e5c9e2016-09-14 10:50:09 -0700549 mService.closeSurfaceTransaction();
Jorim Jaggi50981592015-12-29 17:54:12 +0100550 }
551
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800552 /**
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700553 * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
554 * above all application surfaces.
555 */
556 private int getResizeDimLayer() {
557 return (mWindow != null) ? mWindow.mLayer - 1 : LAYER_OFFSET_DIM;
558 }
559
560 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800561 * Notifies the docked stack divider controller of a visibility change that happens without
562 * an animation.
563 */
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700564 void notifyAppVisibilityChanged() {
565 checkMinimizeChanged(false /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800566 }
567
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200568 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps, int appTransition) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700569 final boolean wasMinimized = mMinimizedDock;
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700570 checkMinimizeChanged(true /* animate */);
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700571
572 // We were minimized, and now we are still minimized, but somebody is trying to launch an
Matthew Ng8e265522017-02-13 11:09:37 -0800573 // app in docked stack, better show recent apps so we actually get unminimized! However do
574 // not do this if keyguard is dismissed such as when the device is unlocking. This catches
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700575 // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
576 // we couldn't retrace the launch of the app in the docked stack to the launch from
577 // homescreen.
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200578 if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
Matthew Ng8e265522017-02-13 11:09:37 -0800579 && appTransition != TRANSIT_NONE &&
580 !AppTransition.isKeyguardGoingAwayTransit(appTransition)) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700581 mService.showRecentApps(true /* fromHome */);
582 }
583 }
584
585 /**
586 * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
587 */
588 private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
589 for (int i = apps.size() - 1; i >= 0; i--) {
590 final AppWindowToken token = apps.valueAt(i);
Bryce Lee6d410262017-02-28 15:30:17 -0800591 if (token.getTask() != null && token.getTask().mStack.mStackId == DOCKED_STACK_ID) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700592 return true;
593 }
594 }
595 return false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800596 }
597
Jorim Jaggi1ae68bf2016-05-09 18:44:34 -0700598 boolean isMinimizedDock() {
599 return mMinimizedDock;
600 }
601
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700602 private void checkMinimizeChanged(boolean animate) {
Jorim Jaggife762342016-10-13 14:33:27 +0200603 if (mDisplayContent.getDockedStackIgnoringVisibility() == null) {
Jorim Jaggi817a5242016-05-06 15:45:00 -0700604 return;
605 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700606 final TaskStack homeStack = mDisplayContent.getHomeStack();
607 if (homeStack == null) {
608 return;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800609 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700610 final Task homeTask = homeStack.findHomeTask();
611 if (homeTask == null || !isWithinDisplay(homeTask)) {
612 return;
613 }
Matthew Ng8e265522017-02-13 11:09:37 -0800614
615 // Do not minimize when dock is already minimized while keyguard is showing and not
616 // occluded such as unlocking the screen
617 if (mMinimizedDock && mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
618 return;
619 }
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700620 final TaskStack fullscreenStack = mDisplayContent.getStack(
621 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700622 final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700623 final boolean homeBehind = fullscreenStack != null && fullscreenStack.isVisible();
Wale Ogunwale069bbd32017-02-03 07:58:14 -0800624 setMinimizedDockedStack(homeVisible && !homeBehind, animate);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800625 }
626
627 private boolean isWithinDisplay(Task task) {
628 task.mStack.getBounds(mTmpRect);
629 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
630 return mTmpRect.intersect(mTmpRect2);
631 }
632
633 /**
634 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
635 * docked stack are heavily clipped so you can only see a minimal peek state.
636 *
637 * @param minimizedDock Whether the docked stack is currently minimized.
638 * @param animate Whether to animate the change.
639 */
640 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700641 final boolean wasMinimized = mMinimizedDock;
642 mMinimizedDock = minimizedDock;
Jorim Jaggi817a5242016-05-06 15:45:00 -0700643 if (minimizedDock == wasMinimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800644 return;
645 }
646
Chong Zhang22eff0a2016-07-01 14:48:11 -0700647 final boolean imeChanged = clearImeAdjustAnimation();
648 boolean minimizedChange = false;
Matthew Nge15352e2016-12-20 15:36:29 -0800649 if (isHomeStackResizable()) {
650 notifyDockedStackMinimizedChanged(minimizedDock, true /* animate */,
651 true /* isHomeStackResizable */);
652 minimizedChange = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800653 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800654 if (minimizedDock) {
655 if (animate) {
656 startAdjustAnimation(0f, 1f);
657 } else {
658 minimizedChange |= setMinimizedDockedStack(true);
659 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800660 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800661 if (animate) {
662 startAdjustAnimation(1f, 0f);
663 } else {
664 minimizedChange |= setMinimizedDockedStack(false);
665 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800666 }
667 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700668 if (imeChanged || minimizedChange) {
669 if (imeChanged && !minimizedChange) {
670 Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing,"
671 + " minimizedDock=" + minimizedDock
672 + " minimizedChange=" + minimizedChange);
673 }
674 mService.mWindowPlacerLocked.performSurfacePlacement();
675 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800676 }
677
Chong Zhang22eff0a2016-07-01 14:48:11 -0700678 private boolean clearImeAdjustAnimation() {
Wale Ogunwale10124582016-09-15 20:25:50 -0700679 final boolean changed = mDisplayContent.clearImeAdjustAnimation();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700680 mAnimatingForIme = false;
Chong Zhang22eff0a2016-07-01 14:48:11 -0700681 return changed;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700682 }
683
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800684 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700685 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800686 mAnimationStarted = false;
687 mAnimationStart = from;
688 mAnimationTarget = to;
689 }
690
Chong Zhangf347ab52016-04-18 21:02:01 -0700691 private void startImeAdjustAnimation(
692 boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700693
694 // If we're not in an animation, the starting point depends on whether we're adjusted
695 // or not. If we're already in an animation, we start from where the current animation
696 // left off, so that the motion doesn't look discontinuous.
697 if (!mAnimatingForIme) {
698 mAnimationStart = mAdjustedForIme ? 1 : 0;
699 mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
700 mLastAnimationProgress = mAnimationStart;
701 mLastDividerProgress = mDividerAnimationStart;
702 } else {
703 mAnimationStart = mLastAnimationProgress;
704 mDividerAnimationStart = mLastDividerProgress;
705 }
Jorim Jaggi3070e772016-05-17 16:41:32 -0700706 mAnimatingForIme = true;
707 mAnimationStarted = false;
Chong Zhangf347ab52016-04-18 21:02:01 -0700708 mAnimationTarget = adjustedForIme ? 1 : 0;
709 mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700710
Wale Ogunwale10124582016-09-15 20:25:50 -0700711 mDisplayContent.beginImeAdjustAnimation();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700712
713 // We put all tasks into drag resizing mode - wait until all of them have completed the
714 // drag resizing switch.
715 if (!mService.mWaitingForDrawn.isEmpty()) {
716 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
717 mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
718 IME_ADJUST_DRAWN_TIMEOUT);
719 mAnimationStartDelayed = true;
720 if (imeWin != null) {
721
722 // There might be an old window delaying the animation start - clear it.
723 if (mDelayedImeWin != null) {
724 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
725 }
726 mDelayedImeWin = imeWin;
727 imeWin.mWinAnimator.startDelayingAnimationStart();
728 }
Jorim Jaggi31883862016-11-04 15:45:30 -0700729
730 // If we are already waiting for something to be drawn, clear out the old one so it
731 // still gets executed.
732 // TODO: Have a real system where we can wait on different windows to be drawn with
733 // different callbacks.
734 if (mService.mWaitingForDrawnCallback != null) {
735 mService.mWaitingForDrawnCallback.run();
736 }
Jorim Jaggiff71d202016-04-14 13:12:36 -0700737 mService.mWaitingForDrawnCallback = () -> {
738 mAnimationStartDelayed = false;
739 if (mDelayedImeWin != null) {
740 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
741 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700742 // If the adjust status changed since this was posted, only notify
743 // the new states and don't animate.
744 long duration = 0;
745 if (mAdjustedForIme == adjustedForIme
746 && mAdjustedForDivider == adjustedForDivider) {
747 duration = IME_ADJUST_ANIM_DURATION;
748 } else {
749 Slog.w(TAG, "IME adjust changed while waiting for drawn:"
750 + " adjustedForIme=" + adjustedForIme
751 + " adjustedForDivider=" + adjustedForDivider
752 + " mAdjustedForIme=" + mAdjustedForIme
753 + " mAdjustedForDivider=" + mAdjustedForDivider);
754 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700755 notifyAdjustedForImeChanged(
Chong Zhang22eff0a2016-07-01 14:48:11 -0700756 mAdjustedForIme || mAdjustedForDivider, duration);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700757 };
758 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700759 notifyAdjustedForImeChanged(
760 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700761 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700762 }
763
Chong Zhang22eff0a2016-07-01 14:48:11 -0700764 private boolean setMinimizedDockedStack(boolean minimized) {
Jorim Jaggife762342016-10-13 14:33:27 +0200765 final TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility();
Matthew Nge15352e2016-12-20 15:36:29 -0800766 notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
Chong Zhang22eff0a2016-07-01 14:48:11 -0700767 return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800768 }
769
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800770 private boolean isAnimationMaximizing() {
771 return mAnimationTarget == 0f;
772 }
773
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800774 public boolean animate(long now) {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700775 if (mWindow == null) {
776 return false;
777 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700778 if (mAnimatingForMinimizedDockedStack) {
779 return animateForMinimizedDockedStack(now);
780 } else if (mAnimatingForIme) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700781 return animateForIme(now);
Chong Zhangbaba7832016-03-24 10:21:26 -0700782 } else {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700783 if (mDimLayer != null && mDimLayer.isDimming()) {
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700784 mDimLayer.setLayer(getResizeDimLayer());
Chong Zhang1402c2e2016-04-21 15:17:47 -0700785 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800786 return false;
787 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700788 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800789
Jorim Jaggieb88d832016-04-13 20:17:43 -0700790 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700791 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700792 mAnimationStarted = true;
793 mAnimationStartTime = now;
794 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700795 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700796 }
797 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
798 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
799 .getInterpolation(t);
Wale Ogunwale10124582016-09-15 20:25:50 -0700800 final boolean updated =
801 mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700802 if (updated) {
803 mService.mWindowPlacerLocked.performSurfacePlacement();
804 }
805 if (t >= 1.0f) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700806 mLastAnimationProgress = mAnimationTarget;
807 mLastDividerProgress = mDividerAnimationTarget;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700808 mAnimatingForIme = false;
809 return false;
810 } else {
811 return true;
812 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700813 }
814
815 private boolean animateForMinimizedDockedStack(long now) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700816 final TaskStack stack =
817 mDisplayContent.getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800818 if (!mAnimationStarted) {
819 mAnimationStarted = true;
820 mAnimationStartTime = now;
Matthew Nge15352e2016-12-20 15:36:29 -0800821 notifyDockedStackMinimizedChanged(mMinimizedDock, true /* animate */,
822 isHomeStackResizable() /* isHomeStackResizable */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800823 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800824 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
825 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
826 .getInterpolation(t);
Chong Zhang741c0ba2016-05-27 12:52:11 -0700827 if (stack != null) {
828 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
829 mService.mWindowPlacerLocked.performSurfacePlacement();
830 }
831 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800832 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700833 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800834 return false;
835 } else {
836 return true;
837 }
838 }
839
Wale Ogunwale10124582016-09-15 20:25:50 -0700840 float getInterpolatedAnimationValue(float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700841 return t * mAnimationTarget + (1 - t) * mAnimationStart;
842 }
843
Wale Ogunwale10124582016-09-15 20:25:50 -0700844 float getInterpolatedDividerValue(float t) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700845 return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
846 }
847
Jorim Jaggif97ed922016-02-18 18:57:07 -0800848 /**
849 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
850 */
851 private float getMinimizeAmount(TaskStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700852 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800853 if (isAnimationMaximizing()) {
854 return adjustMaximizeAmount(stack, t, naturalAmount);
855 } else {
856 return naturalAmount;
857 }
858 }
859
860 /**
861 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
862 * during the transition such that the edge of the clip reveal rect is met earlier in the
863 * transition so we don't create a visible "hole", but only if both the clip reveal and the
864 * docked stack divider start from about the same portion on the screen.
865 */
866 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
867 if (mMaximizeMeetFraction == 1f) {
868 return naturalAmount;
869 }
870 final int minimizeDistance = stack.getMinimizeDistance();
871 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
872 / (float) minimizeDistance;
873 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
874 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
875 return amountPrime * t2 + naturalAmount * (1 - t2);
876 }
877
878 /**
879 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
880 * edge. See {@link #adjustMaximizeAmount}.
881 */
882 private float getClipRevealMeetFraction(TaskStack stack) {
883 if (!isAnimationMaximizing() || stack == null ||
884 !mService.mAppTransition.hadClipRevealAnimation()) {
885 return 1f;
886 }
887 final int minimizeDistance = stack.getMinimizeDistance();
888 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
889 / (float) minimizeDistance;
890 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
891 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
892 return CLIP_REVEAL_MEET_EARLIEST
893 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
894 }
895
Jorim Jaggi50981592015-12-29 17:54:12 +0100896 @Override
Wale Ogunwale29bfbb82016-05-12 15:13:52 -0700897 public boolean dimFullscreen() {
Jorim Jaggi50981592015-12-29 17:54:12 +0100898 return false;
899 }
900
901 @Override
902 public DisplayInfo getDisplayInfo() {
903 return mDisplayContent.getDisplayInfo();
904 }
905
906 @Override
Wale Ogunwalef0a60a92017-01-19 09:44:40 -0800907 public boolean isAttachedToDisplay() {
908 return mDisplayContent != null;
909 }
910
911 @Override
Jorim Jaggi50981592015-12-29 17:54:12 +0100912 public void getDimBounds(Rect outBounds) {
913 // This dim layer user doesn't need this.
914 }
915
916 @Override
917 public String toShortString() {
918 return TAG;
919 }
Robert Carre63e01a2016-04-18 20:27:34 -0700920
921 WindowState getWindow() {
922 return mWindow;
923 }
Jorim Jaggi31f71702016-05-04 16:43:04 -0700924
925 void dump(String prefix, PrintWriter pw) {
926 pw.println(prefix + "DockedStackDividerController");
927 pw.println(prefix + " mLastVisibility=" + mLastVisibility);
928 pw.println(prefix + " mMinimizedDock=" + mMinimizedDock);
929 pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme);
930 pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider);
931 if (mDimLayer.isDimming()) {
932 pw.println(prefix + " Dim layer is dimming: ");
933 mDimLayer.printTo(prefix + " ", pw);
934 }
935 }
Steven Timotiusaf03df62017-07-18 16:56:43 -0700936
937 void writeToProto(ProtoOutputStream proto, long fieldId) {
938 final long token = proto.start(fieldId);
939 proto.write(MINIMIZED_DOCK, mMinimizedDock);
940 proto.end(token);
941 }
Robert Carre63e01a2016-04-18 20:27:34 -0700942}