blob: ef8f492f5a6fc134f2c05e9ebe4e50810e10288c [file] [log] [blame]
Filip Gruszczynski466f3212015-09-21 17:57:57 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wm;
18
Jorim Jaggibc5425c2016-03-01 13:51:16 +010019import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
Jorim Jaggid3ec5072016-04-28 15:57:47 -070020import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010021import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
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;
32import 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;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010035
Filip Gruszczynski466f3212015-09-21 17:57:57 -070036import android.content.Context;
Jorim Jaggi85639432016-05-06 17:27:55 -070037import android.content.res.Configuration;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070038import android.graphics.Rect;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010039import android.os.RemoteCallbackList;
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080040import android.os.RemoteException;
Jorim Jaggi936aaeb2016-08-26 19:02:11 -070041import android.util.ArraySet;
Filip Gruszczynski77049052015-11-09 14:01:21 -080042import android.util.Slog;
Jorim Jaggi50981592015-12-29 17:54:12 +010043import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010044import android.view.IDockedStackListener;
Jorim Jaggi50981592015-12-29 17:54:12 +010045import android.view.SurfaceControl;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080046import android.view.animation.AnimationUtils;
47import android.view.animation.Interpolator;
Jorim Jaggieb88d832016-04-13 20:17:43 -070048import android.view.animation.PathInterpolator;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070049import android.view.inputmethod.InputMethodManagerInternal;
Jorim Jaggi50981592015-12-29 17:54:12 +010050
Jorim Jaggi85639432016-05-06 17:27:55 -070051import com.android.internal.policy.DividerSnapAlgorithm;
52import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070053import com.android.server.LocalServices;
Jorim Jaggi50981592015-12-29 17:54:12 +010054import com.android.server.wm.DimLayer.DimLayerUser;
Jorim Jaggiff71d202016-04-14 13:12:36 -070055import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010056
Jorim Jaggi31f71702016-05-04 16:43:04 -070057import java.io.PrintWriter;
Chong Zhangbaba7832016-03-24 10:21:26 -070058import java.util.ArrayList;
59
Filip Gruszczynski466f3212015-09-21 17:57:57 -070060/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010061 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070062 */
Jorim Jaggi50981592015-12-29 17:54:12 +010063public class DockedStackDividerController implements DimLayerUser {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010064
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080065 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010066
Jorim Jaggif97ed922016-02-18 18:57:07 -080067 /**
68 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
69 * revealing surface at the earliest.
70 */
71 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
72
73 /**
74 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
75 * revealing surface at the latest.
76 */
77 private static final float CLIP_REVEAL_MEET_LAST = 1f;
78
79 /**
80 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
81 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
82 */
83 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
84
85 /**
86 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
87 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
88 */
89 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
90
Jorim Jaggieb88d832016-04-13 20:17:43 -070091 private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
Jorim Jaggiff71d202016-04-14 13:12:36 -070092 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggieb88d832016-04-13 20:17:43 -070093
Jorim Jaggi698e7632016-04-13 21:02:22 -070094 private static final long IME_ADJUST_ANIM_DURATION = 280;
Jorim Jaggieb88d832016-04-13 20:17:43 -070095
Jorim Jaggiff71d202016-04-14 13:12:36 -070096 private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
97
Chong Zhang198afac2016-04-15 12:03:11 -070098 private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
99
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800100 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700101 private final DisplayContent mDisplayContent;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700102 private int mDividerWindowWidth;
Chong Zhang198afac2016-04-15 12:03:11 -0700103 private int mDividerWindowWidthInactive;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700104 private int mDividerInsets;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100105 private boolean mResizing;
106 private WindowState mWindow;
107 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800108 private final Rect mTmpRect2 = new Rect();
Jorim Jaggi85639432016-05-06 17:27:55 -0700109 private final Rect mTmpRect3 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -0800110 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800111 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100112 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
113 = new RemoteCallbackList<>();
Jorim Jaggi50981592015-12-29 17:54:12 +0100114 private final DimLayer mDimLayer;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700115
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800116 private boolean mMinimizedDock;
Chong Zhangbaba7832016-03-24 10:21:26 -0700117 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800118 private boolean mAnimationStarted;
119 private long mAnimationStartTime;
120 private float mAnimationStart;
121 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800122 private long mAnimationDuration;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700123 private boolean mAnimationStartDelayed;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800124 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800125 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100126 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700127 private boolean mAnimatingForIme;
128 private boolean mAdjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700129 private int mImeHeight;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700130 private WindowState mDelayedImeWin;
Chong Zhangf347ab52016-04-18 21:02:01 -0700131 private boolean mAdjustedForDivider;
132 private float mDividerAnimationStart;
133 private float mDividerAnimationTarget;
Wale Ogunwale10124582016-09-15 20:25:50 -0700134 float mLastAnimationProgress;
135 float mLastDividerProgress;
Jorim Jaggi85639432016-05-06 17:27:55 -0700136 private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700137 private boolean mImeHideRequested;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800138
139 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
140 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700141 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800142 final Context context = service.mContext;
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100143 mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
144 "DockedStackDim");
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800145 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
146 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700147 loadDimens();
148 }
149
Jorim Jaggi85639432016-05-06 17:27:55 -0700150 int getSmallestWidthDpForBounds(Rect bounds) {
151 final DisplayInfo di = mDisplayContent.getDisplayInfo();
152
153 // If the bounds are fullscreen, return the value of the fullscreen configuration
154 if (bounds == null || (bounds.left == 0 && bounds.top == 0
155 && bounds.right == di.logicalWidth && bounds.bottom == di.logicalHeight)) {
Andrii Kulian8072d112016-09-16 11:11:01 -0700156 return mService.mGlobalConfiguration.smallestScreenWidthDp;
Jorim Jaggi85639432016-05-06 17:27:55 -0700157 }
158 final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
159 final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
160 int minWidth = Integer.MAX_VALUE;
161
162 // Go through all screen orientations and find the orientation in which the task has the
163 // smallest width.
164 for (int rotation = 0; rotation < 4; rotation++) {
165 mTmpRect.set(bounds);
166 mDisplayContent.rotateBounds(di.rotation, rotation, mTmpRect);
167 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
168 mTmpRect2.set(0, 0,
169 rotated ? baseDisplayHeight : baseDisplayWidth,
170 rotated ? baseDisplayWidth : baseDisplayHeight);
171 final int orientation = mTmpRect2.width() <= mTmpRect2.height()
172 ? ORIENTATION_PORTRAIT
173 : ORIENTATION_LANDSCAPE;
174 final int dockSide = TaskStack.getDockSideUnchecked(mTmpRect, mTmpRect2, orientation);
175 final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
176 getContentWidth());
177
178 // Since we only care about feasible states, snap to the closest snap target, like it
179 // would happen when actually rotating the screen.
180 final int snappedPosition = mSnapAlgorithmForRotation[rotation]
181 .calculateNonDismissingSnapTarget(position).position;
182 DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, mTmpRect,
183 mTmpRect2.width(), mTmpRect2.height(), getContentWidth());
184 mService.mPolicy.getStableInsetsLw(rotation, mTmpRect2.width(), mTmpRect2.height(),
185 mTmpRect3);
186 mService.subtractInsets(mTmpRect2, mTmpRect3, mTmpRect);
187 minWidth = Math.min(mTmpRect.width(), minWidth);
188 }
189 return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
190 }
191
192 private void initSnapAlgorithmForRotations() {
Andrii Kulian8072d112016-09-16 11:11:01 -0700193 final Configuration baseConfig = mService.mGlobalConfiguration;
Jorim Jaggi85639432016-05-06 17:27:55 -0700194
195 // Initialize the snap algorithms for all 4 screen orientations.
196 final Configuration config = new Configuration();
197 for (int rotation = 0; rotation < 4; rotation++) {
198 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
199 final int dw = rotated
200 ? mDisplayContent.mBaseDisplayHeight
201 : mDisplayContent.mBaseDisplayWidth;
202 final int dh = rotated
203 ? mDisplayContent.mBaseDisplayWidth
204 : mDisplayContent.mBaseDisplayHeight;
205 mService.mPolicy.getStableInsetsLw(rotation, dw, dh, mTmpRect);
Andrii Kulianb10330d2016-09-16 13:51:46 -0700206 config.unset();
Jorim Jaggi85639432016-05-06 17:27:55 -0700207 config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
208 config.screenWidthDp = (int)
209 (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode) /
210 mDisplayContent.getDisplayMetrics().density);
211 config.screenHeightDp = (int)
212 (mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, baseConfig.uiMode) /
213 mDisplayContent.getDisplayMetrics().density);
214 final Context rotationContext = mService.mContext.createConfigurationContext(config);
215 mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
216 rotationContext.getResources(), dw, dh, getContentWidth(),
217 config.orientation == ORIENTATION_PORTRAIT, mTmpRect);
218 }
219 }
220
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700221 private void loadDimens() {
222 final Context context = mService.mContext;
223 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
224 com.android.internal.R.dimen.docked_stack_divider_thickness);
225 mDividerInsets = context.getResources().getDimensionPixelSize(
226 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700227 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
228 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Jorim Jaggi85639432016-05-06 17:27:55 -0700229 initSnapAlgorithmForRotations();
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700230 }
231
232 void onConfigurationChanged() {
233 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700234 }
235
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100236 boolean isResizing() {
237 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700238 }
239
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100240 int getContentWidth() {
241 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700242 }
243
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800244 int getContentInsets() {
245 return mDividerInsets;
246 }
247
Chong Zhang198afac2016-04-15 12:03:11 -0700248 int getContentWidthInactive() {
249 return mDividerWindowWidthInactive;
250 }
251
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100252 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800253 if (mResizing != resizing) {
254 mResizing = resizing;
255 resetDragResizingChangeReported();
256 }
257 }
258
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100259 void setTouchRegion(Rect touchRegion) {
260 mTouchRegion.set(touchRegion);
261 }
262
263 void getTouchRegion(Rect outRegion) {
264 outRegion.set(mTouchRegion);
265 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
266 }
267
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800268 private void resetDragResizingChangeReported() {
269 final WindowList windowList = mDisplayContent.getWindowList();
270 for (int i = windowList.size() - 1; i >= 0; i--) {
271 windowList.get(i).resetDragResizingChangeReported();
272 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100273 }
274
275 void setWindow(WindowState window) {
276 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800277 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100278 }
279
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800280 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800281 if (mWindow == null) {
282 return;
283 }
Jorim Jaggie48f4282015-11-06 17:32:44 +0100284 TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi7998e482016-02-12 18:47:06 -0800285
286 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
287 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800288 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800289 return;
290 }
291 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100292 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100293 if (!visible) {
294 setResizeDimLayer(false, INVALID_STACK_ID, 0f);
295 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100296 }
297
298 boolean wasVisible() {
299 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100300 }
301
Chong Zhangf347ab52016-04-18 21:02:01 -0700302 void setAdjustedForIme(
303 boolean adjustedForIme, boolean adjustedForDivider,
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700304 boolean animate, WindowState imeWin, int imeHeight) {
305 if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
306 || mAdjustedForDivider != adjustedForDivider) {
Jorim Jaggi3070e772016-05-17 16:41:32 -0700307 if (animate && !mAnimatingForMinimizedDockedStack) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700308 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700309 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700310 // Animation might be delayed, so only notify if we don't run an animation.
Chong Zhangf347ab52016-04-18 21:02:01 -0700311 notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700312 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700313 mAdjustedForIme = adjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700314 mImeHeight = imeHeight;
Chong Zhangf347ab52016-04-18 21:02:01 -0700315 mAdjustedForDivider = adjustedForDivider;
Chong Zhangbaba7832016-03-24 10:21:26 -0700316 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700317 }
318
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700319 int getImeHeightAdjustedFor() {
320 return mImeHeight;
321 }
322
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700323 void positionDockedStackedDivider(Rect frame) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700324 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700325 if (stack == null) {
326 // Unfortunately we might end up with still having a divider, even though the underlying
327 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800328 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
329 // keep putting it in the same place it was before the stack was removed to have
330 // continuity and prevent it from jumping to the center. It will get hidden soon.
331 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700332 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800333 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800334 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700335 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100336 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700337 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700338 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100339 frame.set(mTmpRect.right - mDividerInsets, frame.top,
340 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700341 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700342 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100343 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
344 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700345 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700346 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100347 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
348 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700349 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700350 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100351 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
352 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700353 break;
354 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800355 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700356 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800357
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100358 void notifyDockedDividerVisibilityChanged(boolean visible) {
359 final int size = mDockedStackListeners.beginBroadcast();
360 for (int i = 0; i < size; ++i) {
361 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
362 try {
363 listener.onDividerVisibilityChanged(visible);
364 } catch (RemoteException e) {
365 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
366 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800367 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100368 mDockedStackListeners.finishBroadcast();
369 }
370
371 void notifyDockedStackExistsChanged(boolean exists) {
372 final int size = mDockedStackListeners.beginBroadcast();
373 for (int i = 0; i < size; ++i) {
374 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
375 try {
376 listener.onDockedStackExistsChanged(exists);
377 } catch (RemoteException e) {
378 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
379 }
380 }
381 mDockedStackListeners.finishBroadcast();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700382 if (exists) {
383 InputMethodManagerInternal inputMethodManagerInternal =
384 LocalServices.getService(InputMethodManagerInternal.class);
385 if (inputMethodManagerInternal != null) {
386
387 // Hide the current IME to avoid problems with animations from IME adjustment when
388 // attaching the docked stack.
389 inputMethodManagerInternal.hideCurrentInputMethod();
390 mImeHideRequested = true;
391 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700392 } else if (setMinimizedDockedStack(false)) {
393 mService.mWindowPlacerLocked.performSurfacePlacement();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700394 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100395 }
396
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700397 /**
398 * Resets the state that IME hide has been requested. See {@link #isImeHideRequested}.
399 */
400 void resetImeHideRequested() {
401 mImeHideRequested = false;
402 }
403
404 /**
405 * The docked stack divider controller makes sure the IME gets hidden when attaching the docked
406 * stack, to avoid animation problems. This flag indicates whether the request to hide the IME
407 * has been sent in an asynchronous manner, and the IME should be treated as hidden already.
408 *
409 * @return whether IME hide request has been sent
410 */
411 boolean isImeHideRequested() {
412 return mImeHideRequested;
413 }
414
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800415 void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
Tony Mak853304c2016-04-18 15:17:41 +0100416 mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
417 mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
418 minimizedDock ? 1 : 0, 0).sendToTarget();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800419 final int size = mDockedStackListeners.beginBroadcast();
420 for (int i = 0; i < size; ++i) {
421 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
422 try {
423 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
424 } catch (RemoteException e) {
425 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
426 }
427 }
428 mDockedStackListeners.finishBroadcast();
429 }
430
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700431 void notifyDockSideChanged(int newDockSide) {
432 final int size = mDockedStackListeners.beginBroadcast();
433 for (int i = 0; i < size; ++i) {
434 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
435 try {
436 listener.onDockSideChanged(newDockSide);
437 } catch (RemoteException e) {
438 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
439 }
440 }
441 mDockedStackListeners.finishBroadcast();
442 }
443
Jorim Jaggi698e7632016-04-13 21:02:22 -0700444 void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
445 final int size = mDockedStackListeners.beginBroadcast();
446 for (int i = 0; i < size; ++i) {
447 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
448 try {
449 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
450 } catch (RemoteException e) {
451 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
452 }
453 }
454 mDockedStackListeners.finishBroadcast();
455 }
456
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100457 void registerDockedStackListener(IDockedStackListener listener) {
458 mDockedStackListeners.register(listener);
459 notifyDockedDividerVisibilityChanged(wasVisible());
460 notifyDockedStackExistsChanged(
461 mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700462 notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
Jorim Jaggi698e7632016-04-13 21:02:22 -0700463 notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
464
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800465 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100466
467 void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
Robert Carr68e5c9e2016-09-14 10:50:09 -0700468 mService.openSurfaceTransaction();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100469 final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
470 final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
471 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100472 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100473 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100474 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100475 mDimLayer.setBounds(mTmpRect);
Chong Zhang1402c2e2016-04-21 15:17:47 -0700476 mDimLayer.show(mService.mLayersController.getResizeDimLayer(),
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100477 alpha, 0 /* duration */);
478 } else {
479 visibleAndValid = false;
480 }
481 }
482 if (!visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100483 mDimLayer.hide();
484 }
Robert Carr68e5c9e2016-09-14 10:50:09 -0700485 mService.closeSurfaceTransaction();
Jorim Jaggi50981592015-12-29 17:54:12 +0100486 }
487
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800488 /**
489 * Notifies the docked stack divider controller of a visibility change that happens without
490 * an animation.
491 */
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700492 void notifyAppVisibilityChanged() {
493 checkMinimizeChanged(false /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800494 }
495
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700496 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps) {
497 final boolean wasMinimized = mMinimizedDock;
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700498 checkMinimizeChanged(true /* animate */);
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700499
500 // We were minimized, and now we are still minimized, but somebody is trying to launch an
501 // app in docked stack, better show recent apps so we actually get unminimized! This catches
502 // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
503 // we couldn't retrace the launch of the app in the docked stack to the launch from
504 // homescreen.
505 if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)) {
506 mService.showRecentApps(true /* fromHome */);
507 }
508 }
509
510 /**
511 * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
512 */
513 private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
514 for (int i = apps.size() - 1; i >= 0; i--) {
515 final AppWindowToken token = apps.valueAt(i);
516 if (token.mTask != null && token.mTask.mStack.mStackId == DOCKED_STACK_ID) {
517 return true;
518 }
519 }
520 return false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800521 }
522
Jorim Jaggi1ae68bf2016-05-09 18:44:34 -0700523 boolean isMinimizedDock() {
524 return mMinimizedDock;
525 }
526
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700527 private void checkMinimizeChanged(boolean animate) {
Jorim Jaggi817a5242016-05-06 15:45:00 -0700528 if (mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
529 return;
530 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700531 final TaskStack homeStack = mDisplayContent.getHomeStack();
532 if (homeStack == null) {
533 return;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800534 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700535 final Task homeTask = homeStack.findHomeTask();
536 if (homeTask == null || !isWithinDisplay(homeTask)) {
537 return;
538 }
539 final TaskStack fullscreenStack
540 = mService.mStackIdToStack.get(FULLSCREEN_WORKSPACE_STACK_ID);
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700541 final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700542 final boolean homeBehind = (fullscreenStack != null && fullscreenStack.isVisible())
Wale Ogunwale15ead902016-09-02 14:30:11 -0700543 || (homeStack.hasMultipleTaskWithHomeTaskNotTop());
Jiaquan He9bc01a82016-07-08 10:29:38 -0700544 // If the home task is an on-top launcher, we don't want to minimize the docked stack.
545 // Instead we want everything underneath that was visible to remain visible.
546 // See android.R.attr#onTopLauncher.
Wale Ogunwale15ead902016-09-02 14:30:11 -0700547 final boolean isOnTopLauncher = homeStack.topTaskIsOnTopLauncher();
Jiaquan He9bc01a82016-07-08 10:29:38 -0700548 setMinimizedDockedStack(homeVisible && !homeBehind && !isOnTopLauncher, animate);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800549 }
550
551 private boolean isWithinDisplay(Task task) {
552 task.mStack.getBounds(mTmpRect);
553 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
554 return mTmpRect.intersect(mTmpRect2);
555 }
556
557 /**
558 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
559 * docked stack are heavily clipped so you can only see a minimal peek state.
560 *
561 * @param minimizedDock Whether the docked stack is currently minimized.
562 * @param animate Whether to animate the change.
563 */
564 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700565 final boolean wasMinimized = mMinimizedDock;
566 mMinimizedDock = minimizedDock;
Jorim Jaggi817a5242016-05-06 15:45:00 -0700567 if (minimizedDock == wasMinimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800568 return;
569 }
570
Chong Zhang22eff0a2016-07-01 14:48:11 -0700571 final boolean imeChanged = clearImeAdjustAnimation();
572 boolean minimizedChange = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800573 if (minimizedDock) {
574 if (animate) {
575 startAdjustAnimation(0f, 1f);
576 } else {
Chong Zhang22eff0a2016-07-01 14:48:11 -0700577 minimizedChange |= setMinimizedDockedStack(true);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800578 }
579 } else {
580 if (animate) {
581 startAdjustAnimation(1f, 0f);
582 } else {
Chong Zhang22eff0a2016-07-01 14:48:11 -0700583 minimizedChange |= setMinimizedDockedStack(false);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800584 }
585 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700586 if (imeChanged || minimizedChange) {
587 if (imeChanged && !minimizedChange) {
588 Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing,"
589 + " minimizedDock=" + minimizedDock
590 + " minimizedChange=" + minimizedChange);
591 }
592 mService.mWindowPlacerLocked.performSurfacePlacement();
593 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800594 }
595
Chong Zhang22eff0a2016-07-01 14:48:11 -0700596 private boolean clearImeAdjustAnimation() {
Wale Ogunwale10124582016-09-15 20:25:50 -0700597 final boolean changed = mDisplayContent.clearImeAdjustAnimation();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700598 mAnimatingForIme = false;
Chong Zhang22eff0a2016-07-01 14:48:11 -0700599 return changed;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700600 }
601
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800602 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700603 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800604 mAnimationStarted = false;
605 mAnimationStart = from;
606 mAnimationTarget = to;
607 }
608
Chong Zhangf347ab52016-04-18 21:02:01 -0700609 private void startImeAdjustAnimation(
610 boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700611
612 // If we're not in an animation, the starting point depends on whether we're adjusted
613 // or not. If we're already in an animation, we start from where the current animation
614 // left off, so that the motion doesn't look discontinuous.
615 if (!mAnimatingForIme) {
616 mAnimationStart = mAdjustedForIme ? 1 : 0;
617 mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
618 mLastAnimationProgress = mAnimationStart;
619 mLastDividerProgress = mDividerAnimationStart;
620 } else {
621 mAnimationStart = mLastAnimationProgress;
622 mDividerAnimationStart = mLastDividerProgress;
623 }
Jorim Jaggi3070e772016-05-17 16:41:32 -0700624 mAnimatingForIme = true;
625 mAnimationStarted = false;
Chong Zhangf347ab52016-04-18 21:02:01 -0700626 mAnimationTarget = adjustedForIme ? 1 : 0;
627 mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700628
Wale Ogunwale10124582016-09-15 20:25:50 -0700629 mDisplayContent.beginImeAdjustAnimation();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700630
631 // We put all tasks into drag resizing mode - wait until all of them have completed the
632 // drag resizing switch.
633 if (!mService.mWaitingForDrawn.isEmpty()) {
634 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
635 mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
636 IME_ADJUST_DRAWN_TIMEOUT);
637 mAnimationStartDelayed = true;
638 if (imeWin != null) {
639
640 // There might be an old window delaying the animation start - clear it.
641 if (mDelayedImeWin != null) {
642 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
643 }
644 mDelayedImeWin = imeWin;
645 imeWin.mWinAnimator.startDelayingAnimationStart();
646 }
647 mService.mWaitingForDrawnCallback = () -> {
648 mAnimationStartDelayed = false;
649 if (mDelayedImeWin != null) {
650 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
651 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700652 // If the adjust status changed since this was posted, only notify
653 // the new states and don't animate.
654 long duration = 0;
655 if (mAdjustedForIme == adjustedForIme
656 && mAdjustedForDivider == adjustedForDivider) {
657 duration = IME_ADJUST_ANIM_DURATION;
658 } else {
659 Slog.w(TAG, "IME adjust changed while waiting for drawn:"
660 + " adjustedForIme=" + adjustedForIme
661 + " adjustedForDivider=" + adjustedForDivider
662 + " mAdjustedForIme=" + mAdjustedForIme
663 + " mAdjustedForDivider=" + mAdjustedForDivider);
664 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700665 notifyAdjustedForImeChanged(
Chong Zhang22eff0a2016-07-01 14:48:11 -0700666 mAdjustedForIme || mAdjustedForDivider, duration);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700667 };
668 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700669 notifyAdjustedForImeChanged(
670 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700671 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700672 }
673
Chong Zhang22eff0a2016-07-01 14:48:11 -0700674 private boolean setMinimizedDockedStack(boolean minimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800675 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700676 notifyDockedStackMinimizedChanged(minimized, 0);
Chong Zhang22eff0a2016-07-01 14:48:11 -0700677 return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800678 }
679
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800680 private boolean isAnimationMaximizing() {
681 return mAnimationTarget == 0f;
682 }
683
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800684 public boolean animate(long now) {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700685 if (mWindow == null) {
686 return false;
687 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700688 if (mAnimatingForMinimizedDockedStack) {
689 return animateForMinimizedDockedStack(now);
690 } else if (mAnimatingForIme) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700691 return animateForIme(now);
Chong Zhangbaba7832016-03-24 10:21:26 -0700692 } else {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700693 if (mDimLayer != null && mDimLayer.isDimming()) {
Chong Zhang1402c2e2016-04-21 15:17:47 -0700694 mDimLayer.setLayer(mService.mLayersController.getResizeDimLayer());
695 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800696 return false;
697 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700698 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800699
Jorim Jaggieb88d832016-04-13 20:17:43 -0700700 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700701 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700702 mAnimationStarted = true;
703 mAnimationStartTime = now;
704 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700705 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700706 }
707 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
708 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
709 .getInterpolation(t);
Wale Ogunwale10124582016-09-15 20:25:50 -0700710 final boolean updated =
711 mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700712 if (updated) {
713 mService.mWindowPlacerLocked.performSurfacePlacement();
714 }
715 if (t >= 1.0f) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700716 mLastAnimationProgress = mAnimationTarget;
717 mLastDividerProgress = mDividerAnimationTarget;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700718 mAnimatingForIme = false;
719 return false;
720 } else {
721 return true;
722 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700723 }
724
725 private boolean animateForMinimizedDockedStack(long now) {
Jorim Jaggiaf558e12016-04-27 22:56:56 -0700726 final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800727 if (!mAnimationStarted) {
728 mAnimationStarted = true;
729 mAnimationStartTime = now;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800730 final long transitionDuration = isAnimationMaximizing()
731 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
732 : DEFAULT_APP_TRANSITION_DURATION;
733 mAnimationDuration = (long)
734 (transitionDuration * mService.getTransitionAnimationScaleLocked());
Jorim Jaggif97ed922016-02-18 18:57:07 -0800735 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800736 notifyDockedStackMinimizedChanged(mMinimizedDock,
Jorim Jaggif97ed922016-02-18 18:57:07 -0800737 (long) (mAnimationDuration * mMaximizeMeetFraction));
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800738 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800739 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
740 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
741 .getInterpolation(t);
Chong Zhang741c0ba2016-05-27 12:52:11 -0700742 if (stack != null) {
743 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
744 mService.mWindowPlacerLocked.performSurfacePlacement();
745 }
746 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800747 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700748 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800749 return false;
750 } else {
751 return true;
752 }
753 }
754
Wale Ogunwale10124582016-09-15 20:25:50 -0700755 float getInterpolatedAnimationValue(float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700756 return t * mAnimationTarget + (1 - t) * mAnimationStart;
757 }
758
Wale Ogunwale10124582016-09-15 20:25:50 -0700759 float getInterpolatedDividerValue(float t) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700760 return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
761 }
762
Jorim Jaggif97ed922016-02-18 18:57:07 -0800763 /**
764 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
765 */
766 private float getMinimizeAmount(TaskStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700767 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800768 if (isAnimationMaximizing()) {
769 return adjustMaximizeAmount(stack, t, naturalAmount);
770 } else {
771 return naturalAmount;
772 }
773 }
774
775 /**
776 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
777 * during the transition such that the edge of the clip reveal rect is met earlier in the
778 * transition so we don't create a visible "hole", but only if both the clip reveal and the
779 * docked stack divider start from about the same portion on the screen.
780 */
781 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
782 if (mMaximizeMeetFraction == 1f) {
783 return naturalAmount;
784 }
785 final int minimizeDistance = stack.getMinimizeDistance();
786 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
787 / (float) minimizeDistance;
788 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
789 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
790 return amountPrime * t2 + naturalAmount * (1 - t2);
791 }
792
793 /**
794 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
795 * edge. See {@link #adjustMaximizeAmount}.
796 */
797 private float getClipRevealMeetFraction(TaskStack stack) {
798 if (!isAnimationMaximizing() || stack == null ||
799 !mService.mAppTransition.hadClipRevealAnimation()) {
800 return 1f;
801 }
802 final int minimizeDistance = stack.getMinimizeDistance();
803 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
804 / (float) minimizeDistance;
805 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
806 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
807 return CLIP_REVEAL_MEET_EARLIEST
808 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
809 }
810
Jorim Jaggi50981592015-12-29 17:54:12 +0100811 @Override
Wale Ogunwale29bfbb82016-05-12 15:13:52 -0700812 public boolean dimFullscreen() {
Jorim Jaggi50981592015-12-29 17:54:12 +0100813 return false;
814 }
815
816 @Override
817 public DisplayInfo getDisplayInfo() {
818 return mDisplayContent.getDisplayInfo();
819 }
820
821 @Override
822 public void getDimBounds(Rect outBounds) {
823 // This dim layer user doesn't need this.
824 }
825
826 @Override
827 public String toShortString() {
828 return TAG;
829 }
Robert Carre63e01a2016-04-18 20:27:34 -0700830
831 WindowState getWindow() {
832 return mWindow;
833 }
Jorim Jaggi31f71702016-05-04 16:43:04 -0700834
835 void dump(String prefix, PrintWriter pw) {
836 pw.println(prefix + "DockedStackDividerController");
837 pw.println(prefix + " mLastVisibility=" + mLastVisibility);
838 pw.println(prefix + " mMinimizedDock=" + mMinimizedDock);
839 pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme);
840 pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider);
841 if (mDimLayer.isDimming()) {
842 pw.println(prefix + " Dim layer is dimming: ");
843 mDimLayer.printTo(prefix + " ", pw);
844 }
845 }
Robert Carre63e01a2016-04-18 20:27:34 -0700846}