blob: 69f557b1a2a8b8ff6c0c94fcf1db96f59eaf8c0d [file] [log] [blame]
Filip Gruszczynski466f3212015-09-21 17:57:57 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wm;
18
Wale Ogunwaleb62139d2017-09-20 15:37:35 -070019import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Wale Ogunwale68278562017-09-23 17:13:55 -070020import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Jorim Jaggi85639432016-05-06 17:27:55 -070021import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
22import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
23import static android.view.Surface.ROTATION_270;
24import static android.view.Surface.ROTATION_90;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010025import static android.view.WindowManager.DOCKED_BOTTOM;
26import static android.view.WindowManager.DOCKED_LEFT;
27import static android.view.WindowManager.DOCKED_RIGHT;
28import static android.view.WindowManager.DOCKED_TOP;
29import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
30import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
Jorim Jaggi84afb1a2016-09-28 14:54:04 +020031import static com.android.server.wm.AppTransition.TRANSIT_NONE;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010032import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
33import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Tony Mak853304c2016-04-18 15:17:41 +010034import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
Wale Ogunwalec69694a2016-10-18 13:51:15 -070035import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
Steven Timotiusaf03df62017-07-18 16:56:43 -070036import static com.android.server.wm.proto.DockedStackDividerControllerProto.MINIMIZED_DOCK;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010037
Filip Gruszczynski466f3212015-09-21 17:57:57 -070038import android.content.Context;
Jorim Jaggi85639432016-05-06 17:27:55 -070039import android.content.res.Configuration;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070040import android.graphics.Rect;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010041import android.os.RemoteCallbackList;
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080042import android.os.RemoteException;
Jorim Jaggi936aaeb2016-08-26 19:02:11 -070043import android.util.ArraySet;
Filip Gruszczynski77049052015-11-09 14:01:21 -080044import android.util.Slog;
Steven Timotiusaf03df62017-07-18 16:56:43 -070045import android.util.proto.ProtoOutputStream;
Jorim Jaggi50981592015-12-29 17:54:12 +010046import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010047import android.view.IDockedStackListener;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080048import android.view.animation.AnimationUtils;
49import android.view.animation.Interpolator;
Jorim Jaggieb88d832016-04-13 20:17:43 -070050import android.view.animation.PathInterpolator;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070051import android.view.inputmethod.InputMethodManagerInternal;
Jorim Jaggi50981592015-12-29 17:54:12 +010052
Jorim Jaggi85639432016-05-06 17:27:55 -070053import com.android.internal.policy.DividerSnapAlgorithm;
54import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070055import com.android.server.LocalServices;
Jorim Jaggi50981592015-12-29 17:54:12 +010056import com.android.server.wm.DimLayer.DimLayerUser;
Jorim Jaggiff71d202016-04-14 13:12:36 -070057import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010058
Jorim Jaggi31f71702016-05-04 16:43:04 -070059import java.io.PrintWriter;
Chong Zhangbaba7832016-03-24 10:21:26 -070060
Filip Gruszczynski466f3212015-09-21 17:57:57 -070061/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010062 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070063 */
Jorim Jaggi50981592015-12-29 17:54:12 +010064public class DockedStackDividerController implements DimLayerUser {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010065
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080066 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010067
Jorim Jaggif97ed922016-02-18 18:57:07 -080068 /**
69 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
70 * revealing surface at the earliest.
71 */
72 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
73
74 /**
75 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
76 * revealing surface at the latest.
77 */
78 private static final float CLIP_REVEAL_MEET_LAST = 1f;
79
80 /**
81 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
82 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
83 */
84 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
85
86 /**
87 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
88 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
89 */
90 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
91
Jorim Jaggieb88d832016-04-13 20:17:43 -070092 private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
Jorim Jaggiff71d202016-04-14 13:12:36 -070093 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggieb88d832016-04-13 20:17:43 -070094
Jorim Jaggi698e7632016-04-13 21:02:22 -070095 private static final long IME_ADJUST_ANIM_DURATION = 280;
Jorim Jaggieb88d832016-04-13 20:17:43 -070096
Jorim Jaggiff71d202016-04-14 13:12:36 -070097 private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
98
Chong Zhang198afac2016-04-15 12:03:11 -070099 private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
100
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800101 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700102 private final DisplayContent mDisplayContent;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700103 private int mDividerWindowWidth;
Chong Zhang198afac2016-04-15 12:03:11 -0700104 private int mDividerWindowWidthInactive;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700105 private int mDividerInsets;
Matthew Nge15352e2016-12-20 15:36:29 -0800106 private int mTaskHeightInMinimizedMode;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100107 private boolean mResizing;
108 private WindowState mWindow;
109 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800110 private final Rect mTmpRect2 = new Rect();
Jorim Jaggi85639432016-05-06 17:27:55 -0700111 private final Rect mTmpRect3 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -0800112 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800113 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100114 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
115 = new RemoteCallbackList<>();
Jorim Jaggi50981592015-12-29 17:54:12 +0100116 private final DimLayer mDimLayer;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700117
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800118 private boolean mMinimizedDock;
Chong Zhangbaba7832016-03-24 10:21:26 -0700119 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800120 private boolean mAnimationStarted;
121 private long mAnimationStartTime;
122 private float mAnimationStart;
123 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800124 private long mAnimationDuration;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700125 private boolean mAnimationStartDelayed;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800126 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800127 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100128 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700129 private boolean mAnimatingForIme;
130 private boolean mAdjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700131 private int mImeHeight;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700132 private WindowState mDelayedImeWin;
Chong Zhangf347ab52016-04-18 21:02:01 -0700133 private boolean mAdjustedForDivider;
134 private float mDividerAnimationStart;
135 private float mDividerAnimationTarget;
Wale Ogunwale10124582016-09-15 20:25:50 -0700136 float mLastAnimationProgress;
137 float mLastDividerProgress;
Jorim Jaggi85639432016-05-06 17:27:55 -0700138 private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700139 private boolean mImeHideRequested;
Jorim Jaggif93ac2b2017-10-25 15:20:24 +0200140 private final Rect mLastDimLayerRect = new Rect();
141 private float mLastDimLayerAlpha;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800142
143 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
144 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700145 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800146 final Context context = service.mContext;
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100147 mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
148 "DockedStackDim");
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800149 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
150 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700151 loadDimens();
152 }
153
Jorim Jaggi85639432016-05-06 17:27:55 -0700154 int getSmallestWidthDpForBounds(Rect bounds) {
155 final DisplayInfo di = mDisplayContent.getDisplayInfo();
156
Jorim Jaggi85639432016-05-06 17:27:55 -0700157 final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
158 final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
159 int minWidth = Integer.MAX_VALUE;
160
161 // Go through all screen orientations and find the orientation in which the task has the
162 // smallest width.
163 for (int rotation = 0; rotation < 4; rotation++) {
164 mTmpRect.set(bounds);
165 mDisplayContent.rotateBounds(di.rotation, rotation, mTmpRect);
166 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
167 mTmpRect2.set(0, 0,
168 rotated ? baseDisplayHeight : baseDisplayWidth,
169 rotated ? baseDisplayWidth : baseDisplayHeight);
170 final int orientation = mTmpRect2.width() <= mTmpRect2.height()
171 ? ORIENTATION_PORTRAIT
172 : ORIENTATION_LANDSCAPE;
173 final int dockSide = TaskStack.getDockSideUnchecked(mTmpRect, mTmpRect2, orientation);
174 final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
175 getContentWidth());
176
177 // Since we only care about feasible states, snap to the closest snap target, like it
178 // would happen when actually rotating the screen.
179 final int snappedPosition = mSnapAlgorithmForRotation[rotation]
180 .calculateNonDismissingSnapTarget(position).position;
181 DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, mTmpRect,
182 mTmpRect2.width(), mTmpRect2.height(), getContentWidth());
183 mService.mPolicy.getStableInsetsLw(rotation, mTmpRect2.width(), mTmpRect2.height(),
184 mTmpRect3);
Winson Chungbdc646f2017-02-13 12:12:22 -0800185 mService.intersectDisplayInsetBounds(mTmpRect2, mTmpRect3, mTmpRect);
Jorim Jaggi85639432016-05-06 17:27:55 -0700186 minWidth = Math.min(mTmpRect.width(), minWidth);
187 }
188 return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
189 }
190
Matthew Nge15352e2016-12-20 15:36:29 -0800191 void getHomeStackBoundsInDockedMode(Rect outBounds) {
192 final DisplayInfo di = mDisplayContent.getDisplayInfo();
193 mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
194 mTmpRect);
195 int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
196 Configuration configuration = mDisplayContent.getConfiguration();
Matthew Nga9e173d2017-05-17 15:03:18 -0700197 // The offset in the left (landscape)/top (portrait) is calculated with the minimized
198 // offset value with the divider size and any system insets in that direction.
Matthew Nge15352e2016-12-20 15:36:29 -0800199 if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
200 outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
201 di.logicalWidth, di.logicalHeight);
202 } else {
Matthew Nga9e173d2017-05-17 15:03:18 -0700203 // In landscape append the left position with the statusbar height to match the
204 // minimized size height in portrait mode.
205 outBounds.set(mTaskHeightInMinimizedMode + dividerSize + mTmpRect.left + mTmpRect.top,
206 0, di.logicalWidth, di.logicalHeight);
Matthew Nge15352e2016-12-20 15:36:29 -0800207 }
208 }
209
210 boolean isHomeStackResizable() {
211 final TaskStack homeStack = mDisplayContent.getHomeStack();
212 if (homeStack == null) {
213 return false;
214 }
215 final Task homeTask = homeStack.findHomeTask();
216 return homeTask != null && homeTask.isResizeable();
217 }
218
Jorim Jaggi85639432016-05-06 17:27:55 -0700219 private void initSnapAlgorithmForRotations() {
Andrii Kulian441e4492016-09-29 15:25:00 -0700220 final Configuration baseConfig = mDisplayContent.getConfiguration();
Jorim Jaggi85639432016-05-06 17:27:55 -0700221
222 // Initialize the snap algorithms for all 4 screen orientations.
223 final Configuration config = new Configuration();
224 for (int rotation = 0; rotation < 4; rotation++) {
225 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
226 final int dw = rotated
227 ? mDisplayContent.mBaseDisplayHeight
228 : mDisplayContent.mBaseDisplayWidth;
229 final int dh = rotated
230 ? mDisplayContent.mBaseDisplayWidth
231 : mDisplayContent.mBaseDisplayHeight;
232 mService.mPolicy.getStableInsetsLw(rotation, dw, dh, mTmpRect);
Andrii Kulianb10330d2016-09-16 13:51:46 -0700233 config.unset();
Jorim Jaggi85639432016-05-06 17:27:55 -0700234 config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
Bryce Lee7566d762017-03-30 09:34:15 -0700235
236 final int displayId = mDisplayContent.getDisplayId();
237 final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation,
238 baseConfig.uiMode, displayId);
239 final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
240 baseConfig.uiMode, displayId);
241 mService.mPolicy.getNonDecorInsetsLw(rotation, dw, dh, mTmpRect);
242 final int leftInset = mTmpRect.left;
243 final int topInset = mTmpRect.top;
244
Wale Ogunwale822e5122017-07-26 06:02:24 -0700245 config.windowConfiguration.setAppBounds(leftInset /*left*/, topInset /*top*/,
246 leftInset + appWidth /*right*/, topInset + appHeight /*bottom*/);
Bryce Lee7566d762017-03-30 09:34:15 -0700247
Jorim Jaggi85639432016-05-06 17:27:55 -0700248 config.screenWidthDp = (int)
Andrii Kuliandb8e1062016-11-15 18:30:27 -0800249 (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode,
Bryce Lee7566d762017-03-30 09:34:15 -0700250 displayId) / mDisplayContent.getDisplayMetrics().density);
Jorim Jaggi85639432016-05-06 17:27:55 -0700251 config.screenHeightDp = (int)
Andrii Kuliandb8e1062016-11-15 18:30:27 -0800252 (mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, baseConfig.uiMode,
Bryce Lee7566d762017-03-30 09:34:15 -0700253 displayId) / mDisplayContent.getDisplayMetrics().density);
Jorim Jaggi85639432016-05-06 17:27:55 -0700254 final Context rotationContext = mService.mContext.createConfigurationContext(config);
255 mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
256 rotationContext.getResources(), dw, dh, getContentWidth(),
257 config.orientation == ORIENTATION_PORTRAIT, mTmpRect);
258 }
259 }
260
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700261 private void loadDimens() {
262 final Context context = mService.mContext;
263 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
264 com.android.internal.R.dimen.docked_stack_divider_thickness);
265 mDividerInsets = context.getResources().getDimensionPixelSize(
266 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700267 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
268 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Matthew Nge15352e2016-12-20 15:36:29 -0800269 mTaskHeightInMinimizedMode = context.getResources().getDimensionPixelSize(
270 com.android.internal.R.dimen.task_height_of_minimized_mode);
Jorim Jaggi85639432016-05-06 17:27:55 -0700271 initSnapAlgorithmForRotations();
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700272 }
273
274 void onConfigurationChanged() {
275 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700276 }
277
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100278 boolean isResizing() {
279 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700280 }
281
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100282 int getContentWidth() {
283 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700284 }
285
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800286 int getContentInsets() {
287 return mDividerInsets;
288 }
289
Chong Zhang198afac2016-04-15 12:03:11 -0700290 int getContentWidthInactive() {
291 return mDividerWindowWidthInactive;
292 }
293
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100294 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800295 if (mResizing != resizing) {
296 mResizing = resizing;
297 resetDragResizingChangeReported();
298 }
299 }
300
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100301 void setTouchRegion(Rect touchRegion) {
302 mTouchRegion.set(touchRegion);
303 }
304
305 void getTouchRegion(Rect outRegion) {
306 outRegion.set(mTouchRegion);
307 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
308 }
309
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800310 private void resetDragResizingChangeReported() {
Wale Ogunwaled1880962016-11-08 10:31:59 -0800311 mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
312 true /* traverseTopToBottom */ );
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100313 }
314
315 void setWindow(WindowState window) {
316 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800317 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100318 }
319
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800320 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800321 if (mWindow == null) {
322 return;
323 }
Matthew Ng64e77cf2017-10-31 14:01:31 -0700324 TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Jorim Jaggi7998e482016-02-12 18:47:06 -0800325
326 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
327 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800328 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800329 return;
330 }
331 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100332 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100333 if (!visible) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700334 setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f);
Jorim Jaggi50981592015-12-29 17:54:12 +0100335 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100336 }
337
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700338 private boolean wasVisible() {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100339 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100340 }
341
Chong Zhangf347ab52016-04-18 21:02:01 -0700342 void setAdjustedForIme(
343 boolean adjustedForIme, boolean adjustedForDivider,
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700344 boolean animate, WindowState imeWin, int imeHeight) {
345 if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
346 || mAdjustedForDivider != adjustedForDivider) {
Jorim Jaggi3070e772016-05-17 16:41:32 -0700347 if (animate && !mAnimatingForMinimizedDockedStack) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700348 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700349 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700350 // Animation might be delayed, so only notify if we don't run an animation.
Chong Zhangf347ab52016-04-18 21:02:01 -0700351 notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700352 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700353 mAdjustedForIme = adjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700354 mImeHeight = imeHeight;
Chong Zhangf347ab52016-04-18 21:02:01 -0700355 mAdjustedForDivider = adjustedForDivider;
Chong Zhangbaba7832016-03-24 10:21:26 -0700356 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700357 }
358
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700359 int getImeHeightAdjustedFor() {
360 return mImeHeight;
361 }
362
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700363 void positionDockedStackedDivider(Rect frame) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700364 TaskStack stack = mDisplayContent.getSplitScreenPrimaryStack();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700365 if (stack == null) {
366 // Unfortunately we might end up with still having a divider, even though the underlying
367 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800368 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
369 // keep putting it in the same place it was before the stack was removed to have
370 // continuity and prevent it from jumping to the center. It will get hidden soon.
371 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700372 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800373 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800374 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700375 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100376 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700377 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700378 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100379 frame.set(mTmpRect.right - mDividerInsets, frame.top,
380 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700381 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700382 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100383 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
384 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700385 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700386 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100387 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
388 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700389 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700390 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100391 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
392 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700393 break;
394 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800395 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700396 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800397
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700398 private void notifyDockedDividerVisibilityChanged(boolean visible) {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100399 final int size = mDockedStackListeners.beginBroadcast();
400 for (int i = 0; i < size; ++i) {
401 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
402 try {
403 listener.onDividerVisibilityChanged(visible);
404 } catch (RemoteException e) {
405 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
406 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800407 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100408 mDockedStackListeners.finishBroadcast();
409 }
410
411 void notifyDockedStackExistsChanged(boolean exists) {
Andrii Kulian5406e7a2016-10-21 11:55:23 -0700412 // TODO(multi-display): Perform all actions only for current display.
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100413 final int size = mDockedStackListeners.beginBroadcast();
414 for (int i = 0; i < size; ++i) {
415 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
416 try {
417 listener.onDockedStackExistsChanged(exists);
418 } catch (RemoteException e) {
419 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
420 }
421 }
422 mDockedStackListeners.finishBroadcast();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700423 if (exists) {
424 InputMethodManagerInternal inputMethodManagerInternal =
425 LocalServices.getService(InputMethodManagerInternal.class);
426 if (inputMethodManagerInternal != null) {
427
428 // Hide the current IME to avoid problems with animations from IME adjustment when
429 // attaching the docked stack.
430 inputMethodManagerInternal.hideCurrentInputMethod();
431 mImeHideRequested = true;
432 }
Matthew Ngbc527a32017-06-19 16:42:31 -0700433 return;
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700434 }
Matthew Ngbc527a32017-06-19 16:42:31 -0700435 setMinimizedDockedStack(false /* minimizedDock */, false /* animate */);
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100436 }
437
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700438 /**
439 * Resets the state that IME hide has been requested. See {@link #isImeHideRequested}.
440 */
441 void resetImeHideRequested() {
442 mImeHideRequested = false;
443 }
444
445 /**
446 * The docked stack divider controller makes sure the IME gets hidden when attaching the docked
447 * stack, to avoid animation problems. This flag indicates whether the request to hide the IME
448 * has been sent in an asynchronous manner, and the IME should be treated as hidden already.
449 *
450 * @return whether IME hide request has been sent
451 */
452 boolean isImeHideRequested() {
453 return mImeHideRequested;
454 }
455
Matthew Nge15352e2016-12-20 15:36:29 -0800456 private void notifyDockedStackMinimizedChanged(boolean minimizedDock, boolean animate,
457 boolean isHomeStackResizable) {
458 long animDuration = 0;
459 if (animate) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700460 final TaskStack stack =
Matthew Ng64e77cf2017-10-31 14:01:31 -0700461 mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Matthew Nge15352e2016-12-20 15:36:29 -0800462 final long transitionDuration = isAnimationMaximizing()
463 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
464 : DEFAULT_APP_TRANSITION_DURATION;
465 mAnimationDuration = (long)
466 (transitionDuration * mService.getTransitionAnimationScaleLocked());
467 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
468 animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
469 }
Tony Mak853304c2016-04-18 15:17:41 +0100470 mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
471 mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
472 minimizedDock ? 1 : 0, 0).sendToTarget();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800473 final int size = mDockedStackListeners.beginBroadcast();
474 for (int i = 0; i < size; ++i) {
475 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
476 try {
Matthew Nge15352e2016-12-20 15:36:29 -0800477 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration,
478 isHomeStackResizable);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800479 } catch (RemoteException e) {
480 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
481 }
482 }
483 mDockedStackListeners.finishBroadcast();
484 }
485
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700486 void notifyDockSideChanged(int newDockSide) {
487 final int size = mDockedStackListeners.beginBroadcast();
488 for (int i = 0; i < size; ++i) {
489 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
490 try {
491 listener.onDockSideChanged(newDockSide);
492 } catch (RemoteException e) {
493 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
494 }
495 }
496 mDockedStackListeners.finishBroadcast();
497 }
498
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700499 private void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
Jorim Jaggi698e7632016-04-13 21:02:22 -0700500 final int size = mDockedStackListeners.beginBroadcast();
501 for (int i = 0; i < size; ++i) {
502 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
503 try {
504 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
505 } catch (RemoteException e) {
506 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
507 }
508 }
509 mDockedStackListeners.finishBroadcast();
510 }
511
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100512 void registerDockedStackListener(IDockedStackListener listener) {
513 mDockedStackListeners.register(listener);
514 notifyDockedDividerVisibilityChanged(wasVisible());
Wale Ogunwale61911492017-10-11 08:50:50 -0700515 notifyDockedStackExistsChanged(
Matthew Ng64e77cf2017-10-31 14:01:31 -0700516 mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() != 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) {
Wale Ogunwale68278562017-09-23 17:13:55 -0700530 // TODO: Maybe only allow split-screen windowing modes?
531 final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
532 ? mDisplayContent.getStack(targetWindowingMode)
533 : null;
Matthew Ng64e77cf2017-10-31 14:01:31 -0700534 final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStack();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100535 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100536 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100537 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100538 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggif93ac2b2017-10-25 15:20:24 +0200539 if (!mLastDimLayerRect.equals(mTmpRect) || mLastDimLayerAlpha != alpha) {
540 try {
541 // TODO: This should use the regular animation transaction - here and below
542 mService.openSurfaceTransaction();
543 mDimLayer.setBounds(mTmpRect);
544 mDimLayer.show(getResizeDimLayer(), alpha, 0 /* duration */);
545 } finally {
546 mService.closeSurfaceTransaction();
547 }
548 }
549 mLastDimLayerRect.set(mTmpRect);
550 mLastDimLayerAlpha = alpha;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100551 } else {
552 visibleAndValid = false;
553 }
554 }
555 if (!visibleAndValid) {
Jorim Jaggif93ac2b2017-10-25 15:20:24 +0200556 if (mLastDimLayerAlpha != 0f) {
557 try {
558 mService.openSurfaceTransaction();
559 mDimLayer.hide();
560 } finally {
561 mService.closeSurfaceTransaction();
562 }
563 }
564 mLastDimLayerAlpha = 0f;
Jorim Jaggi50981592015-12-29 17:54:12 +0100565 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100566 }
567
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800568 /**
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700569 * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
570 * above all application surfaces.
571 */
572 private int getResizeDimLayer() {
573 return (mWindow != null) ? mWindow.mLayer - 1 : LAYER_OFFSET_DIM;
574 }
575
576 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800577 * Notifies the docked stack divider controller of a visibility change that happens without
578 * an animation.
579 */
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700580 void notifyAppVisibilityChanged() {
581 checkMinimizeChanged(false /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800582 }
583
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200584 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps, int appTransition) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700585 final boolean wasMinimized = mMinimizedDock;
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700586 checkMinimizeChanged(true /* animate */);
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700587
588 // We were minimized, and now we are still minimized, but somebody is trying to launch an
Matthew Ng8e265522017-02-13 11:09:37 -0800589 // app in docked stack, better show recent apps so we actually get unminimized! However do
590 // not do this if keyguard is dismissed such as when the device is unlocking. This catches
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700591 // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
592 // we couldn't retrace the launch of the app in the docked stack to the launch from
593 // homescreen.
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200594 if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
Matthew Ng8e265522017-02-13 11:09:37 -0800595 && appTransition != TRANSIT_NONE &&
596 !AppTransition.isKeyguardGoingAwayTransit(appTransition)) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700597 mService.showRecentApps(true /* fromHome */);
598 }
599 }
600
601 /**
602 * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
603 */
604 private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
605 for (int i = apps.size() - 1; i >= 0; i--) {
606 final AppWindowToken token = apps.valueAt(i);
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700607 if (token.getTask() != null && token.inSplitScreenPrimaryWindowingMode()) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700608 return true;
609 }
610 }
611 return false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800612 }
613
Jorim Jaggi1ae68bf2016-05-09 18:44:34 -0700614 boolean isMinimizedDock() {
615 return mMinimizedDock;
616 }
617
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700618 private void checkMinimizeChanged(boolean animate) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700619 if (mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() == null) {
Jorim Jaggi817a5242016-05-06 15:45:00 -0700620 return;
621 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700622 final TaskStack homeStack = mDisplayContent.getHomeStack();
623 if (homeStack == null) {
624 return;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800625 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700626 final Task homeTask = homeStack.findHomeTask();
627 if (homeTask == null || !isWithinDisplay(homeTask)) {
628 return;
629 }
Matthew Ng8e265522017-02-13 11:09:37 -0800630
631 // Do not minimize when dock is already minimized while keyguard is showing and not
632 // occluded such as unlocking the screen
633 if (mMinimizedDock && mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
634 return;
635 }
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700636 final TaskStack fullscreenStack = mDisplayContent.getStack(
637 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700638 final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700639 final boolean homeBehind = fullscreenStack != null && fullscreenStack.isVisible();
Wale Ogunwale069bbd32017-02-03 07:58:14 -0800640 setMinimizedDockedStack(homeVisible && !homeBehind, animate);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800641 }
642
643 private boolean isWithinDisplay(Task task) {
644 task.mStack.getBounds(mTmpRect);
645 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
646 return mTmpRect.intersect(mTmpRect2);
647 }
648
649 /**
650 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
651 * docked stack are heavily clipped so you can only see a minimal peek state.
652 *
653 * @param minimizedDock Whether the docked stack is currently minimized.
654 * @param animate Whether to animate the change.
655 */
656 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700657 final boolean wasMinimized = mMinimizedDock;
658 mMinimizedDock = minimizedDock;
Jorim Jaggi817a5242016-05-06 15:45:00 -0700659 if (minimizedDock == wasMinimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800660 return;
661 }
662
Chong Zhang22eff0a2016-07-01 14:48:11 -0700663 final boolean imeChanged = clearImeAdjustAnimation();
664 boolean minimizedChange = false;
Matthew Nge15352e2016-12-20 15:36:29 -0800665 if (isHomeStackResizable()) {
666 notifyDockedStackMinimizedChanged(minimizedDock, true /* animate */,
667 true /* isHomeStackResizable */);
668 minimizedChange = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800669 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800670 if (minimizedDock) {
671 if (animate) {
672 startAdjustAnimation(0f, 1f);
673 } else {
674 minimizedChange |= setMinimizedDockedStack(true);
675 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800676 } else {
Matthew Nge15352e2016-12-20 15:36:29 -0800677 if (animate) {
678 startAdjustAnimation(1f, 0f);
679 } else {
680 minimizedChange |= setMinimizedDockedStack(false);
681 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800682 }
683 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700684 if (imeChanged || minimizedChange) {
685 if (imeChanged && !minimizedChange) {
686 Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing,"
687 + " minimizedDock=" + minimizedDock
688 + " minimizedChange=" + minimizedChange);
689 }
690 mService.mWindowPlacerLocked.performSurfacePlacement();
691 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800692 }
693
Chong Zhang22eff0a2016-07-01 14:48:11 -0700694 private boolean clearImeAdjustAnimation() {
Wale Ogunwale10124582016-09-15 20:25:50 -0700695 final boolean changed = mDisplayContent.clearImeAdjustAnimation();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700696 mAnimatingForIme = false;
Chong Zhang22eff0a2016-07-01 14:48:11 -0700697 return changed;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700698 }
699
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800700 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700701 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800702 mAnimationStarted = false;
703 mAnimationStart = from;
704 mAnimationTarget = to;
705 }
706
Chong Zhangf347ab52016-04-18 21:02:01 -0700707 private void startImeAdjustAnimation(
708 boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700709
710 // If we're not in an animation, the starting point depends on whether we're adjusted
711 // or not. If we're already in an animation, we start from where the current animation
712 // left off, so that the motion doesn't look discontinuous.
713 if (!mAnimatingForIme) {
714 mAnimationStart = mAdjustedForIme ? 1 : 0;
715 mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
716 mLastAnimationProgress = mAnimationStart;
717 mLastDividerProgress = mDividerAnimationStart;
718 } else {
719 mAnimationStart = mLastAnimationProgress;
720 mDividerAnimationStart = mLastDividerProgress;
721 }
Jorim Jaggi3070e772016-05-17 16:41:32 -0700722 mAnimatingForIme = true;
723 mAnimationStarted = false;
Chong Zhangf347ab52016-04-18 21:02:01 -0700724 mAnimationTarget = adjustedForIme ? 1 : 0;
725 mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700726
Wale Ogunwale10124582016-09-15 20:25:50 -0700727 mDisplayContent.beginImeAdjustAnimation();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700728
729 // We put all tasks into drag resizing mode - wait until all of them have completed the
730 // drag resizing switch.
731 if (!mService.mWaitingForDrawn.isEmpty()) {
732 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
733 mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
734 IME_ADJUST_DRAWN_TIMEOUT);
735 mAnimationStartDelayed = true;
736 if (imeWin != null) {
737
738 // There might be an old window delaying the animation start - clear it.
739 if (mDelayedImeWin != null) {
740 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
741 }
742 mDelayedImeWin = imeWin;
743 imeWin.mWinAnimator.startDelayingAnimationStart();
744 }
Jorim Jaggi31883862016-11-04 15:45:30 -0700745
746 // If we are already waiting for something to be drawn, clear out the old one so it
747 // still gets executed.
748 // TODO: Have a real system where we can wait on different windows to be drawn with
749 // different callbacks.
750 if (mService.mWaitingForDrawnCallback != null) {
751 mService.mWaitingForDrawnCallback.run();
752 }
Jorim Jaggiff71d202016-04-14 13:12:36 -0700753 mService.mWaitingForDrawnCallback = () -> {
754 mAnimationStartDelayed = false;
755 if (mDelayedImeWin != null) {
756 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
757 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700758 // If the adjust status changed since this was posted, only notify
759 // the new states and don't animate.
760 long duration = 0;
761 if (mAdjustedForIme == adjustedForIme
762 && mAdjustedForDivider == adjustedForDivider) {
763 duration = IME_ADJUST_ANIM_DURATION;
764 } else {
765 Slog.w(TAG, "IME adjust changed while waiting for drawn:"
766 + " adjustedForIme=" + adjustedForIme
767 + " adjustedForDivider=" + adjustedForDivider
768 + " mAdjustedForIme=" + mAdjustedForIme
769 + " mAdjustedForDivider=" + mAdjustedForDivider);
770 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700771 notifyAdjustedForImeChanged(
Chong Zhang22eff0a2016-07-01 14:48:11 -0700772 mAdjustedForIme || mAdjustedForDivider, duration);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700773 };
774 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700775 notifyAdjustedForImeChanged(
776 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700777 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700778 }
779
Chong Zhang22eff0a2016-07-01 14:48:11 -0700780 private boolean setMinimizedDockedStack(boolean minimized) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700781 final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Matthew Nge15352e2016-12-20 15:36:29 -0800782 notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
Chong Zhang22eff0a2016-07-01 14:48:11 -0700783 return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800784 }
785
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800786 private boolean isAnimationMaximizing() {
787 return mAnimationTarget == 0f;
788 }
789
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800790 public boolean animate(long now) {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700791 if (mWindow == null) {
792 return false;
793 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700794 if (mAnimatingForMinimizedDockedStack) {
795 return animateForMinimizedDockedStack(now);
796 } else if (mAnimatingForIme) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700797 return animateForIme(now);
Chong Zhangbaba7832016-03-24 10:21:26 -0700798 } else {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700799 if (mDimLayer != null && mDimLayer.isDimming()) {
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700800 mDimLayer.setLayer(getResizeDimLayer());
Chong Zhang1402c2e2016-04-21 15:17:47 -0700801 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800802 return false;
803 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700804 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800805
Jorim Jaggieb88d832016-04-13 20:17:43 -0700806 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700807 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700808 mAnimationStarted = true;
809 mAnimationStartTime = now;
810 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700811 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700812 }
813 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
814 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
815 .getInterpolation(t);
Wale Ogunwale10124582016-09-15 20:25:50 -0700816 final boolean updated =
817 mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700818 if (updated) {
819 mService.mWindowPlacerLocked.performSurfacePlacement();
820 }
821 if (t >= 1.0f) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700822 mLastAnimationProgress = mAnimationTarget;
823 mLastDividerProgress = mDividerAnimationTarget;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700824 mAnimatingForIme = false;
825 return false;
826 } else {
827 return true;
828 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700829 }
830
831 private boolean animateForMinimizedDockedStack(long now) {
Matthew Ng64e77cf2017-10-31 14:01:31 -0700832 final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800833 if (!mAnimationStarted) {
834 mAnimationStarted = true;
835 mAnimationStartTime = now;
Matthew Nge15352e2016-12-20 15:36:29 -0800836 notifyDockedStackMinimizedChanged(mMinimizedDock, true /* animate */,
837 isHomeStackResizable() /* isHomeStackResizable */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800838 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800839 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
840 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
841 .getInterpolation(t);
Chong Zhang741c0ba2016-05-27 12:52:11 -0700842 if (stack != null) {
843 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
844 mService.mWindowPlacerLocked.performSurfacePlacement();
845 }
846 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800847 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700848 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800849 return false;
850 } else {
851 return true;
852 }
853 }
854
Wale Ogunwale10124582016-09-15 20:25:50 -0700855 float getInterpolatedAnimationValue(float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700856 return t * mAnimationTarget + (1 - t) * mAnimationStart;
857 }
858
Wale Ogunwale10124582016-09-15 20:25:50 -0700859 float getInterpolatedDividerValue(float t) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700860 return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
861 }
862
Jorim Jaggif97ed922016-02-18 18:57:07 -0800863 /**
864 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
865 */
866 private float getMinimizeAmount(TaskStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700867 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800868 if (isAnimationMaximizing()) {
869 return adjustMaximizeAmount(stack, t, naturalAmount);
870 } else {
871 return naturalAmount;
872 }
873 }
874
875 /**
876 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
877 * during the transition such that the edge of the clip reveal rect is met earlier in the
878 * transition so we don't create a visible "hole", but only if both the clip reveal and the
879 * docked stack divider start from about the same portion on the screen.
880 */
881 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
882 if (mMaximizeMeetFraction == 1f) {
883 return naturalAmount;
884 }
885 final int minimizeDistance = stack.getMinimizeDistance();
886 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
887 / (float) minimizeDistance;
888 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
889 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
890 return amountPrime * t2 + naturalAmount * (1 - t2);
891 }
892
893 /**
894 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
895 * edge. See {@link #adjustMaximizeAmount}.
896 */
897 private float getClipRevealMeetFraction(TaskStack stack) {
898 if (!isAnimationMaximizing() || stack == null ||
899 !mService.mAppTransition.hadClipRevealAnimation()) {
900 return 1f;
901 }
902 final int minimizeDistance = stack.getMinimizeDistance();
903 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
904 / (float) minimizeDistance;
905 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
906 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
907 return CLIP_REVEAL_MEET_EARLIEST
908 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
909 }
910
Jorim Jaggi50981592015-12-29 17:54:12 +0100911 @Override
Wale Ogunwale29bfbb82016-05-12 15:13:52 -0700912 public boolean dimFullscreen() {
Jorim Jaggi50981592015-12-29 17:54:12 +0100913 return false;
914 }
915
916 @Override
917 public DisplayInfo getDisplayInfo() {
918 return mDisplayContent.getDisplayInfo();
919 }
920
921 @Override
Wale Ogunwalef0a60a92017-01-19 09:44:40 -0800922 public boolean isAttachedToDisplay() {
923 return mDisplayContent != null;
924 }
925
926 @Override
Jorim Jaggi50981592015-12-29 17:54:12 +0100927 public void getDimBounds(Rect outBounds) {
928 // This dim layer user doesn't need this.
929 }
930
931 @Override
932 public String toShortString() {
933 return TAG;
934 }
Robert Carre63e01a2016-04-18 20:27:34 -0700935
936 WindowState getWindow() {
937 return mWindow;
938 }
Jorim Jaggi31f71702016-05-04 16:43:04 -0700939
940 void dump(String prefix, PrintWriter pw) {
941 pw.println(prefix + "DockedStackDividerController");
942 pw.println(prefix + " mLastVisibility=" + mLastVisibility);
943 pw.println(prefix + " mMinimizedDock=" + mMinimizedDock);
944 pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme);
945 pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider);
946 if (mDimLayer.isDimming()) {
947 pw.println(prefix + " Dim layer is dimming: ");
948 mDimLayer.printTo(prefix + " ", pw);
949 }
950 }
Steven Timotiusaf03df62017-07-18 16:56:43 -0700951
952 void writeToProto(ProtoOutputStream proto, long fieldId) {
953 final long token = proto.start(fieldId);
954 proto.write(MINIMIZED_DOCK, mMinimizedDock);
955 proto.end(token);
956 }
Robert Carre63e01a2016-04-18 20:27:34 -0700957}