blob: 6f7e64f28e7481eae3e20b6e48b376b720d385d5 [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();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700246 if (!exists) {
247 setMinimizedDockedStack(false);
248 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100249 }
250
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800251 void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
252 final int size = mDockedStackListeners.beginBroadcast();
253 for (int i = 0; i < size; ++i) {
254 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
255 try {
256 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
257 } catch (RemoteException e) {
258 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
259 }
260 }
261 mDockedStackListeners.finishBroadcast();
262 }
263
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100264 void registerDockedStackListener(IDockedStackListener listener) {
265 mDockedStackListeners.register(listener);
266 notifyDockedDividerVisibilityChanged(wasVisible());
267 notifyDockedStackExistsChanged(
268 mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700269 notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800270 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100271
272 void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
273 SurfaceControl.openTransaction();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100274 final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
275 final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
276 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100277 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100278 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100279 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100280 mDimLayer.setBounds(mTmpRect);
281 mDimLayer.show(mDisplayContent.mService.mLayersController.getResizeDimLayer(),
282 alpha, 0 /* duration */);
283 } else {
284 visibleAndValid = false;
285 }
286 }
287 if (!visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100288 mDimLayer.hide();
289 }
290 SurfaceControl.closeTransaction();
291 }
292
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800293 /**
294 * Notifies the docked stack divider controller of a visibility change that happens without
295 * an animation.
296 */
297 void notifyAppVisibilityChanged(AppWindowToken wtoken, boolean visible) {
298 final Task task = wtoken.mTask;
299 if (!task.isHomeTask() || !task.isVisibleForUser()) {
300 return;
301 }
302
303 // If the stack is completely offscreen, this might just be an intermediate state when
304 // docking a task/launching recents at the same time, but home doesn't actually get
305 // visible after the state settles in.
306 if (isWithinDisplay(task)
307 && mDisplayContent.getDockedStackVisibleForUserLocked() != null) {
308 setMinimizedDockedStack(visible, false /* animate */);
309 }
310 }
311
312 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps,
313 ArraySet<AppWindowToken> closingApps) {
314 if (containsHomeTaskWithinDisplay(openingApps)) {
315 setMinimizedDockedStack(true /* minimized */, true /* animate */);
316 } else if (containsHomeTaskWithinDisplay(closingApps)) {
317 setMinimizedDockedStack(false /* minimized */, true /* animate */);
318 }
319 }
320
321 private boolean containsHomeTaskWithinDisplay(ArraySet<AppWindowToken> apps) {
322 for (int i = apps.size() - 1; i >= 0; i--) {
323 final Task task = apps.valueAt(i).mTask;
324 if (task != null && task.isHomeTask()) {
325 return isWithinDisplay(task);
326 }
327 }
328 return false;
329 }
330
331 private boolean isWithinDisplay(Task task) {
332 task.mStack.getBounds(mTmpRect);
333 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
334 return mTmpRect.intersect(mTmpRect2);
335 }
336
337 /**
338 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
339 * docked stack are heavily clipped so you can only see a minimal peek state.
340 *
341 * @param minimizedDock Whether the docked stack is currently minimized.
342 * @param animate Whether to animate the change.
343 */
344 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700345 final boolean wasMinimized = mMinimizedDock;
346 mMinimizedDock = minimizedDock;
347 if (minimizedDock == wasMinimized
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800348 || mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
349 return;
350 }
351
Chong Zhangbaba7832016-03-24 10:21:26 -0700352 mAnimatingForIme = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800353 if (minimizedDock) {
354 if (animate) {
355 startAdjustAnimation(0f, 1f);
356 } else {
357 setMinimizedDockedStack(true);
358 }
359 } else {
360 if (animate) {
361 startAdjustAnimation(1f, 0f);
362 } else {
363 setMinimizedDockedStack(false);
364 }
365 }
366 }
367
368 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700369 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800370 mAnimationStarted = false;
371 mAnimationStart = from;
372 mAnimationTarget = to;
373 }
374
375 private void setMinimizedDockedStack(boolean minimized) {
376 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700377 notifyDockedStackMinimizedChanged(minimized, 0);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800378 if (stack == null) {
379 return;
380 }
381 if (stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f)) {
382 mService.mWindowPlacerLocked.performSurfacePlacement();
383 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800384 }
385
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800386 private boolean isAnimationMaximizing() {
387 return mAnimationTarget == 0f;
388 }
389
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800390 public boolean animate(long now) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700391 if (mAnimatingForMinimizedDockedStack) {
392 return animateForMinimizedDockedStack(now);
393 } else if (mAnimatingForIme) {
394 return animateForIme();
395 } else {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800396 return false;
397 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700398 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800399
Chong Zhangbaba7832016-03-24 10:21:26 -0700400 private boolean animateForIme() {
401 boolean updated = false;
402 boolean animating = false;
403
404 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
405 for (int i = stacks.size() - 1; i >= 0; --i) {
406 final TaskStack stack = stacks.get(i);
407 if (stack != null && stack.isAdjustedForIme()) {
408 updated |= stack.updateAdjustForIme();
409 animating |= stack.isAnimatingForIme();
410 }
411 }
412
413 if (updated) {
414 mService.mWindowPlacerLocked.performSurfacePlacement();
415 }
416
417 if (!animating) {
418 mAnimatingForIme = false;
419 for (int i = stacks.size() - 1; i >= 0; --i) {
420 final TaskStack stack = stacks.get(i);
421 if (stack != null) {
422 stack.clearImeGoingAway();
423 }
424 }
425 }
426 return animating;
427 }
428
429 private boolean animateForMinimizedDockedStack(long now) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800430 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800431 if (!mAnimationStarted) {
432 mAnimationStarted = true;
433 mAnimationStartTime = now;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800434 final long transitionDuration = isAnimationMaximizing()
435 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
436 : DEFAULT_APP_TRANSITION_DURATION;
437 mAnimationDuration = (long)
438 (transitionDuration * mService.getTransitionAnimationScaleLocked());
Jorim Jaggif97ed922016-02-18 18:57:07 -0800439 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800440 notifyDockedStackMinimizedChanged(mMinimizedDock,
Jorim Jaggif97ed922016-02-18 18:57:07 -0800441 (long) (mAnimationDuration * mMaximizeMeetFraction));
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800442 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800443 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
444 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
445 .getInterpolation(t);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800446 if (stack != null) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800447 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800448 mService.mWindowPlacerLocked.performSurfacePlacement();
449 }
450 }
451 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700452 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800453 return false;
454 } else {
455 return true;
456 }
457 }
458
Jorim Jaggif97ed922016-02-18 18:57:07 -0800459 /**
460 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
461 */
462 private float getMinimizeAmount(TaskStack stack, float t) {
463 final float naturalAmount = t * mAnimationTarget + (1 - t) * mAnimationStart;
464 if (isAnimationMaximizing()) {
465 return adjustMaximizeAmount(stack, t, naturalAmount);
466 } else {
467 return naturalAmount;
468 }
469 }
470
471 /**
472 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
473 * during the transition such that the edge of the clip reveal rect is met earlier in the
474 * transition so we don't create a visible "hole", but only if both the clip reveal and the
475 * docked stack divider start from about the same portion on the screen.
476 */
477 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
478 if (mMaximizeMeetFraction == 1f) {
479 return naturalAmount;
480 }
481 final int minimizeDistance = stack.getMinimizeDistance();
482 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
483 / (float) minimizeDistance;
484 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
485 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
486 return amountPrime * t2 + naturalAmount * (1 - t2);
487 }
488
489 /**
490 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
491 * edge. See {@link #adjustMaximizeAmount}.
492 */
493 private float getClipRevealMeetFraction(TaskStack stack) {
494 if (!isAnimationMaximizing() || stack == null ||
495 !mService.mAppTransition.hadClipRevealAnimation()) {
496 return 1f;
497 }
498 final int minimizeDistance = stack.getMinimizeDistance();
499 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
500 / (float) minimizeDistance;
501 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
502 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
503 return CLIP_REVEAL_MEET_EARLIEST
504 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
505 }
506
Jorim Jaggi50981592015-12-29 17:54:12 +0100507 @Override
508 public boolean isFullscreen() {
509 return false;
510 }
511
512 @Override
513 public DisplayInfo getDisplayInfo() {
514 return mDisplayContent.getDisplayInfo();
515 }
516
517 @Override
518 public void getDimBounds(Rect outBounds) {
519 // This dim layer user doesn't need this.
520 }
521
522 @Override
523 public String toShortString() {
524 return TAG;
525 }
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700526}