blob: 629af669d614b6669e19d73e32fce942d0cbf808 [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_PRIMARY;
20import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Wale Ogunwale68278562017-09-23 17:13:55 -070021import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Jorim Jaggi85639432016-05-06 17:27:55 -070022import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
23import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
24import static android.view.Surface.ROTATION_270;
25import static android.view.Surface.ROTATION_90;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010026import static android.view.WindowManager.DOCKED_BOTTOM;
27import 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 Jaggi84afb1a2016-09-28 14:54:04 +020032import static com.android.server.wm.AppTransition.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;
Steven Timotiusaf03df62017-07-18 16:56:43 -070037import static com.android.server.wm.proto.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;
Jorim Jaggi50981592015-12-29 17:54:12 +010047import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010048import android.view.IDockedStackListener;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080049import android.view.animation.AnimationUtils;
50import android.view.animation.Interpolator;
Jorim Jaggieb88d832016-04-13 20:17:43 -070051import android.view.animation.PathInterpolator;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070052import android.view.inputmethod.InputMethodManagerInternal;
Jorim Jaggi50981592015-12-29 17:54:12 +010053
Jorim Jaggi85639432016-05-06 17:27:55 -070054import com.android.internal.policy.DividerSnapAlgorithm;
55import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070056import com.android.server.LocalServices;
Jorim Jaggi50981592015-12-29 17:54:12 +010057import com.android.server.wm.DimLayer.DimLayerUser;
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 */
Jorim Jaggi50981592015-12-29 17:54:12 +010065public class DockedStackDividerController implements DimLayerUser {
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<>();
Jorim Jaggi50981592015-12-29 17:54:12 +0100117 private final DimLayer mDimLayer;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700118
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800119 private boolean mMinimizedDock;
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 Jaggi42625d1b2016-02-11 20:11:07 -0800141
142 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
143 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700144 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800145 final Context context = service.mContext;
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100146 mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
147 "DockedStackDim");
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800148 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
149 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700150 loadDimens();
151 }
152
Jorim Jaggi85639432016-05-06 17:27:55 -0700153 int getSmallestWidthDpForBounds(Rect bounds) {
154 final DisplayInfo di = mDisplayContent.getDisplayInfo();
155
Jorim Jaggi85639432016-05-06 17:27:55 -0700156 final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
157 final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
158 int minWidth = Integer.MAX_VALUE;
159
160 // Go through all screen orientations and find the orientation in which the task has the
161 // smallest width.
162 for (int rotation = 0; rotation < 4; rotation++) {
163 mTmpRect.set(bounds);
164 mDisplayContent.rotateBounds(di.rotation, rotation, mTmpRect);
165 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
166 mTmpRect2.set(0, 0,
167 rotated ? baseDisplayHeight : baseDisplayWidth,
168 rotated ? baseDisplayWidth : baseDisplayHeight);
169 final int orientation = mTmpRect2.width() <= mTmpRect2.height()
170 ? ORIENTATION_PORTRAIT
171 : ORIENTATION_LANDSCAPE;
172 final int dockSide = TaskStack.getDockSideUnchecked(mTmpRect, mTmpRect2, orientation);
173 final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
174 getContentWidth());
175
176 // Since we only care about feasible states, snap to the closest snap target, like it
177 // would happen when actually rotating the screen.
178 final int snappedPosition = mSnapAlgorithmForRotation[rotation]
179 .calculateNonDismissingSnapTarget(position).position;
180 DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, mTmpRect,
181 mTmpRect2.width(), mTmpRect2.height(), getContentWidth());
182 mService.mPolicy.getStableInsetsLw(rotation, mTmpRect2.width(), mTmpRect2.height(),
183 mTmpRect3);
Winson Chungbdc646f2017-02-13 12:12:22 -0800184 mService.intersectDisplayInsetBounds(mTmpRect2, mTmpRect3, mTmpRect);
Jorim Jaggi85639432016-05-06 17:27:55 -0700185 minWidth = Math.min(mTmpRect.width(), minWidth);
186 }
187 return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
188 }
189
Matthew Nge15352e2016-12-20 15:36:29 -0800190 void getHomeStackBoundsInDockedMode(Rect outBounds) {
191 final DisplayInfo di = mDisplayContent.getDisplayInfo();
192 mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
193 mTmpRect);
194 int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
195 Configuration configuration = mDisplayContent.getConfiguration();
Matthew Nga9e173d2017-05-17 15:03:18 -0700196 // The offset in the left (landscape)/top (portrait) is calculated with the minimized
197 // offset value with the divider size and any system insets in that direction.
Matthew Nge15352e2016-12-20 15:36:29 -0800198 if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
199 outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
200 di.logicalWidth, di.logicalHeight);
201 } else {
Matthew Nga9e173d2017-05-17 15:03:18 -0700202 // In landscape append the left position with the statusbar height to match the
203 // minimized size height in portrait mode.
204 outBounds.set(mTaskHeightInMinimizedMode + dividerSize + mTmpRect.left + mTmpRect.top,
205 0, di.logicalWidth, di.logicalHeight);
Matthew Nge15352e2016-12-20 15:36:29 -0800206 }
207 }
208
209 boolean isHomeStackResizable() {
210 final TaskStack homeStack = mDisplayContent.getHomeStack();
211 if (homeStack == null) {
212 return false;
213 }
214 final Task homeTask = homeStack.findHomeTask();
215 return homeTask != null && homeTask.isResizeable();
216 }
217
Jorim Jaggi85639432016-05-06 17:27:55 -0700218 private void initSnapAlgorithmForRotations() {
Andrii Kulian441e4492016-09-29 15:25:00 -0700219 final Configuration baseConfig = mDisplayContent.getConfiguration();
Jorim Jaggi85639432016-05-06 17:27:55 -0700220
221 // Initialize the snap algorithms for all 4 screen orientations.
222 final Configuration config = new Configuration();
223 for (int rotation = 0; rotation < 4; rotation++) {
224 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
225 final int dw = rotated
226 ? mDisplayContent.mBaseDisplayHeight
227 : mDisplayContent.mBaseDisplayWidth;
228 final int dh = rotated
229 ? mDisplayContent.mBaseDisplayWidth
230 : mDisplayContent.mBaseDisplayHeight;
231 mService.mPolicy.getStableInsetsLw(rotation, dw, dh, mTmpRect);
Andrii Kulianb10330d2016-09-16 13:51:46 -0700232 config.unset();
Jorim Jaggi85639432016-05-06 17:27:55 -0700233 config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
Bryce Lee7566d762017-03-30 09:34:15 -0700234
235 final int displayId = mDisplayContent.getDisplayId();
236 final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation,
237 baseConfig.uiMode, displayId);
238 final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
239 baseConfig.uiMode, displayId);
240 mService.mPolicy.getNonDecorInsetsLw(rotation, dw, dh, mTmpRect);
241 final int leftInset = mTmpRect.left;
242 final int topInset = mTmpRect.top;
243
Wale Ogunwale822e5122017-07-26 06:02:24 -0700244 config.windowConfiguration.setAppBounds(leftInset /*left*/, topInset /*top*/,
245 leftInset + appWidth /*right*/, topInset + appHeight /*bottom*/);
Bryce Lee7566d762017-03-30 09:34:15 -0700246
Jorim Jaggi85639432016-05-06 17:27:55 -0700247 config.screenWidthDp = (int)
Andrii Kuliandb8e1062016-11-15 18:30:27 -0800248 (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode,
Bryce Lee7566d762017-03-30 09:34:15 -0700249 displayId) / mDisplayContent.getDisplayMetrics().density);
Jorim Jaggi85639432016-05-06 17:27:55 -0700250 config.screenHeightDp = (int)
Andrii Kuliandb8e1062016-11-15 18:30:27 -0800251 (mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, baseConfig.uiMode,
Bryce Lee7566d762017-03-30 09:34:15 -0700252 displayId) / mDisplayContent.getDisplayMetrics().density);
Jorim Jaggi85639432016-05-06 17:27:55 -0700253 final Context rotationContext = mService.mContext.createConfigurationContext(config);
254 mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
255 rotationContext.getResources(), dw, dh, getContentWidth(),
256 config.orientation == ORIENTATION_PORTRAIT, mTmpRect);
257 }
258 }
259
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700260 private void loadDimens() {
261 final Context context = mService.mContext;
262 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
263 com.android.internal.R.dimen.docked_stack_divider_thickness);
264 mDividerInsets = context.getResources().getDimensionPixelSize(
265 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700266 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
267 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Matthew Nge15352e2016-12-20 15:36:29 -0800268 mTaskHeightInMinimizedMode = context.getResources().getDimensionPixelSize(
269 com.android.internal.R.dimen.task_height_of_minimized_mode);
Jorim Jaggi85639432016-05-06 17:27:55 -0700270 initSnapAlgorithmForRotations();
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700271 }
272
273 void onConfigurationChanged() {
274 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700275 }
276
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100277 boolean isResizing() {
278 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700279 }
280
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100281 int getContentWidth() {
282 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700283 }
284
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800285 int getContentInsets() {
286 return mDividerInsets;
287 }
288
Chong Zhang198afac2016-04-15 12:03:11 -0700289 int getContentWidthInactive() {
290 return mDividerWindowWidthInactive;
291 }
292
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100293 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800294 if (mResizing != resizing) {
295 mResizing = resizing;
296 resetDragResizingChangeReported();
297 }
298 }
299
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100300 void setTouchRegion(Rect touchRegion) {
301 mTouchRegion.set(touchRegion);
302 }
303
304 void getTouchRegion(Rect outRegion) {
305 outRegion.set(mTouchRegion);
306 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
307 }
308
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800309 private void resetDragResizingChangeReported() {
Wale Ogunwaled1880962016-11-08 10:31:59 -0800310 mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
311 true /* traverseTopToBottom */ );
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100312 }
313
314 void setWindow(WindowState window) {
315 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800316 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100317 }
318
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800319 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800320 if (mWindow == null) {
321 return;
322 }
Jorim Jaggife762342016-10-13 14:33:27 +0200323 TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility();
Jorim Jaggi7998e482016-02-12 18:47:06 -0800324
325 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
326 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800327 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800328 return;
329 }
330 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100331 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100332 if (!visible) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700333 setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f);
Jorim Jaggi50981592015-12-29 17:54:12 +0100334 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100335 }
336
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700337 private boolean wasVisible() {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100338 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100339 }
340
Chong Zhangf347ab52016-04-18 21:02:01 -0700341 void setAdjustedForIme(
342 boolean adjustedForIme, boolean adjustedForDivider,
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700343 boolean animate, WindowState imeWin, int imeHeight) {
344 if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
345 || mAdjustedForDivider != adjustedForDivider) {
Jorim Jaggi3070e772016-05-17 16:41:32 -0700346 if (animate && !mAnimatingForMinimizedDockedStack) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700347 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700348 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700349 // Animation might be delayed, so only notify if we don't run an animation.
Chong Zhangf347ab52016-04-18 21:02:01 -0700350 notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700351 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700352 mAdjustedForIme = adjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700353 mImeHeight = imeHeight;
Chong Zhangf347ab52016-04-18 21:02:01 -0700354 mAdjustedForDivider = adjustedForDivider;
Chong Zhangbaba7832016-03-24 10:21:26 -0700355 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700356 }
357
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700358 int getImeHeightAdjustedFor() {
359 return mImeHeight;
360 }
361
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700362 void positionDockedStackedDivider(Rect frame) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700363 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700364 if (stack == null) {
365 // Unfortunately we might end up with still having a divider, even though the underlying
366 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800367 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
368 // keep putting it in the same place it was before the stack was removed to have
369 // continuity and prevent it from jumping to the center. It will get hidden soon.
370 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700371 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800372 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800373 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700374 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100375 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700376 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700377 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100378 frame.set(mTmpRect.right - mDividerInsets, frame.top,
379 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700380 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700381 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100382 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
383 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700384 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700385 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100386 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
387 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700388 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700389 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100390 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
391 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700392 break;
393 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800394 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700395 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800396
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700397 private void notifyDockedDividerVisibilityChanged(boolean visible) {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100398 final int size = mDockedStackListeners.beginBroadcast();
399 for (int i = 0; i < size; ++i) {
400 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
401 try {
402 listener.onDividerVisibilityChanged(visible);
403 } catch (RemoteException e) {
404 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
405 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800406 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100407 mDockedStackListeners.finishBroadcast();
408 }
409
410 void notifyDockedStackExistsChanged(boolean exists) {
Andrii Kulian5406e7a2016-10-21 11:55:23 -0700411 // TODO(multi-display): Perform all actions only for current display.
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100412 final int size = mDockedStackListeners.beginBroadcast();
413 for (int i = 0; i < size; ++i) {
414 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
415 try {
416 listener.onDockedStackExistsChanged(exists);
417 } catch (RemoteException e) {
418 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
419 }
420 }
421 mDockedStackListeners.finishBroadcast();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700422 if (exists) {
423 InputMethodManagerInternal inputMethodManagerInternal =
424 LocalServices.getService(InputMethodManagerInternal.class);
425 if (inputMethodManagerInternal != null) {
426
427 // Hide the current IME to avoid problems with animations from IME adjustment when
428 // attaching the docked stack.
429 inputMethodManagerInternal.hideCurrentInputMethod();
430 mImeHideRequested = true;
431 }
Matthew Ngbc527a32017-06-19 16:42:31 -0700432 return;
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700433 }
Matthew Ngbc527a32017-06-19 16:42:31 -0700434 setMinimizedDockedStack(false /* minimizedDock */, false /* animate */);
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100435 }
436
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700437 /**
438 * Resets the state that IME hide has been requested. See {@link #isImeHideRequested}.
439 */
440 void resetImeHideRequested() {
441 mImeHideRequested = false;
442 }
443
444 /**
445 * The docked stack divider controller makes sure the IME gets hidden when attaching the docked
446 * stack, to avoid animation problems. This flag indicates whether the request to hide the IME
447 * has been sent in an asynchronous manner, and the IME should be treated as hidden already.
448 *
449 * @return whether IME hide request has been sent
450 */
451 boolean isImeHideRequested() {
452 return mImeHideRequested;
453 }
454
Matthew Nge15352e2016-12-20 15:36:29 -0800455 private void notifyDockedStackMinimizedChanged(boolean minimizedDock, boolean animate,
456 boolean isHomeStackResizable) {
457 long animDuration = 0;
458 if (animate) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700459 final TaskStack stack =
460 mDisplayContent.getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Matthew Nge15352e2016-12-20 15:36:29 -0800461 final long transitionDuration = isAnimationMaximizing()
462 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
463 : DEFAULT_APP_TRANSITION_DURATION;
464 mAnimationDuration = (long)
465 (transitionDuration * mService.getTransitionAnimationScaleLocked());
466 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
467 animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
468 }
Tony Mak853304c2016-04-18 15:17:41 +0100469 mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
470 mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
471 minimizedDock ? 1 : 0, 0).sendToTarget();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800472 final int size = mDockedStackListeners.beginBroadcast();
473 for (int i = 0; i < size; ++i) {
474 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
475 try {
Matthew Nge15352e2016-12-20 15:36:29 -0800476 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration,
477 isHomeStackResizable);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800478 } catch (RemoteException e) {
479 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
480 }
481 }
482 mDockedStackListeners.finishBroadcast();
483 }
484
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700485 void notifyDockSideChanged(int newDockSide) {
486 final int size = mDockedStackListeners.beginBroadcast();
487 for (int i = 0; i < size; ++i) {
488 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
489 try {
490 listener.onDockSideChanged(newDockSide);
491 } catch (RemoteException e) {
492 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
493 }
494 }
495 mDockedStackListeners.finishBroadcast();
496 }
497
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700498 private void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
Jorim Jaggi698e7632016-04-13 21:02:22 -0700499 final int size = mDockedStackListeners.beginBroadcast();
500 for (int i = 0; i < size; ++i) {
501 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
502 try {
503 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
504 } catch (RemoteException e) {
505 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
506 }
507 }
508 mDockedStackListeners.finishBroadcast();
509 }
510
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100511 void registerDockedStackListener(IDockedStackListener listener) {
512 mDockedStackListeners.register(listener);
513 notifyDockedDividerVisibilityChanged(wasVisible());
Wale Ogunwale1666e312016-12-16 11:27:18 -0800514 notifyDockedStackExistsChanged(mDisplayContent.getDockedStackIgnoringVisibility() != null);
Matthew Nge15352e2016-12-20 15:36:29 -0800515 notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
516 isHomeStackResizable());
Jorim Jaggi698e7632016-04-13 21:02:22 -0700517 notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
518
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800519 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100520
Wale Ogunwale68278562017-09-23 17:13:55 -0700521 /**
522 * Shows a dim layer with {@param alpha} if {@param visible} is true and
523 * {@param targetWindowingMode} isn't
524 * {@link android.app.WindowConfiguration#WINDOWING_MODE_UNDEFINED} and there is a stack on the
525 * display in that windowing mode.
526 */
527 void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
Robert Carr68e5c9e2016-09-14 10:50:09 -0700528 mService.openSurfaceTransaction();
Wale Ogunwale68278562017-09-23 17:13:55 -0700529 // TODO: Maybe only allow split-screen windowing modes?
530 final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
531 ? mDisplayContent.getStack(targetWindowingMode)
532 : null;
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100533 final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
534 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100535 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100536 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100537 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100538 mDimLayer.setBounds(mTmpRect);
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700539 mDimLayer.show(getResizeDimLayer(), alpha, 0 /* duration */);
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100540 } else {
541 visibleAndValid = false;
542 }
543 }
544 if (!visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100545 mDimLayer.hide();
546 }
Robert Carr68e5c9e2016-09-14 10:50:09 -0700547 mService.closeSurfaceTransaction();
Jorim Jaggi50981592015-12-29 17:54:12 +0100548 }
549
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800550 /**
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700551 * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
552 * above all application surfaces.
553 */
554 private int getResizeDimLayer() {
555 return (mWindow != null) ? mWindow.mLayer - 1 : LAYER_OFFSET_DIM;
556 }
557
558 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800559 * Notifies the docked stack divider controller of a visibility change that happens without
560 * an animation.
561 */
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700562 void notifyAppVisibilityChanged() {
563 checkMinimizeChanged(false /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800564 }
565
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200566 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps, int appTransition) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700567 final boolean wasMinimized = mMinimizedDock;
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700568 checkMinimizeChanged(true /* animate */);
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700569
570 // We were minimized, and now we are still minimized, but somebody is trying to launch an
Matthew Ng8e265522017-02-13 11:09:37 -0800571 // app in docked stack, better show recent apps so we actually get unminimized! However do
572 // not do this if keyguard is dismissed such as when the device is unlocking. This catches
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700573 // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
574 // we couldn't retrace the launch of the app in the docked stack to the launch from
575 // homescreen.
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200576 if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
Matthew Ng8e265522017-02-13 11:09:37 -0800577 && appTransition != TRANSIT_NONE &&
578 !AppTransition.isKeyguardGoingAwayTransit(appTransition)) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700579 mService.showRecentApps(true /* fromHome */);
580 }
581 }
582
583 /**
584 * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
585 */
586 private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
587 for (int i = apps.size() - 1; i >= 0; i--) {
588 final AppWindowToken token = apps.valueAt(i);
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700589 if (token.getTask() != null && token.inSplitScreenPrimaryWindowingMode()) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700590 return true;
591 }
592 }
593 return false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800594 }
595
Jorim Jaggi1ae68bf2016-05-09 18:44:34 -0700596 boolean isMinimizedDock() {
597 return mMinimizedDock;
598 }
599
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700600 private void checkMinimizeChanged(boolean animate) {
Jorim Jaggife762342016-10-13 14:33:27 +0200601 if (mDisplayContent.getDockedStackIgnoringVisibility() == null) {
Jorim Jaggi817a5242016-05-06 15:45:00 -0700602 return;
603 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700604 final TaskStack homeStack = mDisplayContent.getHomeStack();
605 if (homeStack == null) {
606 return;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800607 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700608 final Task homeTask = homeStack.findHomeTask();
609 if (homeTask == null || !isWithinDisplay(homeTask)) {
610 return;
611 }
Matthew Ng8e265522017-02-13 11:09:37 -0800612
613 // Do not minimize when dock is already minimized while keyguard is showing and not
614 // occluded such as unlocking the screen
615 if (mMinimizedDock && mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
616 return;
617 }
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700618 final TaskStack fullscreenStack = mDisplayContent.getStack(
619 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700620 final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700621 final boolean homeBehind = fullscreenStack != null && fullscreenStack.isVisible();
Wale Ogunwale069bbd32017-02-03 07:58:14 -0800622 setMinimizedDockedStack(homeVisible && !homeBehind, animate);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800623 }
624
625 private boolean isWithinDisplay(Task task) {
626 task.mStack.getBounds(mTmpRect);
627 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
628 return mTmpRect.intersect(mTmpRect2);
629 }
630
631 /**
632 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
633 * docked stack are heavily clipped so you can only see a minimal peek state.
634 *
635 * @param minimizedDock Whether the docked stack is currently minimized.
636 * @param animate Whether to animate the change.
637 */
638 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700639 final boolean wasMinimized = mMinimizedDock;
640 mMinimizedDock = minimizedDock;
Jorim Jaggi817a5242016-05-06 15:45:00 -0700641 if (minimizedDock == wasMinimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800642 return;
643 }
644
Chong Zhang22eff0a2016-07-01 14:48:11 -0700645 final boolean imeChanged = clearImeAdjustAnimation();
646 boolean minimizedChange = false;
Matthew Nge15352e2016-12-20 15:36:29 -0800647 if (isHomeStackResizable()) {
648 notifyDockedStackMinimizedChanged(minimizedDock, true /* animate */,
649 true /* isHomeStackResizable */);
650 minimizedChange = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800651 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800652 if (minimizedDock) {
653 if (animate) {
654 startAdjustAnimation(0f, 1f);
655 } else {
656 minimizedChange |= setMinimizedDockedStack(true);
657 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800658 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800659 if (animate) {
660 startAdjustAnimation(1f, 0f);
661 } else {
662 minimizedChange |= setMinimizedDockedStack(false);
663 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800664 }
665 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700666 if (imeChanged || minimizedChange) {
667 if (imeChanged && !minimizedChange) {
668 Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing,"
669 + " minimizedDock=" + minimizedDock
670 + " minimizedChange=" + minimizedChange);
671 }
672 mService.mWindowPlacerLocked.performSurfacePlacement();
673 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800674 }
675
Chong Zhang22eff0a2016-07-01 14:48:11 -0700676 private boolean clearImeAdjustAnimation() {
Wale Ogunwale10124582016-09-15 20:25:50 -0700677 final boolean changed = mDisplayContent.clearImeAdjustAnimation();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700678 mAnimatingForIme = false;
Chong Zhang22eff0a2016-07-01 14:48:11 -0700679 return changed;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700680 }
681
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800682 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700683 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800684 mAnimationStarted = false;
685 mAnimationStart = from;
686 mAnimationTarget = to;
687 }
688
Chong Zhangf347ab52016-04-18 21:02:01 -0700689 private void startImeAdjustAnimation(
690 boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700691
692 // If we're not in an animation, the starting point depends on whether we're adjusted
693 // or not. If we're already in an animation, we start from where the current animation
694 // left off, so that the motion doesn't look discontinuous.
695 if (!mAnimatingForIme) {
696 mAnimationStart = mAdjustedForIme ? 1 : 0;
697 mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
698 mLastAnimationProgress = mAnimationStart;
699 mLastDividerProgress = mDividerAnimationStart;
700 } else {
701 mAnimationStart = mLastAnimationProgress;
702 mDividerAnimationStart = mLastDividerProgress;
703 }
Jorim Jaggi3070e772016-05-17 16:41:32 -0700704 mAnimatingForIme = true;
705 mAnimationStarted = false;
Chong Zhangf347ab52016-04-18 21:02:01 -0700706 mAnimationTarget = adjustedForIme ? 1 : 0;
707 mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700708
Wale Ogunwale10124582016-09-15 20:25:50 -0700709 mDisplayContent.beginImeAdjustAnimation();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700710
711 // We put all tasks into drag resizing mode - wait until all of them have completed the
712 // drag resizing switch.
713 if (!mService.mWaitingForDrawn.isEmpty()) {
714 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
715 mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
716 IME_ADJUST_DRAWN_TIMEOUT);
717 mAnimationStartDelayed = true;
718 if (imeWin != null) {
719
720 // There might be an old window delaying the animation start - clear it.
721 if (mDelayedImeWin != null) {
722 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
723 }
724 mDelayedImeWin = imeWin;
725 imeWin.mWinAnimator.startDelayingAnimationStart();
726 }
Jorim Jaggi31883862016-11-04 15:45:30 -0700727
728 // If we are already waiting for something to be drawn, clear out the old one so it
729 // still gets executed.
730 // TODO: Have a real system where we can wait on different windows to be drawn with
731 // different callbacks.
732 if (mService.mWaitingForDrawnCallback != null) {
733 mService.mWaitingForDrawnCallback.run();
734 }
Jorim Jaggiff71d202016-04-14 13:12:36 -0700735 mService.mWaitingForDrawnCallback = () -> {
736 mAnimationStartDelayed = false;
737 if (mDelayedImeWin != null) {
738 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
739 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700740 // If the adjust status changed since this was posted, only notify
741 // the new states and don't animate.
742 long duration = 0;
743 if (mAdjustedForIme == adjustedForIme
744 && mAdjustedForDivider == adjustedForDivider) {
745 duration = IME_ADJUST_ANIM_DURATION;
746 } else {
747 Slog.w(TAG, "IME adjust changed while waiting for drawn:"
748 + " adjustedForIme=" + adjustedForIme
749 + " adjustedForDivider=" + adjustedForDivider
750 + " mAdjustedForIme=" + mAdjustedForIme
751 + " mAdjustedForDivider=" + mAdjustedForDivider);
752 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700753 notifyAdjustedForImeChanged(
Chong Zhang22eff0a2016-07-01 14:48:11 -0700754 mAdjustedForIme || mAdjustedForDivider, duration);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700755 };
756 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700757 notifyAdjustedForImeChanged(
758 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700759 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700760 }
761
Chong Zhang22eff0a2016-07-01 14:48:11 -0700762 private boolean setMinimizedDockedStack(boolean minimized) {
Jorim Jaggife762342016-10-13 14:33:27 +0200763 final TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility();
Matthew Nge15352e2016-12-20 15:36:29 -0800764 notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
Chong Zhang22eff0a2016-07-01 14:48:11 -0700765 return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800766 }
767
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800768 private boolean isAnimationMaximizing() {
769 return mAnimationTarget == 0f;
770 }
771
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800772 public boolean animate(long now) {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700773 if (mWindow == null) {
774 return false;
775 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700776 if (mAnimatingForMinimizedDockedStack) {
777 return animateForMinimizedDockedStack(now);
778 } else if (mAnimatingForIme) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700779 return animateForIme(now);
Chong Zhangbaba7832016-03-24 10:21:26 -0700780 } else {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700781 if (mDimLayer != null && mDimLayer.isDimming()) {
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700782 mDimLayer.setLayer(getResizeDimLayer());
Chong Zhang1402c2e2016-04-21 15:17:47 -0700783 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800784 return false;
785 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700786 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800787
Jorim Jaggieb88d832016-04-13 20:17:43 -0700788 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700789 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700790 mAnimationStarted = true;
791 mAnimationStartTime = now;
792 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700793 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700794 }
795 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
796 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
797 .getInterpolation(t);
Wale Ogunwale10124582016-09-15 20:25:50 -0700798 final boolean updated =
799 mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700800 if (updated) {
801 mService.mWindowPlacerLocked.performSurfacePlacement();
802 }
803 if (t >= 1.0f) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700804 mLastAnimationProgress = mAnimationTarget;
805 mLastDividerProgress = mDividerAnimationTarget;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700806 mAnimatingForIme = false;
807 return false;
808 } else {
809 return true;
810 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700811 }
812
813 private boolean animateForMinimizedDockedStack(long now) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700814 final TaskStack stack =
815 mDisplayContent.getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800816 if (!mAnimationStarted) {
817 mAnimationStarted = true;
818 mAnimationStartTime = now;
Matthew Nge15352e2016-12-20 15:36:29 -0800819 notifyDockedStackMinimizedChanged(mMinimizedDock, true /* animate */,
820 isHomeStackResizable() /* isHomeStackResizable */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800821 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800822 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
823 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
824 .getInterpolation(t);
Chong Zhang741c0ba2016-05-27 12:52:11 -0700825 if (stack != null) {
826 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
827 mService.mWindowPlacerLocked.performSurfacePlacement();
828 }
829 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800830 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700831 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800832 return false;
833 } else {
834 return true;
835 }
836 }
837
Wale Ogunwale10124582016-09-15 20:25:50 -0700838 float getInterpolatedAnimationValue(float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700839 return t * mAnimationTarget + (1 - t) * mAnimationStart;
840 }
841
Wale Ogunwale10124582016-09-15 20:25:50 -0700842 float getInterpolatedDividerValue(float t) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700843 return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
844 }
845
Jorim Jaggif97ed922016-02-18 18:57:07 -0800846 /**
847 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
848 */
849 private float getMinimizeAmount(TaskStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700850 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800851 if (isAnimationMaximizing()) {
852 return adjustMaximizeAmount(stack, t, naturalAmount);
853 } else {
854 return naturalAmount;
855 }
856 }
857
858 /**
859 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
860 * during the transition such that the edge of the clip reveal rect is met earlier in the
861 * transition so we don't create a visible "hole", but only if both the clip reveal and the
862 * docked stack divider start from about the same portion on the screen.
863 */
864 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
865 if (mMaximizeMeetFraction == 1f) {
866 return naturalAmount;
867 }
868 final int minimizeDistance = stack.getMinimizeDistance();
869 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
870 / (float) minimizeDistance;
871 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
872 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
873 return amountPrime * t2 + naturalAmount * (1 - t2);
874 }
875
876 /**
877 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
878 * edge. See {@link #adjustMaximizeAmount}.
879 */
880 private float getClipRevealMeetFraction(TaskStack stack) {
881 if (!isAnimationMaximizing() || stack == null ||
882 !mService.mAppTransition.hadClipRevealAnimation()) {
883 return 1f;
884 }
885 final int minimizeDistance = stack.getMinimizeDistance();
886 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
887 / (float) minimizeDistance;
888 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
889 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
890 return CLIP_REVEAL_MEET_EARLIEST
891 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
892 }
893
Jorim Jaggi50981592015-12-29 17:54:12 +0100894 @Override
Wale Ogunwale29bfbb82016-05-12 15:13:52 -0700895 public boolean dimFullscreen() {
Jorim Jaggi50981592015-12-29 17:54:12 +0100896 return false;
897 }
898
899 @Override
900 public DisplayInfo getDisplayInfo() {
901 return mDisplayContent.getDisplayInfo();
902 }
903
904 @Override
Wale Ogunwalef0a60a92017-01-19 09:44:40 -0800905 public boolean isAttachedToDisplay() {
906 return mDisplayContent != null;
907 }
908
909 @Override
Jorim Jaggi50981592015-12-29 17:54:12 +0100910 public void getDimBounds(Rect outBounds) {
911 // This dim layer user doesn't need this.
912 }
913
914 @Override
915 public String toShortString() {
916 return TAG;
917 }
Robert Carre63e01a2016-04-18 20:27:34 -0700918
919 WindowState getWindow() {
920 return mWindow;
921 }
Jorim Jaggi31f71702016-05-04 16:43:04 -0700922
923 void dump(String prefix, PrintWriter pw) {
924 pw.println(prefix + "DockedStackDividerController");
925 pw.println(prefix + " mLastVisibility=" + mLastVisibility);
926 pw.println(prefix + " mMinimizedDock=" + mMinimizedDock);
927 pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme);
928 pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider);
929 if (mDimLayer.isDimming()) {
930 pw.println(prefix + " Dim layer is dimming: ");
931 mDimLayer.printTo(prefix + " ", pw);
932 }
933 }
Steven Timotiusaf03df62017-07-18 16:56:43 -0700934
935 void writeToProto(ProtoOutputStream proto, long fieldId) {
936 final long token = proto.start(fieldId);
937 proto.write(MINIMIZED_DOCK, mMinimizedDock);
938 proto.end(token);
939 }
Robert Carre63e01a2016-04-18 20:27:34 -0700940}