blob: 0638a0e94135254940b79a4396c504dc79fbe61e [file] [log] [blame]
Filip Gruszczynski466f3212015-09-21 17:57:57 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wm;
18
Jorim Jaggibc5425c2016-03-01 13:51:16 +010019import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
20import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
21import static android.view.WindowManager.DOCKED_BOTTOM;
22import static android.view.WindowManager.DOCKED_LEFT;
23import static android.view.WindowManager.DOCKED_RIGHT;
24import static android.view.WindowManager.DOCKED_TOP;
25import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
26import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
Jorim Jaggiff71d202016-04-14 13:12:36 -070027import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010028import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
29import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
30
Filip Gruszczynski466f3212015-09-21 17:57:57 -070031import android.content.Context;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070032import android.graphics.Rect;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010033import android.os.RemoteCallbackList;
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080034import android.os.RemoteException;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080035import android.util.ArraySet;
Filip Gruszczynski77049052015-11-09 14:01:21 -080036import android.util.Slog;
Jorim Jaggi50981592015-12-29 17:54:12 +010037import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010038import android.view.IDockedStackListener;
Jorim Jaggi50981592015-12-29 17:54:12 +010039import android.view.SurfaceControl;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080040import android.view.animation.AnimationUtils;
41import android.view.animation.Interpolator;
Jorim Jaggieb88d832016-04-13 20:17:43 -070042import android.view.animation.PathInterpolator;
Jorim Jaggi50981592015-12-29 17:54:12 +010043
44import com.android.server.wm.DimLayer.DimLayerUser;
Jorim Jaggiff71d202016-04-14 13:12:36 -070045import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010046
Chong Zhangbaba7832016-03-24 10:21:26 -070047import java.util.ArrayList;
48
Filip Gruszczynski466f3212015-09-21 17:57:57 -070049/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010050 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070051 */
Jorim Jaggi50981592015-12-29 17:54:12 +010052public class DockedStackDividerController implements DimLayerUser {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010053
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080054 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010055
Jorim Jaggif97ed922016-02-18 18:57:07 -080056 /**
57 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
58 * revealing surface at the earliest.
59 */
60 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
61
62 /**
63 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
64 * revealing surface at the latest.
65 */
66 private static final float CLIP_REVEAL_MEET_LAST = 1f;
67
68 /**
69 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
70 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
71 */
72 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
73
74 /**
75 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
76 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
77 */
78 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
79
Jorim Jaggieb88d832016-04-13 20:17:43 -070080 private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
Jorim Jaggiff71d202016-04-14 13:12:36 -070081 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggieb88d832016-04-13 20:17:43 -070082
Jorim Jaggi698e7632016-04-13 21:02:22 -070083 private static final long IME_ADJUST_ANIM_DURATION = 280;
Jorim Jaggieb88d832016-04-13 20:17:43 -070084
Jorim Jaggiff71d202016-04-14 13:12:36 -070085 private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
86
Chong Zhang198afac2016-04-15 12:03:11 -070087 private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
88
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080089 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070090 private final DisplayContent mDisplayContent;
Jorim Jaggi11c62e12016-04-05 20:41:21 -070091 private int mDividerWindowWidth;
Chong Zhang198afac2016-04-15 12:03:11 -070092 private int mDividerWindowWidthInactive;
Jorim Jaggi11c62e12016-04-05 20:41:21 -070093 private int mDividerInsets;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010094 private boolean mResizing;
95 private WindowState mWindow;
96 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080097 private final Rect mTmpRect2 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -080098 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080099 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100100 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
101 = new RemoteCallbackList<>();
Jorim Jaggi50981592015-12-29 17:54:12 +0100102 private final DimLayer mDimLayer;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700103
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800104 private boolean mMinimizedDock;
Chong Zhangbaba7832016-03-24 10:21:26 -0700105 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800106 private boolean mAnimationStarted;
107 private long mAnimationStartTime;
108 private float mAnimationStart;
109 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800110 private long mAnimationDuration;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700111 private boolean mAnimationStartDelayed;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800112 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800113 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100114 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700115 private boolean mAnimatingForIme;
116 private boolean mAdjustedForIme;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700117 private WindowState mDelayedImeWin;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800118
119 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
120 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700121 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800122 final Context context = service.mContext;
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100123 mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
124 "DockedStackDim");
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800125 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
126 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700127 loadDimens();
128 }
129
130 private void loadDimens() {
131 final Context context = mService.mContext;
132 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
133 com.android.internal.R.dimen.docked_stack_divider_thickness);
134 mDividerInsets = context.getResources().getDimensionPixelSize(
135 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700136 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
137 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700138 }
139
140 void onConfigurationChanged() {
141 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700142 }
143
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100144 boolean isResizing() {
145 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700146 }
147
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100148 int getContentWidth() {
149 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700150 }
151
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800152 int getContentInsets() {
153 return mDividerInsets;
154 }
155
Chong Zhang198afac2016-04-15 12:03:11 -0700156 int getContentWidthInactive() {
157 return mDividerWindowWidthInactive;
158 }
159
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100160 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800161 if (mResizing != resizing) {
162 mResizing = resizing;
163 resetDragResizingChangeReported();
164 }
165 }
166
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100167 void setTouchRegion(Rect touchRegion) {
168 mTouchRegion.set(touchRegion);
169 }
170
171 void getTouchRegion(Rect outRegion) {
172 outRegion.set(mTouchRegion);
173 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
174 }
175
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800176 private void resetDragResizingChangeReported() {
177 final WindowList windowList = mDisplayContent.getWindowList();
178 for (int i = windowList.size() - 1; i >= 0; i--) {
179 windowList.get(i).resetDragResizingChangeReported();
180 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100181 }
182
183 void setWindow(WindowState window) {
184 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800185 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100186 }
187
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800188 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800189 if (mWindow == null) {
190 return;
191 }
Jorim Jaggie48f4282015-11-06 17:32:44 +0100192 TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi7998e482016-02-12 18:47:06 -0800193
194 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
195 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800196 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800197 return;
198 }
199 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100200 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100201 if (!visible) {
202 setResizeDimLayer(false, INVALID_STACK_ID, 0f);
203 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100204 }
205
206 boolean wasVisible() {
207 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100208 }
209
Jorim Jaggiff71d202016-04-14 13:12:36 -0700210 void setAdjustedForIme(boolean adjusted, boolean animate, WindowState imeWin) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700211 if (mAdjustedForIme != adjusted) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700212 mAdjustedForIme = adjusted;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700213 if (animate) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700214 startImeAdjustAnimation(adjusted, imeWin);
215 } else {
216
217 // Animation might be delayed, so only notify if we don't run an animation.
218 notifyAdjustedForImeChanged(adjusted, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700219 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700220 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700221 }
222
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700223 void positionDockedStackedDivider(Rect frame) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700224 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700225 if (stack == null) {
226 // Unfortunately we might end up with still having a divider, even though the underlying
227 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800228 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
229 // keep putting it in the same place it was before the stack was removed to have
230 // continuity and prevent it from jumping to the center. It will get hidden soon.
231 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700232 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800233 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800234 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700235 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100236 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700237 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700238 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100239 frame.set(mTmpRect.right - mDividerInsets, frame.top,
240 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700241 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700242 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100243 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
244 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700245 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700246 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100247 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
248 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700249 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700250 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100251 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
252 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700253 break;
254 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800255 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700256 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800257
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100258 void notifyDockedDividerVisibilityChanged(boolean visible) {
259 final int size = mDockedStackListeners.beginBroadcast();
260 for (int i = 0; i < size; ++i) {
261 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
262 try {
263 listener.onDividerVisibilityChanged(visible);
264 } catch (RemoteException e) {
265 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
266 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800267 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100268 mDockedStackListeners.finishBroadcast();
269 }
270
271 void notifyDockedStackExistsChanged(boolean exists) {
272 final int size = mDockedStackListeners.beginBroadcast();
273 for (int i = 0; i < size; ++i) {
274 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
275 try {
276 listener.onDockedStackExistsChanged(exists);
277 } catch (RemoteException e) {
278 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
279 }
280 }
281 mDockedStackListeners.finishBroadcast();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700282 if (!exists) {
283 setMinimizedDockedStack(false);
284 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100285 }
286
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800287 void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
288 final int size = mDockedStackListeners.beginBroadcast();
289 for (int i = 0; i < size; ++i) {
290 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
291 try {
292 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
293 } catch (RemoteException e) {
294 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
295 }
296 }
297 mDockedStackListeners.finishBroadcast();
298 }
299
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700300 void notifyDockSideChanged(int newDockSide) {
301 final int size = mDockedStackListeners.beginBroadcast();
302 for (int i = 0; i < size; ++i) {
303 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
304 try {
305 listener.onDockSideChanged(newDockSide);
306 } catch (RemoteException e) {
307 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
308 }
309 }
310 mDockedStackListeners.finishBroadcast();
311 }
312
Jorim Jaggi698e7632016-04-13 21:02:22 -0700313 void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
314 final int size = mDockedStackListeners.beginBroadcast();
315 for (int i = 0; i < size; ++i) {
316 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
317 try {
318 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
319 } catch (RemoteException e) {
320 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
321 }
322 }
323 mDockedStackListeners.finishBroadcast();
324 }
325
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100326 void registerDockedStackListener(IDockedStackListener listener) {
327 mDockedStackListeners.register(listener);
328 notifyDockedDividerVisibilityChanged(wasVisible());
329 notifyDockedStackExistsChanged(
330 mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700331 notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
Jorim Jaggi698e7632016-04-13 21:02:22 -0700332 notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
333
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800334 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100335
336 void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
337 SurfaceControl.openTransaction();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100338 final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
339 final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
340 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100341 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100342 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100343 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100344 mDimLayer.setBounds(mTmpRect);
345 mDimLayer.show(mDisplayContent.mService.mLayersController.getResizeDimLayer(),
346 alpha, 0 /* duration */);
347 } else {
348 visibleAndValid = false;
349 }
350 }
351 if (!visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100352 mDimLayer.hide();
353 }
354 SurfaceControl.closeTransaction();
355 }
356
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800357 /**
358 * Notifies the docked stack divider controller of a visibility change that happens without
359 * an animation.
360 */
361 void notifyAppVisibilityChanged(AppWindowToken wtoken, boolean visible) {
362 final Task task = wtoken.mTask;
363 if (!task.isHomeTask() || !task.isVisibleForUser()) {
364 return;
365 }
366
367 // If the stack is completely offscreen, this might just be an intermediate state when
368 // docking a task/launching recents at the same time, but home doesn't actually get
369 // visible after the state settles in.
370 if (isWithinDisplay(task)
371 && mDisplayContent.getDockedStackVisibleForUserLocked() != null) {
372 setMinimizedDockedStack(visible, false /* animate */);
373 }
374 }
375
376 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps,
377 ArraySet<AppWindowToken> closingApps) {
378 if (containsHomeTaskWithinDisplay(openingApps)) {
379 setMinimizedDockedStack(true /* minimized */, true /* animate */);
380 } else if (containsHomeTaskWithinDisplay(closingApps)) {
381 setMinimizedDockedStack(false /* minimized */, true /* animate */);
382 }
383 }
384
385 private boolean containsHomeTaskWithinDisplay(ArraySet<AppWindowToken> apps) {
386 for (int i = apps.size() - 1; i >= 0; i--) {
387 final Task task = apps.valueAt(i).mTask;
388 if (task != null && task.isHomeTask()) {
389 return isWithinDisplay(task);
390 }
391 }
392 return false;
393 }
394
395 private boolean isWithinDisplay(Task task) {
396 task.mStack.getBounds(mTmpRect);
397 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
398 return mTmpRect.intersect(mTmpRect2);
399 }
400
401 /**
402 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
403 * docked stack are heavily clipped so you can only see a minimal peek state.
404 *
405 * @param minimizedDock Whether the docked stack is currently minimized.
406 * @param animate Whether to animate the change.
407 */
408 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700409 final boolean wasMinimized = mMinimizedDock;
410 mMinimizedDock = minimizedDock;
411 if (minimizedDock == wasMinimized
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800412 || mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
413 return;
414 }
415
Jorim Jaggieb88d832016-04-13 20:17:43 -0700416 clearImeAdjustAnimation();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800417 if (minimizedDock) {
418 if (animate) {
419 startAdjustAnimation(0f, 1f);
420 } else {
421 setMinimizedDockedStack(true);
422 }
423 } else {
424 if (animate) {
425 startAdjustAnimation(1f, 0f);
426 } else {
427 setMinimizedDockedStack(false);
428 }
429 }
430 }
431
Jorim Jaggieb88d832016-04-13 20:17:43 -0700432 private void clearImeAdjustAnimation() {
433 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
434 for (int i = stacks.size() - 1; i >= 0; --i) {
435 final TaskStack stack = stacks.get(i);
436 if (stack != null && stack.isAdjustedForIme()) {
437 stack.resetAdjustedForIme(true /* adjustBoundsNow */);
438 }
439 }
440 mAnimatingForIme = false;
441 }
442
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800443 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700444 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800445 mAnimationStarted = false;
446 mAnimationStart = from;
447 mAnimationTarget = to;
448 }
449
Jorim Jaggiff71d202016-04-14 13:12:36 -0700450 private void startImeAdjustAnimation(boolean adjusted, WindowState imeWin) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700451 mAnimatingForIme = true;
452 mAnimationStarted = false;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700453 mAnimationStart = adjusted ? 0 : 1;
454 mAnimationTarget = adjusted ? 1 : 0;
455
456 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
457 for (int i = stacks.size() - 1; i >= 0; --i) {
458 final TaskStack stack = stacks.get(i);
459 if (stack.isVisibleLocked() && stack.isAdjustedForIme()) {
460 stack.beginImeAdjustAnimation();
461 }
462 }
463
464 // We put all tasks into drag resizing mode - wait until all of them have completed the
465 // drag resizing switch.
466 if (!mService.mWaitingForDrawn.isEmpty()) {
467 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
468 mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
469 IME_ADJUST_DRAWN_TIMEOUT);
470 mAnimationStartDelayed = true;
471 if (imeWin != null) {
472
473 // There might be an old window delaying the animation start - clear it.
474 if (mDelayedImeWin != null) {
475 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
476 }
477 mDelayedImeWin = imeWin;
478 imeWin.mWinAnimator.startDelayingAnimationStart();
479 }
480 mService.mWaitingForDrawnCallback = () -> {
481 mAnimationStartDelayed = false;
482 if (mDelayedImeWin != null) {
483 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
484 }
485 notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
486 };
487 } else {
488 notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
489 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700490 }
491
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800492 private void setMinimizedDockedStack(boolean minimized) {
493 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700494 notifyDockedStackMinimizedChanged(minimized, 0);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800495 if (stack == null) {
496 return;
497 }
498 if (stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f)) {
499 mService.mWindowPlacerLocked.performSurfacePlacement();
500 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800501 }
502
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800503 private boolean isAnimationMaximizing() {
504 return mAnimationTarget == 0f;
505 }
506
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800507 public boolean animate(long now) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700508 if (mAnimatingForMinimizedDockedStack) {
509 return animateForMinimizedDockedStack(now);
510 } else if (mAnimatingForIme) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700511 return animateForIme(now);
Chong Zhangbaba7832016-03-24 10:21:26 -0700512 } else {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800513 return false;
514 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700515 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800516
Jorim Jaggieb88d832016-04-13 20:17:43 -0700517 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700518 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700519 mAnimationStarted = true;
520 mAnimationStartTime = now;
521 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700522 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700523 }
524 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
525 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
526 .getInterpolation(t);
Chong Zhangbaba7832016-03-24 10:21:26 -0700527 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700528 boolean updated = false;
Chong Zhangbaba7832016-03-24 10:21:26 -0700529 for (int i = stacks.size() - 1; i >= 0; --i) {
530 final TaskStack stack = stacks.get(i);
531 if (stack != null && stack.isAdjustedForIme()) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700532 if (t >= 1f && mAnimationTarget == 0f) {
533 stack.resetAdjustedForIme(true /* adjustBoundsNow */);
534 updated = true;
535 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700536 updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t),
537 false /* force */);
538 }
539 if (t >= 1f) {
540 stack.endImeAdjustAnimation();
Chong Zhangbaba7832016-03-24 10:21:26 -0700541 }
542 }
543 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700544 if (updated) {
545 mService.mWindowPlacerLocked.performSurfacePlacement();
546 }
547 if (t >= 1.0f) {
548 mAnimatingForIme = false;
549 return false;
550 } else {
551 return true;
552 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700553 }
554
555 private boolean animateForMinimizedDockedStack(long now) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800556 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800557 if (!mAnimationStarted) {
558 mAnimationStarted = true;
559 mAnimationStartTime = now;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800560 final long transitionDuration = isAnimationMaximizing()
561 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
562 : DEFAULT_APP_TRANSITION_DURATION;
563 mAnimationDuration = (long)
564 (transitionDuration * mService.getTransitionAnimationScaleLocked());
Jorim Jaggif97ed922016-02-18 18:57:07 -0800565 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800566 notifyDockedStackMinimizedChanged(mMinimizedDock,
Jorim Jaggif97ed922016-02-18 18:57:07 -0800567 (long) (mAnimationDuration * mMaximizeMeetFraction));
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800568 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800569 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
570 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
571 .getInterpolation(t);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800572 if (stack != null) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800573 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800574 mService.mWindowPlacerLocked.performSurfacePlacement();
575 }
576 }
577 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700578 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800579 return false;
580 } else {
581 return true;
582 }
583 }
584
Jorim Jaggieb88d832016-04-13 20:17:43 -0700585 private float getInterpolatedAnimationValue(float t) {
586 return t * mAnimationTarget + (1 - t) * mAnimationStart;
587 }
588
Jorim Jaggif97ed922016-02-18 18:57:07 -0800589 /**
590 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
591 */
592 private float getMinimizeAmount(TaskStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700593 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800594 if (isAnimationMaximizing()) {
595 return adjustMaximizeAmount(stack, t, naturalAmount);
596 } else {
597 return naturalAmount;
598 }
599 }
600
601 /**
602 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
603 * during the transition such that the edge of the clip reveal rect is met earlier in the
604 * transition so we don't create a visible "hole", but only if both the clip reveal and the
605 * docked stack divider start from about the same portion on the screen.
606 */
607 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
608 if (mMaximizeMeetFraction == 1f) {
609 return naturalAmount;
610 }
611 final int minimizeDistance = stack.getMinimizeDistance();
612 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
613 / (float) minimizeDistance;
614 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
615 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
616 return amountPrime * t2 + naturalAmount * (1 - t2);
617 }
618
619 /**
620 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
621 * edge. See {@link #adjustMaximizeAmount}.
622 */
623 private float getClipRevealMeetFraction(TaskStack stack) {
624 if (!isAnimationMaximizing() || stack == null ||
625 !mService.mAppTransition.hadClipRevealAnimation()) {
626 return 1f;
627 }
628 final int minimizeDistance = stack.getMinimizeDistance();
629 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
630 / (float) minimizeDistance;
631 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
632 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
633 return CLIP_REVEAL_MEET_EARLIEST
634 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
635 }
636
Jorim Jaggi50981592015-12-29 17:54:12 +0100637 @Override
638 public boolean isFullscreen() {
639 return false;
640 }
641
642 @Override
643 public DisplayInfo getDisplayInfo() {
644 return mDisplayContent.getDisplayInfo();
645 }
646
647 @Override
648 public void getDimBounds(Rect outBounds) {
649 // This dim layer user doesn't need this.
650 }
651
652 @Override
653 public String toShortString() {
654 return TAG;
655 }
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700656}