blob: f93e2ffa73bee997f6c404c3421d0252ec7f8785 [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;
Filip Gruszczynski77049052015-11-09 14:01:21 -080041import android.util.Slog;
Jorim Jaggi50981592015-12-29 17:54:12 +010042import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010043import android.view.IDockedStackListener;
Jorim Jaggi50981592015-12-29 17:54:12 +010044import android.view.SurfaceControl;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080045import android.view.animation.AnimationUtils;
46import android.view.animation.Interpolator;
Jorim Jaggieb88d832016-04-13 20:17:43 -070047import android.view.animation.PathInterpolator;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070048import android.view.inputmethod.InputMethodManagerInternal;
Jorim Jaggi50981592015-12-29 17:54:12 +010049
Jorim Jaggi85639432016-05-06 17:27:55 -070050import com.android.internal.policy.DividerSnapAlgorithm;
51import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070052import com.android.server.LocalServices;
Jorim Jaggi50981592015-12-29 17:54:12 +010053import com.android.server.wm.DimLayer.DimLayerUser;
Jorim Jaggiff71d202016-04-14 13:12:36 -070054import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010055
Jorim Jaggi31f71702016-05-04 16:43:04 -070056import java.io.PrintWriter;
Chong Zhangbaba7832016-03-24 10:21:26 -070057import java.util.ArrayList;
58
Filip Gruszczynski466f3212015-09-21 17:57:57 -070059/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010060 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070061 */
Jorim Jaggi50981592015-12-29 17:54:12 +010062public class DockedStackDividerController implements DimLayerUser {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010063
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080064 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010065
Jorim Jaggif97ed922016-02-18 18:57:07 -080066 /**
67 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
68 * revealing surface at the earliest.
69 */
70 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
71
72 /**
73 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
74 * revealing surface at the latest.
75 */
76 private static final float CLIP_REVEAL_MEET_LAST = 1f;
77
78 /**
79 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
80 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
81 */
82 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
83
84 /**
85 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
86 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
87 */
88 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
89
Jorim Jaggieb88d832016-04-13 20:17:43 -070090 private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
Jorim Jaggiff71d202016-04-14 13:12:36 -070091 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggieb88d832016-04-13 20:17:43 -070092
Jorim Jaggi698e7632016-04-13 21:02:22 -070093 private static final long IME_ADJUST_ANIM_DURATION = 280;
Jorim Jaggieb88d832016-04-13 20:17:43 -070094
Jorim Jaggiff71d202016-04-14 13:12:36 -070095 private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
96
Chong Zhang198afac2016-04-15 12:03:11 -070097 private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
98
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080099 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700100 private final DisplayContent mDisplayContent;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700101 private int mDividerWindowWidth;
Chong Zhang198afac2016-04-15 12:03:11 -0700102 private int mDividerWindowWidthInactive;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700103 private int mDividerInsets;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100104 private boolean mResizing;
105 private WindowState mWindow;
106 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800107 private final Rect mTmpRect2 = new Rect();
Jorim Jaggi85639432016-05-06 17:27:55 -0700108 private final Rect mTmpRect3 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -0800109 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800110 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100111 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
112 = new RemoteCallbackList<>();
Jorim Jaggi50981592015-12-29 17:54:12 +0100113 private final DimLayer mDimLayer;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700114
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800115 private boolean mMinimizedDock;
Chong Zhangbaba7832016-03-24 10:21:26 -0700116 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800117 private boolean mAnimationStarted;
118 private long mAnimationStartTime;
119 private float mAnimationStart;
120 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800121 private long mAnimationDuration;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700122 private boolean mAnimationStartDelayed;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800123 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800124 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100125 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700126 private boolean mAnimatingForIme;
127 private boolean mAdjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700128 private int mImeHeight;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700129 private WindowState mDelayedImeWin;
Chong Zhangf347ab52016-04-18 21:02:01 -0700130 private boolean mAdjustedForDivider;
131 private float mDividerAnimationStart;
132 private float mDividerAnimationTarget;
133 private float mLastAnimationProgress;
134 private float mLastDividerProgress;
Jorim Jaggi85639432016-05-06 17:27:55 -0700135 private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700136 private boolean mImeHideRequested;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800137
138 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
139 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700140 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800141 final Context context = service.mContext;
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100142 mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
143 "DockedStackDim");
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800144 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
145 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700146 loadDimens();
147 }
148
Jorim Jaggi85639432016-05-06 17:27:55 -0700149 int getSmallestWidthDpForBounds(Rect bounds) {
150 final DisplayInfo di = mDisplayContent.getDisplayInfo();
151
152 // If the bounds are fullscreen, return the value of the fullscreen configuration
153 if (bounds == null || (bounds.left == 0 && bounds.top == 0
154 && bounds.right == di.logicalWidth && bounds.bottom == di.logicalHeight)) {
155 return mService.mCurConfiguration.smallestScreenWidthDp;
156 }
157 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);
185 mService.subtractInsets(mTmpRect2, mTmpRect3, mTmpRect);
186 minWidth = Math.min(mTmpRect.width(), minWidth);
187 }
188 return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
189 }
190
191 private void initSnapAlgorithmForRotations() {
192 final Configuration baseConfig = mService.mCurConfiguration;
193
194 // Initialize the snap algorithms for all 4 screen orientations.
195 final Configuration config = new Configuration();
196 for (int rotation = 0; rotation < 4; rotation++) {
197 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
198 final int dw = rotated
199 ? mDisplayContent.mBaseDisplayHeight
200 : mDisplayContent.mBaseDisplayWidth;
201 final int dh = rotated
202 ? mDisplayContent.mBaseDisplayWidth
203 : mDisplayContent.mBaseDisplayHeight;
204 mService.mPolicy.getStableInsetsLw(rotation, dw, dh, mTmpRect);
205 config.setToDefaults();
206 config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
207 config.screenWidthDp = (int)
208 (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode) /
209 mDisplayContent.getDisplayMetrics().density);
210 config.screenHeightDp = (int)
211 (mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, baseConfig.uiMode) /
212 mDisplayContent.getDisplayMetrics().density);
213 final Context rotationContext = mService.mContext.createConfigurationContext(config);
214 mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
215 rotationContext.getResources(), dw, dh, getContentWidth(),
216 config.orientation == ORIENTATION_PORTRAIT, mTmpRect);
217 }
218 }
219
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700220 private void loadDimens() {
221 final Context context = mService.mContext;
222 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
223 com.android.internal.R.dimen.docked_stack_divider_thickness);
224 mDividerInsets = context.getResources().getDimensionPixelSize(
225 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700226 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
227 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Jorim Jaggi85639432016-05-06 17:27:55 -0700228 initSnapAlgorithmForRotations();
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700229 }
230
231 void onConfigurationChanged() {
232 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700233 }
234
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100235 boolean isResizing() {
236 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700237 }
238
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100239 int getContentWidth() {
240 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700241 }
242
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800243 int getContentInsets() {
244 return mDividerInsets;
245 }
246
Chong Zhang198afac2016-04-15 12:03:11 -0700247 int getContentWidthInactive() {
248 return mDividerWindowWidthInactive;
249 }
250
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100251 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800252 if (mResizing != resizing) {
253 mResizing = resizing;
254 resetDragResizingChangeReported();
255 }
256 }
257
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100258 void setTouchRegion(Rect touchRegion) {
259 mTouchRegion.set(touchRegion);
260 }
261
262 void getTouchRegion(Rect outRegion) {
263 outRegion.set(mTouchRegion);
264 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
265 }
266
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800267 private void resetDragResizingChangeReported() {
268 final WindowList windowList = mDisplayContent.getWindowList();
269 for (int i = windowList.size() - 1; i >= 0; i--) {
270 windowList.get(i).resetDragResizingChangeReported();
271 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100272 }
273
274 void setWindow(WindowState window) {
275 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800276 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100277 }
278
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800279 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800280 if (mWindow == null) {
281 return;
282 }
Jorim Jaggie48f4282015-11-06 17:32:44 +0100283 TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi7998e482016-02-12 18:47:06 -0800284
285 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
286 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800287 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800288 return;
289 }
290 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100291 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100292 if (!visible) {
293 setResizeDimLayer(false, INVALID_STACK_ID, 0f);
294 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100295 }
296
297 boolean wasVisible() {
298 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100299 }
300
Chong Zhangf347ab52016-04-18 21:02:01 -0700301 void setAdjustedForIme(
302 boolean adjustedForIme, boolean adjustedForDivider,
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700303 boolean animate, WindowState imeWin, int imeHeight) {
304 if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
305 || mAdjustedForDivider != adjustedForDivider) {
Jorim Jaggi3070e772016-05-17 16:41:32 -0700306 if (animate && !mAnimatingForMinimizedDockedStack) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700307 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700308 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700309 // Animation might be delayed, so only notify if we don't run an animation.
Chong Zhangf347ab52016-04-18 21:02:01 -0700310 notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700311 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700312 mAdjustedForIme = adjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700313 mImeHeight = imeHeight;
Chong Zhangf347ab52016-04-18 21:02:01 -0700314 mAdjustedForDivider = adjustedForDivider;
Chong Zhangbaba7832016-03-24 10:21:26 -0700315 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700316 }
317
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700318 int getImeHeightAdjustedFor() {
319 return mImeHeight;
320 }
321
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700322 void positionDockedStackedDivider(Rect frame) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700323 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700324 if (stack == null) {
325 // Unfortunately we might end up with still having a divider, even though the underlying
326 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800327 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
328 // keep putting it in the same place it was before the stack was removed to have
329 // continuity and prevent it from jumping to the center. It will get hidden soon.
330 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700331 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800332 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800333 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700334 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100335 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700336 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700337 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100338 frame.set(mTmpRect.right - mDividerInsets, frame.top,
339 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700340 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700341 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100342 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
343 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700344 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700345 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100346 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
347 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700348 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700349 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100350 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
351 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700352 break;
353 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800354 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700355 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800356
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100357 void notifyDockedDividerVisibilityChanged(boolean visible) {
358 final int size = mDockedStackListeners.beginBroadcast();
359 for (int i = 0; i < size; ++i) {
360 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
361 try {
362 listener.onDividerVisibilityChanged(visible);
363 } catch (RemoteException e) {
364 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
365 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800366 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100367 mDockedStackListeners.finishBroadcast();
368 }
369
370 void notifyDockedStackExistsChanged(boolean exists) {
371 final int size = mDockedStackListeners.beginBroadcast();
372 for (int i = 0; i < size; ++i) {
373 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
374 try {
375 listener.onDockedStackExistsChanged(exists);
376 } catch (RemoteException e) {
377 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
378 }
379 }
380 mDockedStackListeners.finishBroadcast();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700381 if (exists) {
382 InputMethodManagerInternal inputMethodManagerInternal =
383 LocalServices.getService(InputMethodManagerInternal.class);
384 if (inputMethodManagerInternal != null) {
385
386 // Hide the current IME to avoid problems with animations from IME adjustment when
387 // attaching the docked stack.
388 inputMethodManagerInternal.hideCurrentInputMethod();
389 mImeHideRequested = true;
390 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700391 } else if (setMinimizedDockedStack(false)) {
392 mService.mWindowPlacerLocked.performSurfacePlacement();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700393 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100394 }
395
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700396 /**
397 * Resets the state that IME hide has been requested. See {@link #isImeHideRequested}.
398 */
399 void resetImeHideRequested() {
400 mImeHideRequested = false;
401 }
402
403 /**
404 * The docked stack divider controller makes sure the IME gets hidden when attaching the docked
405 * stack, to avoid animation problems. This flag indicates whether the request to hide the IME
406 * has been sent in an asynchronous manner, and the IME should be treated as hidden already.
407 *
408 * @return whether IME hide request has been sent
409 */
410 boolean isImeHideRequested() {
411 return mImeHideRequested;
412 }
413
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800414 void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
Tony Mak853304c2016-04-18 15:17:41 +0100415 mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
416 mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
417 minimizedDock ? 1 : 0, 0).sendToTarget();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800418 final int size = mDockedStackListeners.beginBroadcast();
419 for (int i = 0; i < size; ++i) {
420 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
421 try {
422 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
423 } catch (RemoteException e) {
424 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
425 }
426 }
427 mDockedStackListeners.finishBroadcast();
428 }
429
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700430 void notifyDockSideChanged(int newDockSide) {
431 final int size = mDockedStackListeners.beginBroadcast();
432 for (int i = 0; i < size; ++i) {
433 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
434 try {
435 listener.onDockSideChanged(newDockSide);
436 } catch (RemoteException e) {
437 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
438 }
439 }
440 mDockedStackListeners.finishBroadcast();
441 }
442
Jorim Jaggi698e7632016-04-13 21:02:22 -0700443 void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
444 final int size = mDockedStackListeners.beginBroadcast();
445 for (int i = 0; i < size; ++i) {
446 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
447 try {
448 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
449 } catch (RemoteException e) {
450 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
451 }
452 }
453 mDockedStackListeners.finishBroadcast();
454 }
455
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100456 void registerDockedStackListener(IDockedStackListener listener) {
457 mDockedStackListeners.register(listener);
458 notifyDockedDividerVisibilityChanged(wasVisible());
459 notifyDockedStackExistsChanged(
460 mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700461 notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
Jorim Jaggi698e7632016-04-13 21:02:22 -0700462 notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
463
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800464 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100465
466 void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
467 SurfaceControl.openTransaction();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100468 final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
469 final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
470 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100471 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100472 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100473 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100474 mDimLayer.setBounds(mTmpRect);
Chong Zhang1402c2e2016-04-21 15:17:47 -0700475 mDimLayer.show(mService.mLayersController.getResizeDimLayer(),
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100476 alpha, 0 /* duration */);
477 } else {
478 visibleAndValid = false;
479 }
480 }
481 if (!visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100482 mDimLayer.hide();
483 }
484 SurfaceControl.closeTransaction();
485 }
486
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800487 /**
488 * Notifies the docked stack divider controller of a visibility change that happens without
489 * an animation.
490 */
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700491 void notifyAppVisibilityChanged() {
492 checkMinimizeChanged(false /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800493 }
494
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700495 void notifyAppTransitionStarting() {
496 checkMinimizeChanged(true /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800497 }
498
Jorim Jaggi1ae68bf2016-05-09 18:44:34 -0700499 boolean isMinimizedDock() {
500 return mMinimizedDock;
501 }
502
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700503 private void checkMinimizeChanged(boolean animate) {
Jorim Jaggi817a5242016-05-06 15:45:00 -0700504 if (mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
505 return;
506 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700507 final TaskStack homeStack = mDisplayContent.getHomeStack();
508 if (homeStack == null) {
509 return;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800510 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700511 final Task homeTask = homeStack.findHomeTask();
512 if (homeTask == null || !isWithinDisplay(homeTask)) {
513 return;
514 }
515 final TaskStack fullscreenStack
516 = mService.mStackIdToStack.get(FULLSCREEN_WORKSPACE_STACK_ID);
517 final ArrayList<Task> homeStackTasks = homeStack.getTasks();
518 final Task topHomeStackTask = homeStackTasks.get(homeStackTasks.size() - 1);
519 final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
520 final boolean homeBehind = (fullscreenStack != null && fullscreenStack.isVisibleLocked())
521 || (homeStackTasks.size() > 1 && topHomeStackTask != homeTask);
522 setMinimizedDockedStack(homeVisible && !homeBehind, animate);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800523 }
524
525 private boolean isWithinDisplay(Task task) {
526 task.mStack.getBounds(mTmpRect);
527 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
528 return mTmpRect.intersect(mTmpRect2);
529 }
530
531 /**
532 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
533 * docked stack are heavily clipped so you can only see a minimal peek state.
534 *
535 * @param minimizedDock Whether the docked stack is currently minimized.
536 * @param animate Whether to animate the change.
537 */
538 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700539 final boolean wasMinimized = mMinimizedDock;
540 mMinimizedDock = minimizedDock;
Jorim Jaggi817a5242016-05-06 15:45:00 -0700541 if (minimizedDock == wasMinimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800542 return;
543 }
544
Chong Zhang22eff0a2016-07-01 14:48:11 -0700545 final boolean imeChanged = clearImeAdjustAnimation();
546 boolean minimizedChange = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800547 if (minimizedDock) {
548 if (animate) {
549 startAdjustAnimation(0f, 1f);
550 } else {
Chong Zhang22eff0a2016-07-01 14:48:11 -0700551 minimizedChange |= setMinimizedDockedStack(true);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800552 }
553 } else {
554 if (animate) {
555 startAdjustAnimation(1f, 0f);
556 } else {
Chong Zhang22eff0a2016-07-01 14:48:11 -0700557 minimizedChange |= setMinimizedDockedStack(false);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800558 }
559 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700560 if (imeChanged || minimizedChange) {
561 if (imeChanged && !minimizedChange) {
562 Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing,"
563 + " minimizedDock=" + minimizedDock
564 + " minimizedChange=" + minimizedChange);
565 }
566 mService.mWindowPlacerLocked.performSurfacePlacement();
567 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800568 }
569
Chong Zhang22eff0a2016-07-01 14:48:11 -0700570 private boolean clearImeAdjustAnimation() {
571 boolean changed = false;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700572 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
573 for (int i = stacks.size() - 1; i >= 0; --i) {
574 final TaskStack stack = stacks.get(i);
575 if (stack != null && stack.isAdjustedForIme()) {
576 stack.resetAdjustedForIme(true /* adjustBoundsNow */);
Chong Zhang22eff0a2016-07-01 14:48:11 -0700577 changed = true;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700578 }
579 }
580 mAnimatingForIme = false;
Chong Zhang22eff0a2016-07-01 14:48:11 -0700581 return changed;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700582 }
583
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800584 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700585 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800586 mAnimationStarted = false;
587 mAnimationStart = from;
588 mAnimationTarget = to;
589 }
590
Chong Zhangf347ab52016-04-18 21:02:01 -0700591 private void startImeAdjustAnimation(
592 boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700593
594 // If we're not in an animation, the starting point depends on whether we're adjusted
595 // or not. If we're already in an animation, we start from where the current animation
596 // left off, so that the motion doesn't look discontinuous.
597 if (!mAnimatingForIme) {
598 mAnimationStart = mAdjustedForIme ? 1 : 0;
599 mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
600 mLastAnimationProgress = mAnimationStart;
601 mLastDividerProgress = mDividerAnimationStart;
602 } else {
603 mAnimationStart = mLastAnimationProgress;
604 mDividerAnimationStart = mLastDividerProgress;
605 }
Jorim Jaggi3070e772016-05-17 16:41:32 -0700606 mAnimatingForIme = true;
607 mAnimationStarted = false;
Chong Zhangf347ab52016-04-18 21:02:01 -0700608 mAnimationTarget = adjustedForIme ? 1 : 0;
609 mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700610
611 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
612 for (int i = stacks.size() - 1; i >= 0; --i) {
613 final TaskStack stack = stacks.get(i);
614 if (stack.isVisibleLocked() && stack.isAdjustedForIme()) {
615 stack.beginImeAdjustAnimation();
616 }
617 }
618
619 // We put all tasks into drag resizing mode - wait until all of them have completed the
620 // drag resizing switch.
621 if (!mService.mWaitingForDrawn.isEmpty()) {
622 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
623 mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
624 IME_ADJUST_DRAWN_TIMEOUT);
625 mAnimationStartDelayed = true;
626 if (imeWin != null) {
627
628 // There might be an old window delaying the animation start - clear it.
629 if (mDelayedImeWin != null) {
630 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
631 }
632 mDelayedImeWin = imeWin;
633 imeWin.mWinAnimator.startDelayingAnimationStart();
634 }
635 mService.mWaitingForDrawnCallback = () -> {
636 mAnimationStartDelayed = false;
637 if (mDelayedImeWin != null) {
638 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
639 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700640 // If the adjust status changed since this was posted, only notify
641 // the new states and don't animate.
642 long duration = 0;
643 if (mAdjustedForIme == adjustedForIme
644 && mAdjustedForDivider == adjustedForDivider) {
645 duration = IME_ADJUST_ANIM_DURATION;
646 } else {
647 Slog.w(TAG, "IME adjust changed while waiting for drawn:"
648 + " adjustedForIme=" + adjustedForIme
649 + " adjustedForDivider=" + adjustedForDivider
650 + " mAdjustedForIme=" + mAdjustedForIme
651 + " mAdjustedForDivider=" + mAdjustedForDivider);
652 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700653 notifyAdjustedForImeChanged(
Chong Zhang22eff0a2016-07-01 14:48:11 -0700654 mAdjustedForIme || mAdjustedForDivider, duration);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700655 };
656 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700657 notifyAdjustedForImeChanged(
658 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700659 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700660 }
661
Chong Zhang22eff0a2016-07-01 14:48:11 -0700662 private boolean setMinimizedDockedStack(boolean minimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800663 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700664 notifyDockedStackMinimizedChanged(minimized, 0);
Chong Zhang22eff0a2016-07-01 14:48:11 -0700665 return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800666 }
667
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800668 private boolean isAnimationMaximizing() {
669 return mAnimationTarget == 0f;
670 }
671
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800672 public boolean animate(long now) {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700673 if (mWindow == null) {
674 return false;
675 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700676 if (mAnimatingForMinimizedDockedStack) {
677 return animateForMinimizedDockedStack(now);
678 } else if (mAnimatingForIme) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700679 return animateForIme(now);
Chong Zhangbaba7832016-03-24 10:21:26 -0700680 } else {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700681 if (mDimLayer != null && mDimLayer.isDimming()) {
Chong Zhang1402c2e2016-04-21 15:17:47 -0700682 mDimLayer.setLayer(mService.mLayersController.getResizeDimLayer());
683 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800684 return false;
685 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700686 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800687
Jorim Jaggieb88d832016-04-13 20:17:43 -0700688 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700689 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700690 mAnimationStarted = true;
691 mAnimationStartTime = now;
692 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700693 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700694 }
695 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
696 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
697 .getInterpolation(t);
Chong Zhangbaba7832016-03-24 10:21:26 -0700698 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700699 boolean updated = false;
Chong Zhangbaba7832016-03-24 10:21:26 -0700700 for (int i = stacks.size() - 1; i >= 0; --i) {
701 final TaskStack stack = stacks.get(i);
702 if (stack != null && stack.isAdjustedForIme()) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700703 if (t >= 1f && mAnimationTarget == 0f && mDividerAnimationTarget == 0f) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700704 stack.resetAdjustedForIme(true /* adjustBoundsNow */);
705 updated = true;
706 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700707 mLastAnimationProgress = getInterpolatedAnimationValue(t);
708 mLastDividerProgress = getInterpolatedDividerValue(t);
709 updated |= stack.updateAdjustForIme(
710 mLastAnimationProgress,
711 mLastDividerProgress,
Jorim Jaggiff71d202016-04-14 13:12:36 -0700712 false /* force */);
713 }
714 if (t >= 1f) {
715 stack.endImeAdjustAnimation();
Chong Zhangbaba7832016-03-24 10:21:26 -0700716 }
717 }
718 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700719 if (updated) {
720 mService.mWindowPlacerLocked.performSurfacePlacement();
721 }
722 if (t >= 1.0f) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700723 mLastAnimationProgress = mAnimationTarget;
724 mLastDividerProgress = mDividerAnimationTarget;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700725 mAnimatingForIme = false;
726 return false;
727 } else {
728 return true;
729 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700730 }
731
732 private boolean animateForMinimizedDockedStack(long now) {
Jorim Jaggiaf558e12016-04-27 22:56:56 -0700733 final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800734 if (!mAnimationStarted) {
735 mAnimationStarted = true;
736 mAnimationStartTime = now;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800737 final long transitionDuration = isAnimationMaximizing()
738 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
739 : DEFAULT_APP_TRANSITION_DURATION;
740 mAnimationDuration = (long)
741 (transitionDuration * mService.getTransitionAnimationScaleLocked());
Jorim Jaggif97ed922016-02-18 18:57:07 -0800742 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800743 notifyDockedStackMinimizedChanged(mMinimizedDock,
Jorim Jaggif97ed922016-02-18 18:57:07 -0800744 (long) (mAnimationDuration * mMaximizeMeetFraction));
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800745 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800746 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
747 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
748 .getInterpolation(t);
Chong Zhang741c0ba2016-05-27 12:52:11 -0700749 if (stack != null) {
750 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
751 mService.mWindowPlacerLocked.performSurfacePlacement();
752 }
753 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800754 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700755 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800756 return false;
757 } else {
758 return true;
759 }
760 }
761
Jorim Jaggieb88d832016-04-13 20:17:43 -0700762 private float getInterpolatedAnimationValue(float t) {
763 return t * mAnimationTarget + (1 - t) * mAnimationStart;
764 }
765
Chong Zhangf347ab52016-04-18 21:02:01 -0700766 private float getInterpolatedDividerValue(float t) {
767 return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
768 }
769
Jorim Jaggif97ed922016-02-18 18:57:07 -0800770 /**
771 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
772 */
773 private float getMinimizeAmount(TaskStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700774 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800775 if (isAnimationMaximizing()) {
776 return adjustMaximizeAmount(stack, t, naturalAmount);
777 } else {
778 return naturalAmount;
779 }
780 }
781
782 /**
783 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
784 * during the transition such that the edge of the clip reveal rect is met earlier in the
785 * transition so we don't create a visible "hole", but only if both the clip reveal and the
786 * docked stack divider start from about the same portion on the screen.
787 */
788 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
789 if (mMaximizeMeetFraction == 1f) {
790 return naturalAmount;
791 }
792 final int minimizeDistance = stack.getMinimizeDistance();
793 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
794 / (float) minimizeDistance;
795 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
796 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
797 return amountPrime * t2 + naturalAmount * (1 - t2);
798 }
799
800 /**
801 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
802 * edge. See {@link #adjustMaximizeAmount}.
803 */
804 private float getClipRevealMeetFraction(TaskStack stack) {
805 if (!isAnimationMaximizing() || stack == null ||
806 !mService.mAppTransition.hadClipRevealAnimation()) {
807 return 1f;
808 }
809 final int minimizeDistance = stack.getMinimizeDistance();
810 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
811 / (float) minimizeDistance;
812 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
813 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
814 return CLIP_REVEAL_MEET_EARLIEST
815 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
816 }
817
Jorim Jaggi50981592015-12-29 17:54:12 +0100818 @Override
Wale Ogunwale29bfbb82016-05-12 15:13:52 -0700819 public boolean dimFullscreen() {
Jorim Jaggi50981592015-12-29 17:54:12 +0100820 return false;
821 }
822
823 @Override
824 public DisplayInfo getDisplayInfo() {
825 return mDisplayContent.getDisplayInfo();
826 }
827
828 @Override
829 public void getDimBounds(Rect outBounds) {
830 // This dim layer user doesn't need this.
831 }
832
833 @Override
834 public String toShortString() {
835 return TAG;
836 }
Robert Carre63e01a2016-04-18 20:27:34 -0700837
838 WindowState getWindow() {
839 return mWindow;
840 }
Jorim Jaggi31f71702016-05-04 16:43:04 -0700841
842 void dump(String prefix, PrintWriter pw) {
843 pw.println(prefix + "DockedStackDividerController");
844 pw.println(prefix + " mLastVisibility=" + mLastVisibility);
845 pw.println(prefix + " mMinimizedDock=" + mMinimizedDock);
846 pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme);
847 pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider);
848 if (mDimLayer.isDimming()) {
849 pw.println(prefix + " Dim layer is dimming: ");
850 mDimLayer.printTo(prefix + " ", pw);
851 }
852 }
Robert Carre63e01a2016-04-18 20:27:34 -0700853}