blob: 68ea4df0c0b0d11dcea4d148f336c71597ac6ae9 [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;
27import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
28import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
29
Filip Gruszczynski466f3212015-09-21 17:57:57 -070030import android.content.Context;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070031import android.graphics.Rect;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010032import android.os.RemoteCallbackList;
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080033import android.os.RemoteException;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080034import android.util.ArraySet;
Filip Gruszczynski77049052015-11-09 14:01:21 -080035import android.util.Slog;
Jorim Jaggi50981592015-12-29 17:54:12 +010036import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010037import android.view.IDockedStackListener;
Jorim Jaggi50981592015-12-29 17:54:12 +010038import android.view.SurfaceControl;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080039import android.view.animation.AnimationUtils;
40import android.view.animation.Interpolator;
Jorim Jaggi50981592015-12-29 17:54:12 +010041
42import com.android.server.wm.DimLayer.DimLayerUser;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010043
Chong Zhangbaba7832016-03-24 10:21:26 -070044import java.util.ArrayList;
45
Filip Gruszczynski466f3212015-09-21 17:57:57 -070046/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010047 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070048 */
Jorim Jaggi50981592015-12-29 17:54:12 +010049public class DockedStackDividerController implements DimLayerUser {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010050
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080051 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010052
Jorim Jaggif97ed922016-02-18 18:57:07 -080053 /**
54 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
55 * revealing surface at the earliest.
56 */
57 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
58
59 /**
60 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
61 * revealing surface at the latest.
62 */
63 private static final float CLIP_REVEAL_MEET_LAST = 1f;
64
65 /**
66 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
67 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
68 */
69 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
70
71 /**
72 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
73 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
74 */
75 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
76
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080077 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070078 private final DisplayContent mDisplayContent;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +010079 private final int mDividerWindowWidth;
80 private final int mDividerInsets;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010081 private boolean mResizing;
82 private WindowState mWindow;
83 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080084 private final Rect mTmpRect2 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -080085 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080086 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010087 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
88 = new RemoteCallbackList<>();
Jorim Jaggi50981592015-12-29 17:54:12 +010089 private final DimLayer mDimLayer;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -070090
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080091 private boolean mMinimizedDock;
Chong Zhangbaba7832016-03-24 10:21:26 -070092 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080093 private boolean mAnimationStarted;
94 private long mAnimationStartTime;
95 private float mAnimationStart;
96 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -080097 private long mAnimationDuration;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080098 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -080099 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100100 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700101 private boolean mAnimatingForIme;
102 private boolean mAdjustedForIme;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800103
104 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
105 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700106 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800107 final Context context = service.mContext;
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100108 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700109 com.android.internal.R.dimen.docked_stack_divider_thickness);
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100110 mDividerInsets = context.getResources().getDimensionPixelSize(
111 com.android.internal.R.dimen.docked_stack_divider_insets);
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100112 mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
113 "DockedStackDim");
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800114 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
115 context, android.R.interpolator.fast_out_slow_in);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700116 }
117
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100118 boolean isResizing() {
119 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700120 }
121
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100122 int getContentWidth() {
123 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700124 }
125
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800126 int getContentInsets() {
127 return mDividerInsets;
128 }
129
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100130 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800131 if (mResizing != resizing) {
132 mResizing = resizing;
133 resetDragResizingChangeReported();
134 }
135 }
136
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100137 void setTouchRegion(Rect touchRegion) {
138 mTouchRegion.set(touchRegion);
139 }
140
141 void getTouchRegion(Rect outRegion) {
142 outRegion.set(mTouchRegion);
143 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
144 }
145
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800146 private void resetDragResizingChangeReported() {
147 final WindowList windowList = mDisplayContent.getWindowList();
148 for (int i = windowList.size() - 1; i >= 0; i--) {
149 windowList.get(i).resetDragResizingChangeReported();
150 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100151 }
152
153 void setWindow(WindowState window) {
154 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800155 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100156 }
157
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800158 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800159 if (mWindow == null) {
160 return;
161 }
Jorim Jaggie48f4282015-11-06 17:32:44 +0100162 TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi7998e482016-02-12 18:47:06 -0800163
164 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
165 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800166 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800167 return;
168 }
169 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100170 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100171 if (!visible) {
172 setResizeDimLayer(false, INVALID_STACK_ID, 0f);
173 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100174 }
175
176 boolean wasVisible() {
177 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100178 }
179
Chong Zhangbaba7832016-03-24 10:21:26 -0700180 void setAdjustedForIme(boolean adjusted, boolean animate) {
181 if (mAdjustedForIme != adjusted) {
182 mAnimatingForIme = animate;
183 mAdjustedForIme = adjusted;
184 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700185 }
186
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700187 void positionDockedStackedDivider(Rect frame) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700188 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700189 if (stack == null) {
190 // Unfortunately we might end up with still having a divider, even though the underlying
191 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800192 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
193 // keep putting it in the same place it was before the stack was removed to have
194 // continuity and prevent it from jumping to the center. It will get hidden soon.
195 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700196 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800197 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800198 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700199 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100200 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700201 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700202 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100203 frame.set(mTmpRect.right - mDividerInsets, frame.top,
204 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700205 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700206 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100207 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
208 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700209 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700210 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100211 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
212 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700213 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700214 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100215 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
216 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700217 break;
218 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800219 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700220 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800221
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100222 void notifyDockedDividerVisibilityChanged(boolean visible) {
223 final int size = mDockedStackListeners.beginBroadcast();
224 for (int i = 0; i < size; ++i) {
225 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
226 try {
227 listener.onDividerVisibilityChanged(visible);
228 } catch (RemoteException e) {
229 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
230 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800231 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100232 mDockedStackListeners.finishBroadcast();
233 }
234
235 void notifyDockedStackExistsChanged(boolean exists) {
236 final int size = mDockedStackListeners.beginBroadcast();
237 for (int i = 0; i < size; ++i) {
238 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
239 try {
240 listener.onDockedStackExistsChanged(exists);
241 } catch (RemoteException e) {
242 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
243 }
244 }
245 mDockedStackListeners.finishBroadcast();
246 }
247
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800248 void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
249 final int size = mDockedStackListeners.beginBroadcast();
250 for (int i = 0; i < size; ++i) {
251 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
252 try {
253 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
254 } catch (RemoteException e) {
255 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
256 }
257 }
258 mDockedStackListeners.finishBroadcast();
259 }
260
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100261 void registerDockedStackListener(IDockedStackListener listener) {
262 mDockedStackListeners.register(listener);
263 notifyDockedDividerVisibilityChanged(wasVisible());
264 notifyDockedStackExistsChanged(
265 mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800266 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100267
268 void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
269 SurfaceControl.openTransaction();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100270 final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
271 final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
272 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100273 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100274 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100275 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100276 mDimLayer.setBounds(mTmpRect);
277 mDimLayer.show(mDisplayContent.mService.mLayersController.getResizeDimLayer(),
278 alpha, 0 /* duration */);
279 } else {
280 visibleAndValid = false;
281 }
282 }
283 if (!visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100284 mDimLayer.hide();
285 }
286 SurfaceControl.closeTransaction();
287 }
288
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800289 /**
290 * Notifies the docked stack divider controller of a visibility change that happens without
291 * an animation.
292 */
293 void notifyAppVisibilityChanged(AppWindowToken wtoken, boolean visible) {
294 final Task task = wtoken.mTask;
295 if (!task.isHomeTask() || !task.isVisibleForUser()) {
296 return;
297 }
298
299 // If the stack is completely offscreen, this might just be an intermediate state when
300 // docking a task/launching recents at the same time, but home doesn't actually get
301 // visible after the state settles in.
302 if (isWithinDisplay(task)
303 && mDisplayContent.getDockedStackVisibleForUserLocked() != null) {
304 setMinimizedDockedStack(visible, false /* animate */);
305 }
306 }
307
308 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps,
309 ArraySet<AppWindowToken> closingApps) {
310 if (containsHomeTaskWithinDisplay(openingApps)) {
311 setMinimizedDockedStack(true /* minimized */, true /* animate */);
312 } else if (containsHomeTaskWithinDisplay(closingApps)) {
313 setMinimizedDockedStack(false /* minimized */, true /* animate */);
314 }
315 }
316
317 private boolean containsHomeTaskWithinDisplay(ArraySet<AppWindowToken> apps) {
318 for (int i = apps.size() - 1; i >= 0; i--) {
319 final Task task = apps.valueAt(i).mTask;
320 if (task != null && task.isHomeTask()) {
321 return isWithinDisplay(task);
322 }
323 }
324 return false;
325 }
326
327 private boolean isWithinDisplay(Task task) {
328 task.mStack.getBounds(mTmpRect);
329 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
330 return mTmpRect.intersect(mTmpRect2);
331 }
332
333 /**
334 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
335 * docked stack are heavily clipped so you can only see a minimal peek state.
336 *
337 * @param minimizedDock Whether the docked stack is currently minimized.
338 * @param animate Whether to animate the change.
339 */
340 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
341 if (minimizedDock == mMinimizedDock
342 || mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
343 return;
344 }
345
346 mMinimizedDock = minimizedDock;
Chong Zhangbaba7832016-03-24 10:21:26 -0700347 mAnimatingForIme = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800348 if (minimizedDock) {
349 if (animate) {
350 startAdjustAnimation(0f, 1f);
351 } else {
352 setMinimizedDockedStack(true);
353 }
354 } else {
355 if (animate) {
356 startAdjustAnimation(1f, 0f);
357 } else {
358 setMinimizedDockedStack(false);
359 }
360 }
361 }
362
363 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700364 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800365 mAnimationStarted = false;
366 mAnimationStart = from;
367 mAnimationTarget = to;
368 }
369
370 private void setMinimizedDockedStack(boolean minimized) {
371 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
372 if (stack == null) {
373 return;
374 }
375 if (stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f)) {
376 mService.mWindowPlacerLocked.performSurfacePlacement();
377 }
378 notifyDockedStackMinimizedChanged(minimized, 0);
379 }
380
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800381 private boolean isAnimationMaximizing() {
382 return mAnimationTarget == 0f;
383 }
384
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800385 public boolean animate(long now) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700386 if (mAnimatingForMinimizedDockedStack) {
387 return animateForMinimizedDockedStack(now);
388 } else if (mAnimatingForIme) {
389 return animateForIme();
390 } else {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800391 return false;
392 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700393 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800394
Chong Zhangbaba7832016-03-24 10:21:26 -0700395 private boolean animateForIme() {
396 boolean updated = false;
397 boolean animating = false;
398
399 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
400 for (int i = stacks.size() - 1; i >= 0; --i) {
401 final TaskStack stack = stacks.get(i);
402 if (stack != null && stack.isAdjustedForIme()) {
403 updated |= stack.updateAdjustForIme();
404 animating |= stack.isAnimatingForIme();
405 }
406 }
407
408 if (updated) {
409 mService.mWindowPlacerLocked.performSurfacePlacement();
410 }
411
412 if (!animating) {
413 mAnimatingForIme = false;
414 for (int i = stacks.size() - 1; i >= 0; --i) {
415 final TaskStack stack = stacks.get(i);
416 if (stack != null) {
417 stack.clearImeGoingAway();
418 }
419 }
420 }
421 return animating;
422 }
423
424 private boolean animateForMinimizedDockedStack(long now) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800425 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800426 if (!mAnimationStarted) {
427 mAnimationStarted = true;
428 mAnimationStartTime = now;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800429 final long transitionDuration = isAnimationMaximizing()
430 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
431 : DEFAULT_APP_TRANSITION_DURATION;
432 mAnimationDuration = (long)
433 (transitionDuration * mService.getTransitionAnimationScaleLocked());
Jorim Jaggif97ed922016-02-18 18:57:07 -0800434 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800435 notifyDockedStackMinimizedChanged(mMinimizedDock,
Jorim Jaggif97ed922016-02-18 18:57:07 -0800436 (long) (mAnimationDuration * mMaximizeMeetFraction));
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800437 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800438 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
439 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
440 .getInterpolation(t);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800441 if (stack != null) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800442 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800443 mService.mWindowPlacerLocked.performSurfacePlacement();
444 }
445 }
446 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700447 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800448 return false;
449 } else {
450 return true;
451 }
452 }
453
Jorim Jaggif97ed922016-02-18 18:57:07 -0800454 /**
455 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
456 */
457 private float getMinimizeAmount(TaskStack stack, float t) {
458 final float naturalAmount = t * mAnimationTarget + (1 - t) * mAnimationStart;
459 if (isAnimationMaximizing()) {
460 return adjustMaximizeAmount(stack, t, naturalAmount);
461 } else {
462 return naturalAmount;
463 }
464 }
465
466 /**
467 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
468 * during the transition such that the edge of the clip reveal rect is met earlier in the
469 * transition so we don't create a visible "hole", but only if both the clip reveal and the
470 * docked stack divider start from about the same portion on the screen.
471 */
472 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
473 if (mMaximizeMeetFraction == 1f) {
474 return naturalAmount;
475 }
476 final int minimizeDistance = stack.getMinimizeDistance();
477 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
478 / (float) minimizeDistance;
479 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
480 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
481 return amountPrime * t2 + naturalAmount * (1 - t2);
482 }
483
484 /**
485 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
486 * edge. See {@link #adjustMaximizeAmount}.
487 */
488 private float getClipRevealMeetFraction(TaskStack stack) {
489 if (!isAnimationMaximizing() || stack == null ||
490 !mService.mAppTransition.hadClipRevealAnimation()) {
491 return 1f;
492 }
493 final int minimizeDistance = stack.getMinimizeDistance();
494 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
495 / (float) minimizeDistance;
496 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
497 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
498 return CLIP_REVEAL_MEET_EARLIEST
499 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
500 }
501
Jorim Jaggi50981592015-12-29 17:54:12 +0100502 @Override
503 public boolean isFullscreen() {
504 return false;
505 }
506
507 @Override
508 public DisplayInfo getDisplayInfo() {
509 return mDisplayContent.getDisplayInfo();
510 }
511
512 @Override
513 public void getDimBounds(Rect outBounds) {
514 // This dim layer user doesn't need this.
515 }
516
517 @Override
518 public String toShortString() {
519 return TAG;
520 }
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700521}