blob: 61425114ff9d5d6b4be4da6d5535464c579f9188 [file] [log] [blame]
Filip Gruszczynski466f3212015-09-21 17:57:57 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wm;
18
Jorim Jaggibc5425c2016-03-01 13:51:16 +010019import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
Jorim Jaggid3ec5072016-04-28 15:57:47 -070020import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010021import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
22import static android.view.WindowManager.DOCKED_BOTTOM;
23import static android.view.WindowManager.DOCKED_LEFT;
24import static android.view.WindowManager.DOCKED_RIGHT;
25import static android.view.WindowManager.DOCKED_TOP;
26import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
27import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
28import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
29import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Tony Mak853304c2016-04-18 15:17:41 +010030import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010031
Filip Gruszczynski466f3212015-09-21 17:57:57 -070032import android.content.Context;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070033import android.graphics.Rect;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010034import android.os.RemoteCallbackList;
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080035import android.os.RemoteException;
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
Jorim Jaggi31f71702016-05-04 16:43:04 -070047import java.io.PrintWriter;
Chong Zhangbaba7832016-03-24 10:21:26 -070048import java.util.ArrayList;
49
Filip Gruszczynski466f3212015-09-21 17:57:57 -070050/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010051 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070052 */
Jorim Jaggi50981592015-12-29 17:54:12 +010053public class DockedStackDividerController implements DimLayerUser {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010054
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080055 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010056
Jorim Jaggif97ed922016-02-18 18:57:07 -080057 /**
58 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
59 * revealing surface at the earliest.
60 */
61 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
62
63 /**
64 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
65 * revealing surface at the latest.
66 */
67 private static final float CLIP_REVEAL_MEET_LAST = 1f;
68
69 /**
70 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
71 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
72 */
73 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
74
75 /**
76 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
77 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
78 */
79 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
80
Jorim Jaggieb88d832016-04-13 20:17:43 -070081 private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
Jorim Jaggiff71d202016-04-14 13:12:36 -070082 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggieb88d832016-04-13 20:17:43 -070083
Jorim Jaggi698e7632016-04-13 21:02:22 -070084 private static final long IME_ADJUST_ANIM_DURATION = 280;
Jorim Jaggieb88d832016-04-13 20:17:43 -070085
Jorim Jaggiff71d202016-04-14 13:12:36 -070086 private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
87
Chong Zhang198afac2016-04-15 12:03:11 -070088 private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
89
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080090 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070091 private final DisplayContent mDisplayContent;
Jorim Jaggi11c62e12016-04-05 20:41:21 -070092 private int mDividerWindowWidth;
Chong Zhang198afac2016-04-15 12:03:11 -070093 private int mDividerWindowWidthInactive;
Jorim Jaggi11c62e12016-04-05 20:41:21 -070094 private int mDividerInsets;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010095 private boolean mResizing;
96 private WindowState mWindow;
97 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080098 private final Rect mTmpRect2 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -080099 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800100 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100101 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
102 = new RemoteCallbackList<>();
Jorim Jaggi50981592015-12-29 17:54:12 +0100103 private final DimLayer mDimLayer;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700104
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800105 private boolean mMinimizedDock;
Chong Zhangbaba7832016-03-24 10:21:26 -0700106 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800107 private boolean mAnimationStarted;
108 private long mAnimationStartTime;
109 private float mAnimationStart;
110 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800111 private long mAnimationDuration;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700112 private boolean mAnimationStartDelayed;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800113 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800114 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100115 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700116 private boolean mAnimatingForIme;
117 private boolean mAdjustedForIme;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700118 private WindowState mDelayedImeWin;
Chong Zhangf347ab52016-04-18 21:02:01 -0700119 private boolean mAdjustedForDivider;
120 private float mDividerAnimationStart;
121 private float mDividerAnimationTarget;
122 private float mLastAnimationProgress;
123 private float mLastDividerProgress;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800124
125 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
126 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700127 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800128 final Context context = service.mContext;
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100129 mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
130 "DockedStackDim");
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800131 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
132 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700133 loadDimens();
134 }
135
136 private void loadDimens() {
137 final Context context = mService.mContext;
138 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
139 com.android.internal.R.dimen.docked_stack_divider_thickness);
140 mDividerInsets = context.getResources().getDimensionPixelSize(
141 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700142 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
143 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700144 }
145
146 void onConfigurationChanged() {
147 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700148 }
149
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100150 boolean isResizing() {
151 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700152 }
153
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100154 int getContentWidth() {
155 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700156 }
157
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800158 int getContentInsets() {
159 return mDividerInsets;
160 }
161
Chong Zhang198afac2016-04-15 12:03:11 -0700162 int getContentWidthInactive() {
163 return mDividerWindowWidthInactive;
164 }
165
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100166 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800167 if (mResizing != resizing) {
168 mResizing = resizing;
169 resetDragResizingChangeReported();
170 }
171 }
172
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100173 void setTouchRegion(Rect touchRegion) {
174 mTouchRegion.set(touchRegion);
175 }
176
177 void getTouchRegion(Rect outRegion) {
178 outRegion.set(mTouchRegion);
179 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
180 }
181
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800182 private void resetDragResizingChangeReported() {
183 final WindowList windowList = mDisplayContent.getWindowList();
184 for (int i = windowList.size() - 1; i >= 0; i--) {
185 windowList.get(i).resetDragResizingChangeReported();
186 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100187 }
188
189 void setWindow(WindowState window) {
190 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800191 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100192 }
193
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800194 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800195 if (mWindow == null) {
196 return;
197 }
Jorim Jaggie48f4282015-11-06 17:32:44 +0100198 TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi7998e482016-02-12 18:47:06 -0800199
200 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
201 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800202 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800203 return;
204 }
205 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100206 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100207 if (!visible) {
208 setResizeDimLayer(false, INVALID_STACK_ID, 0f);
209 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100210 }
211
212 boolean wasVisible() {
213 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100214 }
215
Chong Zhangf347ab52016-04-18 21:02:01 -0700216 void setAdjustedForIme(
217 boolean adjustedForIme, boolean adjustedForDivider,
218 boolean animate, WindowState imeWin) {
219 if (mAdjustedForIme != adjustedForIme || mAdjustedForDivider != adjustedForDivider) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700220 if (animate) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700221 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700222 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700223 // Animation might be delayed, so only notify if we don't run an animation.
Chong Zhangf347ab52016-04-18 21:02:01 -0700224 notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700225 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700226 mAdjustedForIme = adjustedForIme;
227 mAdjustedForDivider = adjustedForDivider;
Chong Zhangbaba7832016-03-24 10:21:26 -0700228 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700229 }
230
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700231 void positionDockedStackedDivider(Rect frame) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700232 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700233 if (stack == null) {
234 // Unfortunately we might end up with still having a divider, even though the underlying
235 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800236 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
237 // keep putting it in the same place it was before the stack was removed to have
238 // continuity and prevent it from jumping to the center. It will get hidden soon.
239 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700240 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800241 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800242 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700243 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100244 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700245 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700246 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100247 frame.set(mTmpRect.right - mDividerInsets, frame.top,
248 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700249 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700250 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100251 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
252 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700253 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700254 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100255 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
256 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700257 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700258 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100259 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
260 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700261 break;
262 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800263 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700264 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800265
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100266 void notifyDockedDividerVisibilityChanged(boolean visible) {
267 final int size = mDockedStackListeners.beginBroadcast();
268 for (int i = 0; i < size; ++i) {
269 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
270 try {
271 listener.onDividerVisibilityChanged(visible);
272 } catch (RemoteException e) {
273 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
274 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800275 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100276 mDockedStackListeners.finishBroadcast();
277 }
278
279 void notifyDockedStackExistsChanged(boolean exists) {
280 final int size = mDockedStackListeners.beginBroadcast();
281 for (int i = 0; i < size; ++i) {
282 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
283 try {
284 listener.onDockedStackExistsChanged(exists);
285 } catch (RemoteException e) {
286 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
287 }
288 }
289 mDockedStackListeners.finishBroadcast();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700290 if (!exists) {
291 setMinimizedDockedStack(false);
292 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100293 }
294
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800295 void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
Tony Mak853304c2016-04-18 15:17:41 +0100296 mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
297 mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
298 minimizedDock ? 1 : 0, 0).sendToTarget();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800299 final int size = mDockedStackListeners.beginBroadcast();
300 for (int i = 0; i < size; ++i) {
301 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
302 try {
303 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
304 } catch (RemoteException e) {
305 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
306 }
307 }
308 mDockedStackListeners.finishBroadcast();
309 }
310
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700311 void notifyDockSideChanged(int newDockSide) {
312 final int size = mDockedStackListeners.beginBroadcast();
313 for (int i = 0; i < size; ++i) {
314 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
315 try {
316 listener.onDockSideChanged(newDockSide);
317 } catch (RemoteException e) {
318 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
319 }
320 }
321 mDockedStackListeners.finishBroadcast();
322 }
323
Jorim Jaggi698e7632016-04-13 21:02:22 -0700324 void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
325 final int size = mDockedStackListeners.beginBroadcast();
326 for (int i = 0; i < size; ++i) {
327 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
328 try {
329 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
330 } catch (RemoteException e) {
331 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
332 }
333 }
334 mDockedStackListeners.finishBroadcast();
335 }
336
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100337 void registerDockedStackListener(IDockedStackListener listener) {
338 mDockedStackListeners.register(listener);
339 notifyDockedDividerVisibilityChanged(wasVisible());
340 notifyDockedStackExistsChanged(
341 mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700342 notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
Jorim Jaggi698e7632016-04-13 21:02:22 -0700343 notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
344
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800345 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100346
347 void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
348 SurfaceControl.openTransaction();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100349 final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
350 final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
351 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100352 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100353 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100354 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100355 mDimLayer.setBounds(mTmpRect);
Chong Zhang1402c2e2016-04-21 15:17:47 -0700356 mDimLayer.show(mService.mLayersController.getResizeDimLayer(),
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100357 alpha, 0 /* duration */);
358 } else {
359 visibleAndValid = false;
360 }
361 }
362 if (!visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100363 mDimLayer.hide();
364 }
365 SurfaceControl.closeTransaction();
366 }
367
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800368 /**
369 * Notifies the docked stack divider controller of a visibility change that happens without
370 * an animation.
371 */
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700372 void notifyAppVisibilityChanged() {
373 checkMinimizeChanged(false /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800374 }
375
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700376 void notifyAppTransitionStarting() {
377 checkMinimizeChanged(true /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800378 }
379
Jorim Jaggi1ae68bf2016-05-09 18:44:34 -0700380 boolean isMinimizedDock() {
381 return mMinimizedDock;
382 }
383
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700384 private void checkMinimizeChanged(boolean animate) {
Jorim Jaggi817a5242016-05-06 15:45:00 -0700385 if (mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
386 return;
387 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700388 final TaskStack homeStack = mDisplayContent.getHomeStack();
389 if (homeStack == null) {
390 return;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800391 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700392 final Task homeTask = homeStack.findHomeTask();
393 if (homeTask == null || !isWithinDisplay(homeTask)) {
394 return;
395 }
396 final TaskStack fullscreenStack
397 = mService.mStackIdToStack.get(FULLSCREEN_WORKSPACE_STACK_ID);
398 final ArrayList<Task> homeStackTasks = homeStack.getTasks();
399 final Task topHomeStackTask = homeStackTasks.get(homeStackTasks.size() - 1);
400 final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
401 final boolean homeBehind = (fullscreenStack != null && fullscreenStack.isVisibleLocked())
402 || (homeStackTasks.size() > 1 && topHomeStackTask != homeTask);
403 setMinimizedDockedStack(homeVisible && !homeBehind, animate);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800404 }
405
406 private boolean isWithinDisplay(Task task) {
407 task.mStack.getBounds(mTmpRect);
408 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
409 return mTmpRect.intersect(mTmpRect2);
410 }
411
412 /**
413 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
414 * docked stack are heavily clipped so you can only see a minimal peek state.
415 *
416 * @param minimizedDock Whether the docked stack is currently minimized.
417 * @param animate Whether to animate the change.
418 */
419 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700420 final boolean wasMinimized = mMinimizedDock;
421 mMinimizedDock = minimizedDock;
Jorim Jaggi817a5242016-05-06 15:45:00 -0700422 if (minimizedDock == wasMinimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800423 return;
424 }
425
Jorim Jaggieb88d832016-04-13 20:17:43 -0700426 clearImeAdjustAnimation();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800427 if (minimizedDock) {
428 if (animate) {
429 startAdjustAnimation(0f, 1f);
430 } else {
431 setMinimizedDockedStack(true);
432 }
433 } else {
434 if (animate) {
435 startAdjustAnimation(1f, 0f);
436 } else {
437 setMinimizedDockedStack(false);
438 }
439 }
440 }
441
Jorim Jaggieb88d832016-04-13 20:17:43 -0700442 private void clearImeAdjustAnimation() {
443 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
444 for (int i = stacks.size() - 1; i >= 0; --i) {
445 final TaskStack stack = stacks.get(i);
446 if (stack != null && stack.isAdjustedForIme()) {
447 stack.resetAdjustedForIme(true /* adjustBoundsNow */);
448 }
449 }
450 mAnimatingForIme = false;
451 }
452
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800453 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700454 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800455 mAnimationStarted = false;
456 mAnimationStart = from;
457 mAnimationTarget = to;
458 }
459
Chong Zhangf347ab52016-04-18 21:02:01 -0700460 private void startImeAdjustAnimation(
461 boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700462 mAnimatingForIme = true;
463 mAnimationStarted = false;
Chong Zhangf347ab52016-04-18 21:02:01 -0700464
465 // If we're not in an animation, the starting point depends on whether we're adjusted
466 // or not. If we're already in an animation, we start from where the current animation
467 // left off, so that the motion doesn't look discontinuous.
468 if (!mAnimatingForIme) {
469 mAnimationStart = mAdjustedForIme ? 1 : 0;
470 mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
471 mLastAnimationProgress = mAnimationStart;
472 mLastDividerProgress = mDividerAnimationStart;
473 } else {
474 mAnimationStart = mLastAnimationProgress;
475 mDividerAnimationStart = mLastDividerProgress;
476 }
477 mAnimationTarget = adjustedForIme ? 1 : 0;
478 mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700479
480 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
481 for (int i = stacks.size() - 1; i >= 0; --i) {
482 final TaskStack stack = stacks.get(i);
483 if (stack.isVisibleLocked() && stack.isAdjustedForIme()) {
484 stack.beginImeAdjustAnimation();
485 }
486 }
487
488 // We put all tasks into drag resizing mode - wait until all of them have completed the
489 // drag resizing switch.
490 if (!mService.mWaitingForDrawn.isEmpty()) {
491 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
492 mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
493 IME_ADJUST_DRAWN_TIMEOUT);
494 mAnimationStartDelayed = true;
495 if (imeWin != null) {
496
497 // There might be an old window delaying the animation start - clear it.
498 if (mDelayedImeWin != null) {
499 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
500 }
501 mDelayedImeWin = imeWin;
502 imeWin.mWinAnimator.startDelayingAnimationStart();
503 }
504 mService.mWaitingForDrawnCallback = () -> {
505 mAnimationStartDelayed = false;
506 if (mDelayedImeWin != null) {
507 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
508 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700509 notifyAdjustedForImeChanged(
510 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700511 };
512 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700513 notifyAdjustedForImeChanged(
514 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700515 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700516 }
517
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800518 private void setMinimizedDockedStack(boolean minimized) {
519 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700520 notifyDockedStackMinimizedChanged(minimized, 0);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800521 if (stack == null) {
522 return;
523 }
524 if (stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f)) {
525 mService.mWindowPlacerLocked.performSurfacePlacement();
526 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800527 }
528
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800529 private boolean isAnimationMaximizing() {
530 return mAnimationTarget == 0f;
531 }
532
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800533 public boolean animate(long now) {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700534 if (mWindow == null) {
535 return false;
536 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700537 if (mAnimatingForMinimizedDockedStack) {
538 return animateForMinimizedDockedStack(now);
539 } else if (mAnimatingForIme) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700540 return animateForIme(now);
Chong Zhangbaba7832016-03-24 10:21:26 -0700541 } else {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700542 if (mDimLayer != null && mDimLayer.isDimming()) {
Chong Zhang1402c2e2016-04-21 15:17:47 -0700543 mDimLayer.setLayer(mService.mLayersController.getResizeDimLayer());
544 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800545 return false;
546 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700547 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800548
Jorim Jaggieb88d832016-04-13 20:17:43 -0700549 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700550 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700551 mAnimationStarted = true;
552 mAnimationStartTime = now;
553 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700554 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700555 }
556 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
557 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
558 .getInterpolation(t);
Chong Zhangbaba7832016-03-24 10:21:26 -0700559 final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700560 boolean updated = false;
Chong Zhangbaba7832016-03-24 10:21:26 -0700561 for (int i = stacks.size() - 1; i >= 0; --i) {
562 final TaskStack stack = stacks.get(i);
563 if (stack != null && stack.isAdjustedForIme()) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700564 if (t >= 1f && mAnimationTarget == 0f && mDividerAnimationTarget == 0f) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700565 stack.resetAdjustedForIme(true /* adjustBoundsNow */);
566 updated = true;
567 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700568 mLastAnimationProgress = getInterpolatedAnimationValue(t);
569 mLastDividerProgress = getInterpolatedDividerValue(t);
570 updated |= stack.updateAdjustForIme(
571 mLastAnimationProgress,
572 mLastDividerProgress,
Jorim Jaggiff71d202016-04-14 13:12:36 -0700573 false /* force */);
574 }
575 if (t >= 1f) {
576 stack.endImeAdjustAnimation();
Chong Zhangbaba7832016-03-24 10:21:26 -0700577 }
578 }
579 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700580 if (updated) {
581 mService.mWindowPlacerLocked.performSurfacePlacement();
582 }
583 if (t >= 1.0f) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700584 mLastAnimationProgress = mAnimationTarget;
585 mLastDividerProgress = mDividerAnimationTarget;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700586 mAnimatingForIme = false;
587 return false;
588 } else {
589 return true;
590 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700591 }
592
593 private boolean animateForMinimizedDockedStack(long now) {
Jorim Jaggiaf558e12016-04-27 22:56:56 -0700594 final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800595 if (!mAnimationStarted) {
596 mAnimationStarted = true;
597 mAnimationStartTime = now;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800598 final long transitionDuration = isAnimationMaximizing()
599 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
600 : DEFAULT_APP_TRANSITION_DURATION;
601 mAnimationDuration = (long)
602 (transitionDuration * mService.getTransitionAnimationScaleLocked());
Jorim Jaggif97ed922016-02-18 18:57:07 -0800603 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800604 notifyDockedStackMinimizedChanged(mMinimizedDock,
Jorim Jaggif97ed922016-02-18 18:57:07 -0800605 (long) (mAnimationDuration * mMaximizeMeetFraction));
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800606 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800607 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
608 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
609 .getInterpolation(t);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800610 if (stack != null) {
Jorim Jaggif97ed922016-02-18 18:57:07 -0800611 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800612 mService.mWindowPlacerLocked.performSurfacePlacement();
613 }
614 }
615 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700616 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800617 return false;
618 } else {
619 return true;
620 }
621 }
622
Jorim Jaggieb88d832016-04-13 20:17:43 -0700623 private float getInterpolatedAnimationValue(float t) {
624 return t * mAnimationTarget + (1 - t) * mAnimationStart;
625 }
626
Chong Zhangf347ab52016-04-18 21:02:01 -0700627 private float getInterpolatedDividerValue(float t) {
628 return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
629 }
630
Jorim Jaggif97ed922016-02-18 18:57:07 -0800631 /**
632 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
633 */
634 private float getMinimizeAmount(TaskStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700635 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800636 if (isAnimationMaximizing()) {
637 return adjustMaximizeAmount(stack, t, naturalAmount);
638 } else {
639 return naturalAmount;
640 }
641 }
642
643 /**
644 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
645 * during the transition such that the edge of the clip reveal rect is met earlier in the
646 * transition so we don't create a visible "hole", but only if both the clip reveal and the
647 * docked stack divider start from about the same portion on the screen.
648 */
649 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
650 if (mMaximizeMeetFraction == 1f) {
651 return naturalAmount;
652 }
653 final int minimizeDistance = stack.getMinimizeDistance();
654 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
655 / (float) minimizeDistance;
656 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
657 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
658 return amountPrime * t2 + naturalAmount * (1 - t2);
659 }
660
661 /**
662 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
663 * edge. See {@link #adjustMaximizeAmount}.
664 */
665 private float getClipRevealMeetFraction(TaskStack stack) {
666 if (!isAnimationMaximizing() || stack == null ||
667 !mService.mAppTransition.hadClipRevealAnimation()) {
668 return 1f;
669 }
670 final int minimizeDistance = stack.getMinimizeDistance();
671 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
672 / (float) minimizeDistance;
673 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
674 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
675 return CLIP_REVEAL_MEET_EARLIEST
676 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
677 }
678
Jorim Jaggi50981592015-12-29 17:54:12 +0100679 @Override
680 public boolean isFullscreen() {
681 return false;
682 }
683
684 @Override
685 public DisplayInfo getDisplayInfo() {
686 return mDisplayContent.getDisplayInfo();
687 }
688
689 @Override
690 public void getDimBounds(Rect outBounds) {
691 // This dim layer user doesn't need this.
692 }
693
694 @Override
695 public String toShortString() {
696 return TAG;
697 }
Robert Carre63e01a2016-04-18 20:27:34 -0700698
699 WindowState getWindow() {
700 return mWindow;
701 }
Jorim Jaggi31f71702016-05-04 16:43:04 -0700702
703 void dump(String prefix, PrintWriter pw) {
704 pw.println(prefix + "DockedStackDividerController");
705 pw.println(prefix + " mLastVisibility=" + mLastVisibility);
706 pw.println(prefix + " mMinimizedDock=" + mMinimizedDock);
707 pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme);
708 pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider);
709 if (mDimLayer.isDimming()) {
710 pw.println(prefix + " Dim layer is dimming: ");
711 mDimLayer.printTo(prefix + " ", pw);
712 }
713 }
Robert Carre63e01a2016-04-18 20:27:34 -0700714}