blob: ff537bef1aa9855a2da9c2e2c017d2fd18bf6593 [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 Jaggi11c62e12016-04-05 20:41:21 -070079 private int mDividerWindowWidth;
80 private 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 Jaggibc5425c2016-03-01 13:51:16 +0100108 mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
109 "DockedStackDim");
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800110 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
111 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700112 loadDimens();
113 }
114
115 private void loadDimens() {
116 final Context context = mService.mContext;
117 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
118 com.android.internal.R.dimen.docked_stack_divider_thickness);
119 mDividerInsets = context.getResources().getDimensionPixelSize(
120 com.android.internal.R.dimen.docked_stack_divider_insets);
121 }
122
123 void onConfigurationChanged() {
124 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700125 }
126
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100127 boolean isResizing() {
128 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700129 }
130
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100131 int getContentWidth() {
132 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700133 }
134
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800135 int getContentInsets() {
136 return mDividerInsets;
137 }
138
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100139 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800140 if (mResizing != resizing) {
141 mResizing = resizing;
142 resetDragResizingChangeReported();
143 }
144 }
145
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100146 void setTouchRegion(Rect touchRegion) {
147 mTouchRegion.set(touchRegion);
148 }
149
150 void getTouchRegion(Rect outRegion) {
151 outRegion.set(mTouchRegion);
152 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
153 }
154
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800155 private void resetDragResizingChangeReported() {
156 final WindowList windowList = mDisplayContent.getWindowList();
157 for (int i = windowList.size() - 1; i >= 0; i--) {
158 windowList.get(i).resetDragResizingChangeReported();
159 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100160 }
161
162 void setWindow(WindowState window) {
163 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800164 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100165 }
166
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800167 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800168 if (mWindow == null) {
169 return;
170 }
Jorim Jaggie48f4282015-11-06 17:32:44 +0100171 TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi7998e482016-02-12 18:47:06 -0800172
173 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
174 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800175 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800176 return;
177 }
178 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100179 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100180 if (!visible) {
181 setResizeDimLayer(false, INVALID_STACK_ID, 0f);
182 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100183 }
184
185 boolean wasVisible() {
186 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100187 }
188
Chong Zhangbaba7832016-03-24 10:21:26 -0700189 void setAdjustedForIme(boolean adjusted, boolean animate) {
190 if (mAdjustedForIme != adjusted) {
191 mAnimatingForIme = animate;
192 mAdjustedForIme = adjusted;
193 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700194 }
195
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700196 void positionDockedStackedDivider(Rect frame) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700197 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700198 if (stack == null) {
199 // Unfortunately we might end up with still having a divider, even though the underlying
200 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800201 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
202 // keep putting it in the same place it was before the stack was removed to have
203 // continuity and prevent it from jumping to the center. It will get hidden soon.
204 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700205 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800206 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800207 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700208 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100209 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700210 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700211 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100212 frame.set(mTmpRect.right - mDividerInsets, frame.top,
213 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700214 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700215 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100216 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
217 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700218 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700219 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100220 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
221 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700222 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700223 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100224 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
225 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700226 break;
227 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800228 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700229 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800230
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100231 void notifyDockedDividerVisibilityChanged(boolean visible) {
232 final int size = mDockedStackListeners.beginBroadcast();
233 for (int i = 0; i < size; ++i) {
234 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
235 try {
236 listener.onDividerVisibilityChanged(visible);
237 } catch (RemoteException e) {
238 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
239 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800240 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100241 mDockedStackListeners.finishBroadcast();
242 }
243
244 void notifyDockedStackExistsChanged(boolean exists) {
245 final int size = mDockedStackListeners.beginBroadcast();
246 for (int i = 0; i < size; ++i) {
247 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
248 try {
249 listener.onDockedStackExistsChanged(exists);
250 } catch (RemoteException e) {
251 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
252 }
253 }
254 mDockedStackListeners.finishBroadcast();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700255 if (!exists) {
256 setMinimizedDockedStack(false);
257 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100258 }
259
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800260 void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
261 final int size = mDockedStackListeners.beginBroadcast();
262 for (int i = 0; i < size; ++i) {
263 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
264 try {
265 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
266 } catch (RemoteException e) {
267 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
268 }
269 }
270 mDockedStackListeners.finishBroadcast();
271 }
272
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700273 void notifyDockSideChanged(int newDockSide) {
274 final int size = mDockedStackListeners.beginBroadcast();
275 for (int i = 0; i < size; ++i) {
276 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
277 try {
278 listener.onDockSideChanged(newDockSide);
279 } catch (RemoteException e) {
280 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
281 }
282 }
283 mDockedStackListeners.finishBroadcast();
284 }
285
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100286 void registerDockedStackListener(IDockedStackListener listener) {
287 mDockedStackListeners.register(listener);
288 notifyDockedDividerVisibilityChanged(wasVisible());
289 notifyDockedStackExistsChanged(
290 mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700291 notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800292 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100293
294 void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
295 SurfaceControl.openTransaction();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100296 final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
297 final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
298 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100299 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100300 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100301 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100302 mDimLayer.setBounds(mTmpRect);
303 mDimLayer.show(mDisplayContent.mService.mLayersController.getResizeDimLayer(),
304 alpha, 0 /* duration */);
305 } else {
306 visibleAndValid = false;
307 }
308 }
309 if (!visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100310 mDimLayer.hide();
311 }
312 SurfaceControl.closeTransaction();
313 }
314
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800315 /**
316 * Notifies the docked stack divider controller of a visibility change that happens without
317 * an animation.
318 */
319 void notifyAppVisibilityChanged(AppWindowToken wtoken, boolean visible) {
320 final Task task = wtoken.mTask;
321 if (!task.isHomeTask() || !task.isVisibleForUser()) {
322 return;
323 }
324
325 // If the stack is completely offscreen, this might just be an intermediate state when
326 // docking a task/launching recents at the same time, but home doesn't actually get
327 // visible after the state settles in.
328 if (isWithinDisplay(task)
329 && mDisplayContent.getDockedStackVisibleForUserLocked() != null) {
330 setMinimizedDockedStack(visible, false /* animate */);
331 }
332 }
333
334 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps,
335 ArraySet<AppWindowToken> closingApps) {
336 if (containsHomeTaskWithinDisplay(openingApps)) {
337 setMinimizedDockedStack(true /* minimized */, true /* animate */);
338 } else if (containsHomeTaskWithinDisplay(closingApps)) {
339 setMinimizedDockedStack(false /* minimized */, true /* animate */);
340 }
341 }
342
343 private boolean containsHomeTaskWithinDisplay(ArraySet<AppWindowToken> apps) {
344 for (int i = apps.size() - 1; i >= 0; i--) {
345 final Task task = apps.valueAt(i).mTask;
346 if (task != null && task.isHomeTask()) {
347 return isWithinDisplay(task);
348 }
349 }
350 return false;
351 }
352
353 private boolean isWithinDisplay(Task task) {
354 task.mStack.getBounds(mTmpRect);
355 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
356 return mTmpRect.intersect(mTmpRect2);
357 }
358
359 /**
360 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
361 * docked stack are heavily clipped so you can only see a minimal peek state.
362 *
363 * @param minimizedDock Whether the docked stack is currently minimized.
364 * @param animate Whether to animate the change.
365 */
366 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700367 final boolean wasMinimized = mMinimizedDock;
368 mMinimizedDock = minimizedDock;
369 if (minimizedDock == wasMinimized
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800370 || mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
371 return;
372 }
373
Chong Zhangbaba7832016-03-24 10:21:26 -0700374 mAnimatingForIme = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800375 if (minimizedDock) {
376 if (animate) {
377 startAdjustAnimation(0f, 1f);
378 } else {
379 setMinimizedDockedStack(true);
380 }
381 } else {
382 if (animate) {
383 startAdjustAnimation(1f, 0f);
384 } else {
385 setMinimizedDockedStack(false);
386 }
387 }
388 }
389
390 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700391 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800392 mAnimationStarted = false;
393 mAnimationStart = from;
394 mAnimationTarget = to;
395 }
396
397 private void setMinimizedDockedStack(boolean minimized) {
398 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700399 notifyDockedStackMinimizedChanged(minimized, 0);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800400 if (stack == null) {
401 return;
402 }
403 if (stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f)) {
404 mService.mWindowPlacerLocked.performSurfacePlacement();
405 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800406 }
407
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800408 private boolean isAnimationMaximizing() {
409 return mAnimationTarget == 0f;
410 }
411
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800412 public boolean animate(long now) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700413 if (mAnimatingForMinimizedDockedStack) {
414 return animateForMinimizedDockedStack(now);
415 } else if (mAnimatingForIme) {
416 return animateForIme();
417 } else {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800418 return false;
419 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700420 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800421
Chong Zhangbaba7832016-03-24 10:21:26 -0700422 private boolean animateForIme() {
423 boolean updated = false;
424 boolean animating = false;
425
426 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
427 for (int i = stacks.size() - 1; i >= 0; --i) {
428 final TaskStack stack = stacks.get(i);
429 if (stack != null && stack.isAdjustedForIme()) {
430 updated |= stack.updateAdjustForIme();
431 animating |= stack.isAnimatingForIme();
432 }
433 }
434
435 if (updated) {
436 mService.mWindowPlacerLocked.performSurfacePlacement();
437 }
438
439 if (!animating) {
440 mAnimatingForIme = false;
441 for (int i = stacks.size() - 1; i >= 0; --i) {
442 final TaskStack stack = stacks.get(i);
443 if (stack != null) {
444 stack.clearImeGoingAway();
445 }
446 }
447 }
448 return animating;
449 }
450
451 private boolean animateForMinimizedDockedStack(long now) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800452 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800453 if (!mAnimationStarted) {
454 mAnimationStarted = true;
455 mAnimationStartTime = now;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800456 final long transitionDuration = isAnimationMaximizing()
457 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
458 : DEFAULT_APP_TRANSITION_DURATION;
459 mAnimationDuration = (long)
460 (transitionDuration * mService.getTransitionAnimationScaleLocked());
Jorim Jaggif97ed922016-02-18 18:57:07 -0800461 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800462 notifyDockedStackMinimizedChanged(mMinimizedDock,
Jorim Jaggif97ed922016-02-18 18:57:07 -0800463 (long) (mAnimationDuration * mMaximizeMeetFraction));
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800464 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800465 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
466 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
467 .getInterpolation(t);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800468 if (stack != null) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800469 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800470 mService.mWindowPlacerLocked.performSurfacePlacement();
471 }
472 }
473 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700474 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800475 return false;
476 } else {
477 return true;
478 }
479 }
480
Jorim Jaggif97ed922016-02-18 18:57:07 -0800481 /**
482 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
483 */
484 private float getMinimizeAmount(TaskStack stack, float t) {
485 final float naturalAmount = t * mAnimationTarget + (1 - t) * mAnimationStart;
486 if (isAnimationMaximizing()) {
487 return adjustMaximizeAmount(stack, t, naturalAmount);
488 } else {
489 return naturalAmount;
490 }
491 }
492
493 /**
494 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
495 * during the transition such that the edge of the clip reveal rect is met earlier in the
496 * transition so we don't create a visible "hole", but only if both the clip reveal and the
497 * docked stack divider start from about the same portion on the screen.
498 */
499 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
500 if (mMaximizeMeetFraction == 1f) {
501 return naturalAmount;
502 }
503 final int minimizeDistance = stack.getMinimizeDistance();
504 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
505 / (float) minimizeDistance;
506 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
507 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
508 return amountPrime * t2 + naturalAmount * (1 - t2);
509 }
510
511 /**
512 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
513 * edge. See {@link #adjustMaximizeAmount}.
514 */
515 private float getClipRevealMeetFraction(TaskStack stack) {
516 if (!isAnimationMaximizing() || stack == null ||
517 !mService.mAppTransition.hadClipRevealAnimation()) {
518 return 1f;
519 }
520 final int minimizeDistance = stack.getMinimizeDistance();
521 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
522 / (float) minimizeDistance;
523 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
524 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
525 return CLIP_REVEAL_MEET_EARLIEST
526 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
527 }
528
Jorim Jaggi50981592015-12-29 17:54:12 +0100529 @Override
530 public boolean isFullscreen() {
531 return false;
532 }
533
534 @Override
535 public DisplayInfo getDisplayInfo() {
536 return mDisplayContent.getDisplayInfo();
537 }
538
539 @Override
540 public void getDimBounds(Rect outBounds) {
541 // This dim layer user doesn't need this.
542 }
543
544 @Override
545 public String toShortString() {
546 return TAG;
547 }
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700548}