blob: f75f224d71238ba58e85d75efa991ef9794efecf [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;
Jorim Jaggi85639432016-05-06 17:27:55 -070022import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
23import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
24import static android.view.Surface.ROTATION_270;
25import static android.view.Surface.ROTATION_90;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010026import static android.view.WindowManager.DOCKED_BOTTOM;
27import static android.view.WindowManager.DOCKED_LEFT;
28import static android.view.WindowManager.DOCKED_RIGHT;
29import static android.view.WindowManager.DOCKED_TOP;
30import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
31import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
Jorim Jaggi84afb1a2016-09-28 14:54:04 +020032import static com.android.server.wm.AppTransition.TRANSIT_NONE;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010033import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
34import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Tony Mak853304c2016-04-18 15:17:41 +010035import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
Wale Ogunwalec69694a2016-10-18 13:51:15 -070036import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010037
Filip Gruszczynski466f3212015-09-21 17:57:57 -070038import android.content.Context;
Jorim Jaggi85639432016-05-06 17:27:55 -070039import android.content.res.Configuration;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070040import android.graphics.Rect;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010041import android.os.RemoteCallbackList;
Filip Gruszczynski64cdc142015-11-29 21:10:07 -080042import android.os.RemoteException;
Jorim Jaggi936aaeb2016-08-26 19:02:11 -070043import android.util.ArraySet;
Filip Gruszczynski77049052015-11-09 14:01:21 -080044import android.util.Slog;
Jorim Jaggi50981592015-12-29 17:54:12 +010045import android.view.DisplayInfo;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010046import android.view.IDockedStackListener;
Jorim Jaggi50981592015-12-29 17:54:12 +010047import android.view.SurfaceControl;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080048import android.view.animation.AnimationUtils;
49import android.view.animation.Interpolator;
Jorim Jaggieb88d832016-04-13 20:17:43 -070050import android.view.animation.PathInterpolator;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070051import android.view.inputmethod.InputMethodManagerInternal;
Jorim Jaggi50981592015-12-29 17:54:12 +010052
Jorim Jaggi85639432016-05-06 17:27:55 -070053import com.android.internal.policy.DividerSnapAlgorithm;
54import com.android.internal.policy.DockedDividerUtils;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -070055import com.android.server.LocalServices;
Jorim Jaggi50981592015-12-29 17:54:12 +010056import com.android.server.wm.DimLayer.DimLayerUser;
Jorim Jaggiff71d202016-04-14 13:12:36 -070057import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010058
Jorim Jaggi31f71702016-05-04 16:43:04 -070059import java.io.PrintWriter;
Chong Zhangbaba7832016-03-24 10:21:26 -070060import java.util.ArrayList;
61
Filip Gruszczynski466f3212015-09-21 17:57:57 -070062/**
Jorim Jaggi61f39a72015-10-29 16:54:18 +010063 * Keeps information about the docked stack divider.
Filip Gruszczynski466f3212015-09-21 17:57:57 -070064 */
Jorim Jaggi50981592015-12-29 17:54:12 +010065public class DockedStackDividerController implements DimLayerUser {
Jorim Jaggi61f39a72015-10-29 16:54:18 +010066
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080067 private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010068
Jorim Jaggif97ed922016-02-18 18:57:07 -080069 /**
70 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
71 * revealing surface at the earliest.
72 */
73 private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
74
75 /**
76 * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
77 * revealing surface at the latest.
78 */
79 private static final float CLIP_REVEAL_MEET_LAST = 1f;
80
81 /**
82 * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
83 * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
84 */
85 private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
86
87 /**
88 * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
89 * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
90 */
91 private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
92
Jorim Jaggieb88d832016-04-13 20:17:43 -070093 private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
Jorim Jaggiff71d202016-04-14 13:12:36 -070094 new PathInterpolator(0.2f, 0f, 0.1f, 1f);
Jorim Jaggieb88d832016-04-13 20:17:43 -070095
Jorim Jaggi698e7632016-04-13 21:02:22 -070096 private static final long IME_ADJUST_ANIM_DURATION = 280;
Jorim Jaggieb88d832016-04-13 20:17:43 -070097
Jorim Jaggiff71d202016-04-14 13:12:36 -070098 private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
99
Chong Zhang198afac2016-04-15 12:03:11 -0700100 private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
101
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800102 private final WindowManagerService mService;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700103 private final DisplayContent mDisplayContent;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700104 private int mDividerWindowWidth;
Chong Zhang198afac2016-04-15 12:03:11 -0700105 private int mDividerWindowWidthInactive;
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700106 private int mDividerInsets;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100107 private boolean mResizing;
108 private WindowState mWindow;
109 private final Rect mTmpRect = new Rect();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800110 private final Rect mTmpRect2 = new Rect();
Jorim Jaggi85639432016-05-06 17:27:55 -0700111 private final Rect mTmpRect3 = new Rect();
Filip Gruszczynski77049052015-11-09 14:01:21 -0800112 private final Rect mLastRect = new Rect();
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800113 private boolean mLastVisibility = false;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100114 private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
115 = new RemoteCallbackList<>();
Jorim Jaggi50981592015-12-29 17:54:12 +0100116 private final DimLayer mDimLayer;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700117
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800118 private boolean mMinimizedDock;
Chong Zhangbaba7832016-03-24 10:21:26 -0700119 private boolean mAnimatingForMinimizedDockedStack;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800120 private boolean mAnimationStarted;
121 private long mAnimationStartTime;
122 private float mAnimationStart;
123 private float mAnimationTarget;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800124 private long mAnimationDuration;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700125 private boolean mAnimationStartDelayed;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800126 private final Interpolator mMinimizedDockInterpolator;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800127 private float mMaximizeMeetFraction;
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100128 private final Rect mTouchRegion = new Rect();
Chong Zhangbaba7832016-03-24 10:21:26 -0700129 private boolean mAnimatingForIme;
130 private boolean mAdjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700131 private int mImeHeight;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700132 private WindowState mDelayedImeWin;
Chong Zhangf347ab52016-04-18 21:02:01 -0700133 private boolean mAdjustedForDivider;
134 private float mDividerAnimationStart;
135 private float mDividerAnimationTarget;
Wale Ogunwale10124582016-09-15 20:25:50 -0700136 float mLastAnimationProgress;
137 float mLastDividerProgress;
Jorim Jaggi85639432016-05-06 17:27:55 -0700138 private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700139 private boolean mImeHideRequested;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800140
141 DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
142 mService = service;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700143 mDisplayContent = displayContent;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800144 final Context context = service.mContext;
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100145 mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId(),
146 "DockedStackDim");
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800147 mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
148 context, android.R.interpolator.fast_out_slow_in);
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700149 loadDimens();
150 }
151
Jorim Jaggi85639432016-05-06 17:27:55 -0700152 int getSmallestWidthDpForBounds(Rect bounds) {
153 final DisplayInfo di = mDisplayContent.getDisplayInfo();
154
155 // If the bounds are fullscreen, return the value of the fullscreen configuration
156 if (bounds == null || (bounds.left == 0 && bounds.top == 0
157 && bounds.right == di.logicalWidth && bounds.bottom == di.logicalHeight)) {
Andrii Kulian441e4492016-09-29 15:25:00 -0700158 return mDisplayContent.getConfiguration().smallestScreenWidthDp;
Jorim Jaggi85639432016-05-06 17:27:55 -0700159 }
160 final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
161 final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
162 int minWidth = Integer.MAX_VALUE;
163
164 // Go through all screen orientations and find the orientation in which the task has the
165 // smallest width.
166 for (int rotation = 0; rotation < 4; rotation++) {
167 mTmpRect.set(bounds);
168 mDisplayContent.rotateBounds(di.rotation, rotation, mTmpRect);
169 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
170 mTmpRect2.set(0, 0,
171 rotated ? baseDisplayHeight : baseDisplayWidth,
172 rotated ? baseDisplayWidth : baseDisplayHeight);
173 final int orientation = mTmpRect2.width() <= mTmpRect2.height()
174 ? ORIENTATION_PORTRAIT
175 : ORIENTATION_LANDSCAPE;
176 final int dockSide = TaskStack.getDockSideUnchecked(mTmpRect, mTmpRect2, orientation);
177 final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
178 getContentWidth());
179
180 // Since we only care about feasible states, snap to the closest snap target, like it
181 // would happen when actually rotating the screen.
182 final int snappedPosition = mSnapAlgorithmForRotation[rotation]
183 .calculateNonDismissingSnapTarget(position).position;
184 DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, mTmpRect,
185 mTmpRect2.width(), mTmpRect2.height(), getContentWidth());
186 mService.mPolicy.getStableInsetsLw(rotation, mTmpRect2.width(), mTmpRect2.height(),
187 mTmpRect3);
188 mService.subtractInsets(mTmpRect2, mTmpRect3, mTmpRect);
189 minWidth = Math.min(mTmpRect.width(), minWidth);
190 }
191 return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
192 }
193
194 private void initSnapAlgorithmForRotations() {
Andrii Kulian441e4492016-09-29 15:25:00 -0700195 final Configuration baseConfig = mDisplayContent.getConfiguration();
Jorim Jaggi85639432016-05-06 17:27:55 -0700196
197 // Initialize the snap algorithms for all 4 screen orientations.
198 final Configuration config = new Configuration();
199 for (int rotation = 0; rotation < 4; rotation++) {
200 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
201 final int dw = rotated
202 ? mDisplayContent.mBaseDisplayHeight
203 : mDisplayContent.mBaseDisplayWidth;
204 final int dh = rotated
205 ? mDisplayContent.mBaseDisplayWidth
206 : mDisplayContent.mBaseDisplayHeight;
207 mService.mPolicy.getStableInsetsLw(rotation, dw, dh, mTmpRect);
Andrii Kulianb10330d2016-09-16 13:51:46 -0700208 config.unset();
Jorim Jaggi85639432016-05-06 17:27:55 -0700209 config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
210 config.screenWidthDp = (int)
211 (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode) /
212 mDisplayContent.getDisplayMetrics().density);
213 config.screenHeightDp = (int)
214 (mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, baseConfig.uiMode) /
215 mDisplayContent.getDisplayMetrics().density);
216 final Context rotationContext = mService.mContext.createConfigurationContext(config);
217 mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
218 rotationContext.getResources(), dw, dh, getContentWidth(),
219 config.orientation == ORIENTATION_PORTRAIT, mTmpRect);
220 }
221 }
222
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700223 private void loadDimens() {
224 final Context context = mService.mContext;
225 mDividerWindowWidth = context.getResources().getDimensionPixelSize(
226 com.android.internal.R.dimen.docked_stack_divider_thickness);
227 mDividerInsets = context.getResources().getDimensionPixelSize(
228 com.android.internal.R.dimen.docked_stack_divider_insets);
Chong Zhang198afac2016-04-15 12:03:11 -0700229 mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
230 DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
Jorim Jaggi85639432016-05-06 17:27:55 -0700231 initSnapAlgorithmForRotations();
Jorim Jaggi11c62e12016-04-05 20:41:21 -0700232 }
233
234 void onConfigurationChanged() {
235 loadDimens();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700236 }
237
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100238 boolean isResizing() {
239 return mResizing;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700240 }
241
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100242 int getContentWidth() {
243 return mDividerWindowWidth - 2 * mDividerInsets;
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700244 }
245
Jorim Jaggi81ba11e2016-02-03 22:04:22 -0800246 int getContentInsets() {
247 return mDividerInsets;
248 }
249
Chong Zhang198afac2016-04-15 12:03:11 -0700250 int getContentWidthInactive() {
251 return mDividerWindowWidthInactive;
252 }
253
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100254 void setResizing(boolean resizing) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800255 if (mResizing != resizing) {
256 mResizing = resizing;
257 resetDragResizingChangeReported();
258 }
259 }
260
Jorim Jaggid47e7e12016-03-01 09:57:38 +0100261 void setTouchRegion(Rect touchRegion) {
262 mTouchRegion.set(touchRegion);
263 }
264
265 void getTouchRegion(Rect outRegion) {
266 outRegion.set(mTouchRegion);
267 outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
268 }
269
Jorim Jaggic662d8e2016-02-05 16:54:54 -0800270 private void resetDragResizingChangeReported() {
271 final WindowList windowList = mDisplayContent.getWindowList();
272 for (int i = windowList.size() - 1; i >= 0; i--) {
273 windowList.get(i).resetDragResizingChangeReported();
274 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100275 }
276
277 void setWindow(WindowState window) {
278 mWindow = window;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800279 reevaluateVisibility(false);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100280 }
281
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800282 void reevaluateVisibility(boolean force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800283 if (mWindow == null) {
284 return;
285 }
Jorim Jaggie48f4282015-11-06 17:32:44 +0100286 TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi7998e482016-02-12 18:47:06 -0800287
288 // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
289 final boolean visible = stack != null;
Filip Gruszczynski85d5cc42015-12-04 09:21:37 -0800290 if (mLastVisibility == visible && !force) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800291 return;
292 }
293 mLastVisibility = visible;
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100294 notifyDockedDividerVisibilityChanged(visible);
Jorim Jaggi50981592015-12-29 17:54:12 +0100295 if (!visible) {
296 setResizeDimLayer(false, INVALID_STACK_ID, 0f);
297 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100298 }
299
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700300 private boolean wasVisible() {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100301 return mLastVisibility;
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100302 }
303
Chong Zhangf347ab52016-04-18 21:02:01 -0700304 void setAdjustedForIme(
305 boolean adjustedForIme, boolean adjustedForDivider,
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700306 boolean animate, WindowState imeWin, int imeHeight) {
307 if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
308 || mAdjustedForDivider != adjustedForDivider) {
Jorim Jaggi3070e772016-05-17 16:41:32 -0700309 if (animate && !mAnimatingForMinimizedDockedStack) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700310 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700311 } else {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700312 // Animation might be delayed, so only notify if we don't run an animation.
Chong Zhangf347ab52016-04-18 21:02:01 -0700313 notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700314 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700315 mAdjustedForIme = adjustedForIme;
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700316 mImeHeight = imeHeight;
Chong Zhangf347ab52016-04-18 21:02:01 -0700317 mAdjustedForDivider = adjustedForDivider;
Chong Zhangbaba7832016-03-24 10:21:26 -0700318 }
Chong Zhangb58bbcc2016-03-23 11:57:36 -0700319 }
320
Keisuke Kuroyanagi19d9a8f2016-05-12 16:49:02 -0700321 int getImeHeightAdjustedFor() {
322 return mImeHeight;
323 }
324
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700325 void positionDockedStackedDivider(Rect frame) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700326 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700327 if (stack == null) {
328 // Unfortunately we might end up with still having a divider, even though the underlying
329 // stack was already removed. This is because we are on AM thread and the removal of the
Filip Gruszczynski77049052015-11-09 14:01:21 -0800330 // divider was deferred to WM thread and hasn't happened yet. In that case let's just
331 // keep putting it in the same place it was before the stack was removed to have
332 // continuity and prevent it from jumping to the center. It will get hidden soon.
333 frame.set(mLastRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700334 return;
Filip Gruszczynski77049052015-11-09 14:01:21 -0800335 } else {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800336 stack.getDimBounds(mTmpRect);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700337 }
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100338 int side = stack.getDockSide();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700339 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700340 case DOCKED_LEFT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100341 frame.set(mTmpRect.right - mDividerInsets, frame.top,
342 mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700343 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700344 case DOCKED_TOP:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100345 frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
346 mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700347 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700348 case DOCKED_RIGHT:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100349 frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
350 mTmpRect.left + mDividerInsets, frame.bottom);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700351 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700352 case DOCKED_BOTTOM:
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100353 frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
354 frame.right, mTmpRect.top + mDividerInsets);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700355 break;
356 }
Filip Gruszczynski77049052015-11-09 14:01:21 -0800357 mLastRect.set(frame);
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700358 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800359
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700360 private void notifyDockedDividerVisibilityChanged(boolean visible) {
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100361 final int size = mDockedStackListeners.beginBroadcast();
362 for (int i = 0; i < size; ++i) {
363 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
364 try {
365 listener.onDividerVisibilityChanged(visible);
366 } catch (RemoteException e) {
367 Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
368 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800369 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100370 mDockedStackListeners.finishBroadcast();
371 }
372
373 void notifyDockedStackExistsChanged(boolean exists) {
Andrii Kulian5406e7a2016-10-21 11:55:23 -0700374 // TODO(multi-display): Perform all actions only for current display.
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100375 final int size = mDockedStackListeners.beginBroadcast();
376 for (int i = 0; i < size; ++i) {
377 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
378 try {
379 listener.onDockedStackExistsChanged(exists);
380 } catch (RemoteException e) {
381 Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
382 }
383 }
384 mDockedStackListeners.finishBroadcast();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700385 if (exists) {
386 InputMethodManagerInternal inputMethodManagerInternal =
387 LocalServices.getService(InputMethodManagerInternal.class);
388 if (inputMethodManagerInternal != null) {
389
390 // Hide the current IME to avoid problems with animations from IME adjustment when
391 // attaching the docked stack.
392 inputMethodManagerInternal.hideCurrentInputMethod();
393 mImeHideRequested = true;
394 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700395 } else if (setMinimizedDockedStack(false)) {
396 mService.mWindowPlacerLocked.performSurfacePlacement();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700397 }
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100398 }
399
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700400 /**
401 * Resets the state that IME hide has been requested. See {@link #isImeHideRequested}.
402 */
403 void resetImeHideRequested() {
404 mImeHideRequested = false;
405 }
406
407 /**
408 * The docked stack divider controller makes sure the IME gets hidden when attaching the docked
409 * stack, to avoid animation problems. This flag indicates whether the request to hide the IME
410 * has been sent in an asynchronous manner, and the IME should be treated as hidden already.
411 *
412 * @return whether IME hide request has been sent
413 */
414 boolean isImeHideRequested() {
415 return mImeHideRequested;
416 }
417
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700418 private void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
Tony Mak853304c2016-04-18 15:17:41 +0100419 mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
420 mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
421 minimizedDock ? 1 : 0, 0).sendToTarget();
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800422 final int size = mDockedStackListeners.beginBroadcast();
423 for (int i = 0; i < size; ++i) {
424 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
425 try {
426 listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
427 } catch (RemoteException e) {
428 Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
429 }
430 }
431 mDockedStackListeners.finishBroadcast();
432 }
433
Jorim Jaggi2917dc42016-04-11 11:39:13 -0700434 void notifyDockSideChanged(int newDockSide) {
435 final int size = mDockedStackListeners.beginBroadcast();
436 for (int i = 0; i < size; ++i) {
437 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
438 try {
439 listener.onDockSideChanged(newDockSide);
440 } catch (RemoteException e) {
441 Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
442 }
443 }
444 mDockedStackListeners.finishBroadcast();
445 }
446
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700447 private void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
Jorim Jaggi698e7632016-04-13 21:02:22 -0700448 final int size = mDockedStackListeners.beginBroadcast();
449 for (int i = 0; i < size; ++i) {
450 final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
451 try {
452 listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
453 } catch (RemoteException e) {
454 Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
455 }
456 }
457 mDockedStackListeners.finishBroadcast();
458 }
459
Jorim Jaggia6c934e2015-12-21 13:22:31 +0100460 void registerDockedStackListener(IDockedStackListener listener) {
461 mDockedStackListeners.register(listener);
462 notifyDockedDividerVisibilityChanged(wasVisible());
463 notifyDockedStackExistsChanged(
464 mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700465 notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
Jorim Jaggi698e7632016-04-13 21:02:22 -0700466 notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
467
Filip Gruszczynski64cdc142015-11-29 21:10:07 -0800468 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100469
470 void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
Robert Carr68e5c9e2016-09-14 10:50:09 -0700471 mService.openSurfaceTransaction();
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100472 final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
473 final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
474 boolean visibleAndValid = visible && stack != null && dockedStack != null;
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100475 if (visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100476 stack.getDimBounds(mTmpRect);
Jorim Jaggi10b89dc2016-01-05 15:40:17 +0100477 if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100478 mDimLayer.setBounds(mTmpRect);
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700479 mDimLayer.show(getResizeDimLayer(), alpha, 0 /* duration */);
Jorim Jaggi7b371dd2016-01-05 15:32:34 +0100480 } else {
481 visibleAndValid = false;
482 }
483 }
484 if (!visibleAndValid) {
Jorim Jaggi50981592015-12-29 17:54:12 +0100485 mDimLayer.hide();
486 }
Robert Carr68e5c9e2016-09-14 10:50:09 -0700487 mService.closeSurfaceTransaction();
Jorim Jaggi50981592015-12-29 17:54:12 +0100488 }
489
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800490 /**
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700491 * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
492 * above all application surfaces.
493 */
494 private int getResizeDimLayer() {
495 return (mWindow != null) ? mWindow.mLayer - 1 : LAYER_OFFSET_DIM;
496 }
497
498 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800499 * Notifies the docked stack divider controller of a visibility change that happens without
500 * an animation.
501 */
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700502 void notifyAppVisibilityChanged() {
503 checkMinimizeChanged(false /* animate */);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800504 }
505
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200506 void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps, int appTransition) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700507 final boolean wasMinimized = mMinimizedDock;
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700508 checkMinimizeChanged(true /* animate */);
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700509
510 // We were minimized, and now we are still minimized, but somebody is trying to launch an
511 // app in docked stack, better show recent apps so we actually get unminimized! This catches
512 // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
513 // we couldn't retrace the launch of the app in the docked stack to the launch from
514 // homescreen.
Jorim Jaggi84afb1a2016-09-28 14:54:04 +0200515 if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
516 && appTransition != TRANSIT_NONE) {
Jorim Jaggi936aaeb2016-08-26 19:02:11 -0700517 mService.showRecentApps(true /* fromHome */);
518 }
519 }
520
521 /**
522 * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
523 */
524 private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
525 for (int i = apps.size() - 1; i >= 0; i--) {
526 final AppWindowToken token = apps.valueAt(i);
527 if (token.mTask != null && token.mTask.mStack.mStackId == DOCKED_STACK_ID) {
528 return true;
529 }
530 }
531 return false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800532 }
533
Jorim Jaggi1ae68bf2016-05-09 18:44:34 -0700534 boolean isMinimizedDock() {
535 return mMinimizedDock;
536 }
537
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700538 private void checkMinimizeChanged(boolean animate) {
Jorim Jaggi817a5242016-05-06 15:45:00 -0700539 if (mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
540 return;
541 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700542 final TaskStack homeStack = mDisplayContent.getHomeStack();
543 if (homeStack == null) {
544 return;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800545 }
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700546 final Task homeTask = homeStack.findHomeTask();
547 if (homeTask == null || !isWithinDisplay(homeTask)) {
548 return;
549 }
550 final TaskStack fullscreenStack
551 = mService.mStackIdToStack.get(FULLSCREEN_WORKSPACE_STACK_ID);
Jorim Jaggid3ec5072016-04-28 15:57:47 -0700552 final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700553 final boolean homeBehind = (fullscreenStack != null && fullscreenStack.isVisible())
Wale Ogunwale15ead902016-09-02 14:30:11 -0700554 || (homeStack.hasMultipleTaskWithHomeTaskNotTop());
Jiaquan He9bc01a82016-07-08 10:29:38 -0700555 // If the home task is an on-top launcher, we don't want to minimize the docked stack.
556 // Instead we want everything underneath that was visible to remain visible.
557 // See android.R.attr#onTopLauncher.
Wale Ogunwale15ead902016-09-02 14:30:11 -0700558 final boolean isOnTopLauncher = homeStack.topTaskIsOnTopLauncher();
Jiaquan He9bc01a82016-07-08 10:29:38 -0700559 setMinimizedDockedStack(homeVisible && !homeBehind && !isOnTopLauncher, animate);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800560 }
561
562 private boolean isWithinDisplay(Task task) {
563 task.mStack.getBounds(mTmpRect);
564 mDisplayContent.getLogicalDisplayRect(mTmpRect2);
565 return mTmpRect.intersect(mTmpRect2);
566 }
567
568 /**
569 * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
570 * docked stack are heavily clipped so you can only see a minimal peek state.
571 *
572 * @param minimizedDock Whether the docked stack is currently minimized.
573 * @param animate Whether to animate the change.
574 */
575 private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700576 final boolean wasMinimized = mMinimizedDock;
577 mMinimizedDock = minimizedDock;
Jorim Jaggi817a5242016-05-06 15:45:00 -0700578 if (minimizedDock == wasMinimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800579 return;
580 }
581
Chong Zhang22eff0a2016-07-01 14:48:11 -0700582 final boolean imeChanged = clearImeAdjustAnimation();
583 boolean minimizedChange = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800584 if (minimizedDock) {
585 if (animate) {
586 startAdjustAnimation(0f, 1f);
587 } else {
Chong Zhang22eff0a2016-07-01 14:48:11 -0700588 minimizedChange |= setMinimizedDockedStack(true);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800589 }
590 } else {
591 if (animate) {
592 startAdjustAnimation(1f, 0f);
593 } else {
Chong Zhang22eff0a2016-07-01 14:48:11 -0700594 minimizedChange |= setMinimizedDockedStack(false);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800595 }
596 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700597 if (imeChanged || minimizedChange) {
598 if (imeChanged && !minimizedChange) {
599 Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing,"
600 + " minimizedDock=" + minimizedDock
601 + " minimizedChange=" + minimizedChange);
602 }
603 mService.mWindowPlacerLocked.performSurfacePlacement();
604 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800605 }
606
Chong Zhang22eff0a2016-07-01 14:48:11 -0700607 private boolean clearImeAdjustAnimation() {
Wale Ogunwale10124582016-09-15 20:25:50 -0700608 final boolean changed = mDisplayContent.clearImeAdjustAnimation();
Jorim Jaggieb88d832016-04-13 20:17:43 -0700609 mAnimatingForIme = false;
Chong Zhang22eff0a2016-07-01 14:48:11 -0700610 return changed;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700611 }
612
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800613 private void startAdjustAnimation(float from, float to) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700614 mAnimatingForMinimizedDockedStack = true;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800615 mAnimationStarted = false;
616 mAnimationStart = from;
617 mAnimationTarget = to;
618 }
619
Chong Zhangf347ab52016-04-18 21:02:01 -0700620 private void startImeAdjustAnimation(
621 boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700622
623 // If we're not in an animation, the starting point depends on whether we're adjusted
624 // or not. If we're already in an animation, we start from where the current animation
625 // left off, so that the motion doesn't look discontinuous.
626 if (!mAnimatingForIme) {
627 mAnimationStart = mAdjustedForIme ? 1 : 0;
628 mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
629 mLastAnimationProgress = mAnimationStart;
630 mLastDividerProgress = mDividerAnimationStart;
631 } else {
632 mAnimationStart = mLastAnimationProgress;
633 mDividerAnimationStart = mLastDividerProgress;
634 }
Jorim Jaggi3070e772016-05-17 16:41:32 -0700635 mAnimatingForIme = true;
636 mAnimationStarted = false;
Chong Zhangf347ab52016-04-18 21:02:01 -0700637 mAnimationTarget = adjustedForIme ? 1 : 0;
638 mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
Jorim Jaggiff71d202016-04-14 13:12:36 -0700639
Wale Ogunwale10124582016-09-15 20:25:50 -0700640 mDisplayContent.beginImeAdjustAnimation();
Jorim Jaggiff71d202016-04-14 13:12:36 -0700641
642 // We put all tasks into drag resizing mode - wait until all of them have completed the
643 // drag resizing switch.
644 if (!mService.mWaitingForDrawn.isEmpty()) {
645 mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
646 mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
647 IME_ADJUST_DRAWN_TIMEOUT);
648 mAnimationStartDelayed = true;
649 if (imeWin != null) {
650
651 // There might be an old window delaying the animation start - clear it.
652 if (mDelayedImeWin != null) {
653 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
654 }
655 mDelayedImeWin = imeWin;
656 imeWin.mWinAnimator.startDelayingAnimationStart();
657 }
658 mService.mWaitingForDrawnCallback = () -> {
659 mAnimationStartDelayed = false;
660 if (mDelayedImeWin != null) {
661 mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
662 }
Chong Zhang22eff0a2016-07-01 14:48:11 -0700663 // If the adjust status changed since this was posted, only notify
664 // the new states and don't animate.
665 long duration = 0;
666 if (mAdjustedForIme == adjustedForIme
667 && mAdjustedForDivider == adjustedForDivider) {
668 duration = IME_ADJUST_ANIM_DURATION;
669 } else {
670 Slog.w(TAG, "IME adjust changed while waiting for drawn:"
671 + " adjustedForIme=" + adjustedForIme
672 + " adjustedForDivider=" + adjustedForDivider
673 + " mAdjustedForIme=" + mAdjustedForIme
674 + " mAdjustedForDivider=" + mAdjustedForDivider);
675 }
Chong Zhangf347ab52016-04-18 21:02:01 -0700676 notifyAdjustedForImeChanged(
Chong Zhang22eff0a2016-07-01 14:48:11 -0700677 mAdjustedForIme || mAdjustedForDivider, duration);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700678 };
679 } else {
Chong Zhangf347ab52016-04-18 21:02:01 -0700680 notifyAdjustedForImeChanged(
681 adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
Jorim Jaggiff71d202016-04-14 13:12:36 -0700682 }
Jorim Jaggieb88d832016-04-13 20:17:43 -0700683 }
684
Chong Zhang22eff0a2016-07-01 14:48:11 -0700685 private boolean setMinimizedDockedStack(boolean minimized) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800686 final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
Jorim Jaggief92d6f2016-03-25 22:07:16 -0700687 notifyDockedStackMinimizedChanged(minimized, 0);
Chong Zhang22eff0a2016-07-01 14:48:11 -0700688 return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800689 }
690
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800691 private boolean isAnimationMaximizing() {
692 return mAnimationTarget == 0f;
693 }
694
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800695 public boolean animate(long now) {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700696 if (mWindow == null) {
697 return false;
698 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700699 if (mAnimatingForMinimizedDockedStack) {
700 return animateForMinimizedDockedStack(now);
701 } else if (mAnimatingForIme) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700702 return animateForIme(now);
Chong Zhangbaba7832016-03-24 10:21:26 -0700703 } else {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700704 if (mDimLayer != null && mDimLayer.isDimming()) {
Wale Ogunwalec69694a2016-10-18 13:51:15 -0700705 mDimLayer.setLayer(getResizeDimLayer());
Chong Zhang1402c2e2016-04-21 15:17:47 -0700706 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800707 return false;
708 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700709 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800710
Jorim Jaggieb88d832016-04-13 20:17:43 -0700711 private boolean animateForIme(long now) {
Jorim Jaggiff71d202016-04-14 13:12:36 -0700712 if (!mAnimationStarted || mAnimationStartDelayed) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700713 mAnimationStarted = true;
714 mAnimationStartTime = now;
715 mAnimationDuration = (long)
Jorim Jaggi698e7632016-04-13 21:02:22 -0700716 (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
Jorim Jaggieb88d832016-04-13 20:17:43 -0700717 }
718 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
719 t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
720 .getInterpolation(t);
Wale Ogunwale10124582016-09-15 20:25:50 -0700721 final boolean updated =
722 mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget);
Jorim Jaggieb88d832016-04-13 20:17:43 -0700723 if (updated) {
724 mService.mWindowPlacerLocked.performSurfacePlacement();
725 }
726 if (t >= 1.0f) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700727 mLastAnimationProgress = mAnimationTarget;
728 mLastDividerProgress = mDividerAnimationTarget;
Jorim Jaggieb88d832016-04-13 20:17:43 -0700729 mAnimatingForIme = false;
730 return false;
731 } else {
732 return true;
733 }
Chong Zhangbaba7832016-03-24 10:21:26 -0700734 }
735
736 private boolean animateForMinimizedDockedStack(long now) {
Jorim Jaggiaf558e12016-04-27 22:56:56 -0700737 final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800738 if (!mAnimationStarted) {
739 mAnimationStarted = true;
740 mAnimationStartTime = now;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800741 final long transitionDuration = isAnimationMaximizing()
742 ? mService.mAppTransition.getLastClipRevealTransitionDuration()
743 : DEFAULT_APP_TRANSITION_DURATION;
744 mAnimationDuration = (long)
745 (transitionDuration * mService.getTransitionAnimationScaleLocked());
Jorim Jaggif97ed922016-02-18 18:57:07 -0800746 mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800747 notifyDockedStackMinimizedChanged(mMinimizedDock,
Jorim Jaggif97ed922016-02-18 18:57:07 -0800748 (long) (mAnimationDuration * mMaximizeMeetFraction));
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800749 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800750 float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
751 t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
752 .getInterpolation(t);
Chong Zhang741c0ba2016-05-27 12:52:11 -0700753 if (stack != null) {
754 if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
755 mService.mWindowPlacerLocked.performSurfacePlacement();
756 }
757 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800758 if (t >= 1.0f) {
Chong Zhangbaba7832016-03-24 10:21:26 -0700759 mAnimatingForMinimizedDockedStack = false;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800760 return false;
761 } else {
762 return true;
763 }
764 }
765
Wale Ogunwale10124582016-09-15 20:25:50 -0700766 float getInterpolatedAnimationValue(float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700767 return t * mAnimationTarget + (1 - t) * mAnimationStart;
768 }
769
Wale Ogunwale10124582016-09-15 20:25:50 -0700770 float getInterpolatedDividerValue(float t) {
Chong Zhangf347ab52016-04-18 21:02:01 -0700771 return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
772 }
773
Jorim Jaggif97ed922016-02-18 18:57:07 -0800774 /**
775 * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
776 */
777 private float getMinimizeAmount(TaskStack stack, float t) {
Jorim Jaggieb88d832016-04-13 20:17:43 -0700778 final float naturalAmount = getInterpolatedAnimationValue(t);
Jorim Jaggif97ed922016-02-18 18:57:07 -0800779 if (isAnimationMaximizing()) {
780 return adjustMaximizeAmount(stack, t, naturalAmount);
781 } else {
782 return naturalAmount;
783 }
784 }
785
786 /**
787 * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
788 * during the transition such that the edge of the clip reveal rect is met earlier in the
789 * transition so we don't create a visible "hole", but only if both the clip reveal and the
790 * docked stack divider start from about the same portion on the screen.
791 */
792 private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
793 if (mMaximizeMeetFraction == 1f) {
794 return naturalAmount;
795 }
796 final int minimizeDistance = stack.getMinimizeDistance();
797 float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
798 / (float) minimizeDistance;
799 final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
800 final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
801 return amountPrime * t2 + naturalAmount * (1 - t2);
802 }
803
804 /**
805 * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
806 * edge. See {@link #adjustMaximizeAmount}.
807 */
808 private float getClipRevealMeetFraction(TaskStack stack) {
809 if (!isAnimationMaximizing() || stack == null ||
810 !mService.mAppTransition.hadClipRevealAnimation()) {
811 return 1f;
812 }
813 final int minimizeDistance = stack.getMinimizeDistance();
814 final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
815 / (float) minimizeDistance;
816 final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
817 / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
818 return CLIP_REVEAL_MEET_EARLIEST
819 + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
820 }
821
Jorim Jaggi50981592015-12-29 17:54:12 +0100822 @Override
Wale Ogunwale29bfbb82016-05-12 15:13:52 -0700823 public boolean dimFullscreen() {
Jorim Jaggi50981592015-12-29 17:54:12 +0100824 return false;
825 }
826
827 @Override
828 public DisplayInfo getDisplayInfo() {
829 return mDisplayContent.getDisplayInfo();
830 }
831
832 @Override
833 public void getDimBounds(Rect outBounds) {
834 // This dim layer user doesn't need this.
835 }
836
837 @Override
838 public String toShortString() {
839 return TAG;
840 }
Robert Carre63e01a2016-04-18 20:27:34 -0700841
842 WindowState getWindow() {
843 return mWindow;
844 }
Jorim Jaggi31f71702016-05-04 16:43:04 -0700845
846 void dump(String prefix, PrintWriter pw) {
847 pw.println(prefix + "DockedStackDividerController");
848 pw.println(prefix + " mLastVisibility=" + mLastVisibility);
849 pw.println(prefix + " mMinimizedDock=" + mMinimizedDock);
850 pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme);
851 pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider);
852 if (mDimLayer.isDimming()) {
853 pw.println(prefix + " Dim layer is dimming: ");
854 mDimLayer.printTo(prefix + " ", pw);
855 }
856 }
Robert Carre63e01a2016-04-18 20:27:34 -0700857}