blob: 758062f41428b3cbf4a578be761e4f116036fe80 [file] [log] [blame]
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001/*
2 * Copyright (C) 2018 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 android.view;
18
Yunfan Chenfae0aea2020-02-22 20:57:57 +090019import static android.view.InsetsState.ITYPE_CAPTION_BAR;
Tiger Huang332793b2019-10-29 23:21:27 +080020import static android.view.InsetsState.ITYPE_IME;
Jorim Jaggi33a21832020-04-06 14:15:46 +020021import static android.view.InsetsState.toInternalType;
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +010022import static android.view.InsetsState.toPublicType;
23import static android.view.WindowInsets.Type.all;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +010024import static android.view.WindowInsets.Type.ime;
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -080025
Jorim Jaggi6d5c8012020-02-28 01:40:27 +010026import android.animation.AnimationHandler;
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -080027import android.animation.Animator;
28import android.animation.AnimatorListenerAdapter;
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -080029import android.animation.TypeEvaluator;
Jorim Jaggi5875cca2020-03-17 13:44:57 +010030import android.animation.ValueAnimator;
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -080031import android.annotation.IntDef;
Jorim Jaggib6030952018-10-23 18:31:52 +020032import android.annotation.NonNull;
Jorim Jaggidd3304e2020-01-20 17:24:51 +010033import android.annotation.Nullable;
Jorim Jaggi02a741f2018-12-12 17:40:19 -080034import android.graphics.Insets;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020035import android.graphics.Rect;
Adrian Roos3406fb92020-02-10 18:38:59 -080036import android.os.CancellationSignal;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +010037import android.os.Handler;
Jorim Jaggicb28ae62020-05-14 17:46:32 +020038import android.os.Trace;
Jorim Jaggib6030952018-10-23 18:31:52 +020039import android.util.ArraySet;
Tarandeep Singh46d59f02019-01-29 18:09:15 -080040import android.util.Pair;
Jorim Jaggib6030952018-10-23 18:31:52 +020041import android.util.SparseArray;
Tarandeep Singh46d59f02019-01-29 18:09:15 -080042import android.view.InsetsSourceConsumer.ShowResult;
Tiger Huang332793b2019-10-29 23:21:27 +080043import android.view.InsetsState.InternalInsetsType;
Jorim Jaggib6030952018-10-23 18:31:52 +020044import android.view.SurfaceControl.Transaction;
Tarandeep Singh46d59f02019-01-29 18:09:15 -080045import android.view.WindowInsets.Type;
Tiger Huang332793b2019-10-29 23:21:27 +080046import android.view.WindowInsets.Type.InsetsType;
Adrian Roosdb5b0c22020-02-12 15:05:27 -080047import android.view.WindowInsetsAnimation.Bounds;
Jorim Jaggi4e04eb22020-01-09 16:42:14 +010048import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
Jorim Jaggi79742592019-01-18 17:36:10 +010049import android.view.animation.Interpolator;
Jorim Jaggi5875cca2020-03-17 13:44:57 +010050import android.view.animation.LinearInterpolator;
Jorim Jaggi79742592019-01-18 17:36:10 +010051import android.view.animation.PathInterpolator;
Jorim Jaggibf87c152020-04-22 17:18:25 +020052import android.view.inputmethod.InputMethodManager;
Jorim Jaggib6030952018-10-23 18:31:52 +020053
54import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggi6d5c8012020-02-28 01:40:27 +010055import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020056
57import java.io.PrintWriter;
Jorim Jaggia51168a2019-12-27 15:17:44 +010058import java.lang.annotation.Retention;
59import java.lang.annotation.RetentionPolicy;
Jorim Jaggi5bb571d2018-11-06 14:42:04 +010060import java.util.ArrayList;
Adrian Roosdb5b0c22020-02-12 15:05:27 -080061import java.util.Collections;
62import java.util.List;
Jorim Jaggied35b172020-03-06 00:13:57 +010063import java.util.Objects;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +010064import java.util.function.BiFunction;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020065
66/**
67 * Implements {@link WindowInsetsController} on the client.
Jorim Jaggib6030952018-10-23 18:31:52 +020068 * @hide
Jorim Jaggif96c90a2018-09-26 16:55:15 +020069 */
Yunfan Chen02abf552019-12-05 14:51:09 +090070public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks {
Jorim Jaggif96c90a2018-09-26 16:55:15 +020071
Jorim Jaggibf87c152020-04-22 17:18:25 +020072 public interface Host {
73
74 Handler getHandler();
75
76 /**
77 * Notifies host that {@link InsetsController#getState()} has changed.
78 */
79 void notifyInsetsChanged();
80
81 void dispatchWindowInsetsAnimationPrepare(@NonNull WindowInsetsAnimation animation);
82 Bounds dispatchWindowInsetsAnimationStart(
83 @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds);
84 WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets,
85 @NonNull List<WindowInsetsAnimation> runningAnimations);
86 void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation);
87
88 /**
89 * Requests host to apply surface params in synchronized manner.
90 */
91 void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params);
92
93 /**
94 * @see ViewRootImpl#updateCompatSysUiVisibility(int, boolean, boolean)
95 */
96 void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible,
97 boolean hasControl);
98
99 /**
100 * Called when insets have been modified by the client and should be reported back to WM.
101 */
102 void onInsetsModified(InsetsState insetsState);
103
104 /**
105 * @return Whether the host has any callbacks it wants to synchronize the animations with.
106 * If there are no callbacks, the animation will be off-loaded to another thread and
107 * slightly different animation curves are picked.
108 */
109 boolean hasAnimationCallbacks();
110
111 /**
112 * @see WindowInsetsController#setSystemBarsAppearance
113 */
114 void setSystemBarsAppearance(@Appearance int appearance, @Appearance int mask);
115
116 /**
117 * @see WindowInsetsController#getSystemBarsAppearance()
118 */
119 @Appearance int getSystemBarsAppearance();
120
121 /**
122 * @see WindowInsetsController#setSystemBarsBehavior
123 */
124 void setSystemBarsBehavior(@Behavior int behavior);
125
126 /**
127 * @see WindowInsetsController#getSystemBarsBehavior
128 */
129 @Behavior int getSystemBarsBehavior();
130
131 /**
132 * Releases a surface and ensure that this is done after {@link #applySurfaceParams} has
133 * finished applying params.
134 */
135 void releaseSurfaceControlFromRt(SurfaceControl surfaceControl);
136
137 /**
138 * If this host is a view hierarchy, adds a pre-draw runnable to ensure proper ordering as
139 * described in {@link WindowInsetsAnimation.Callback#onPrepare}.
140 *
141 * If this host isn't a view hierarchy, the runnable can be executed immediately.
142 */
143 void addOnPreDrawRunnable(Runnable r);
144
145 /**
146 * Adds a runnbale to be executed during {@link Choreographer#CALLBACK_INSETS_ANIMATION}
147 * phase.
148 */
149 void postInsetsAnimationCallback(Runnable r);
150
151 /**
152 * Obtains {@link InputMethodManager} instance from host.
153 */
154 InputMethodManager getInputMethodManager();
155 }
156
Jorim Jaggi79742592019-01-18 17:36:10 +0100157 private static final int ANIMATION_DURATION_SHOW_MS = 275;
158 private static final int ANIMATION_DURATION_HIDE_MS = 340;
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100159
160 private static final int ANIMATION_DURATION_SYNC_IME_MS = 285;
161 private static final int ANIMATION_DURATION_UNSYNC_IME_MS = 200;
162
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100163 private static final int PENDING_CONTROL_TIMEOUT_MS = 2000;
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800164
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100165 public static final Interpolator SYSTEM_BARS_INTERPOLATOR =
166 new PathInterpolator(0.4f, 0f, 0.2f, 1f);
167 private static final Interpolator SYNC_IME_INTERPOLATOR =
168 new PathInterpolator(0.2f, 0f, 0f, 1f);
169 private static final Interpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR =
170 new PathInterpolator(0, 0, 0.2f, 1f);
171 private static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR =
172 new PathInterpolator(0.4f, 0f, 1f, 1f);
Tarandeep Singh54554e22019-11-01 14:43:05 -0700173
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -0800174 /**
Jorim Jaggia51168a2019-12-27 15:17:44 +0100175 * Layout mode during insets animation: The views should be laid out as if the changing inset
176 * types are fully shown. Before starting the animation, {@link View#onApplyWindowInsets} will
177 * be called as if the changing insets types are shown, which will result in the views being
178 * laid out as if the insets are fully shown.
179 */
Yunfan Chenb5d2db72019-12-06 15:43:43 +0900180 public static final int LAYOUT_INSETS_DURING_ANIMATION_SHOWN = 0;
Jorim Jaggia51168a2019-12-27 15:17:44 +0100181
182 /**
183 * Layout mode during insets animation: The views should be laid out as if the changing inset
184 * types are fully hidden. Before starting the animation, {@link View#onApplyWindowInsets} will
185 * be called as if the changing insets types are hidden, which will result in the views being
186 * laid out as if the insets are fully hidden.
187 */
Yunfan Chenb5d2db72019-12-06 15:43:43 +0900188 public static final int LAYOUT_INSETS_DURING_ANIMATION_HIDDEN = 1;
Jorim Jaggia51168a2019-12-27 15:17:44 +0100189
190 /**
191 * Determines the behavior of how the views should be laid out during an insets animation that
192 * is controlled by the application by calling {@link #controlWindowInsetsAnimation}.
193 * <p>
194 * When the animation is system-initiated, the layout mode is always chosen such that the
195 * pre-animation layout will represent the opposite of the starting state, i.e. when insets
196 * are appearing, {@link #LAYOUT_INSETS_DURING_ANIMATION_SHOWN} will be used. When insets
197 * are disappearing, {@link #LAYOUT_INSETS_DURING_ANIMATION_HIDDEN} will be used.
198 */
199 @Retention(RetentionPolicy.SOURCE)
200 @IntDef(value = {LAYOUT_INSETS_DURING_ANIMATION_SHOWN,
201 LAYOUT_INSETS_DURING_ANIMATION_HIDDEN})
202 @interface LayoutInsetsDuringAnimation {
203 }
204
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100205 /** Not running an animation. */
206 @VisibleForTesting
207 public static final int ANIMATION_TYPE_NONE = -1;
208
209 /** Running animation will show insets */
210 @VisibleForTesting
211 public static final int ANIMATION_TYPE_SHOW = 0;
212
213 /** Running animation will hide insets */
214 @VisibleForTesting
215 public static final int ANIMATION_TYPE_HIDE = 1;
216
217 /** Running animation is controlled by user via {@link #controlWindowInsetsAnimation} */
218 @VisibleForTesting
219 public static final int ANIMATION_TYPE_USER = 2;
220
221 @Retention(RetentionPolicy.SOURCE)
222 @IntDef(value = {ANIMATION_TYPE_NONE, ANIMATION_TYPE_SHOW, ANIMATION_TYPE_HIDE,
223 ANIMATION_TYPE_USER})
224 @interface AnimationType {
225 }
226
Jorim Jaggia51168a2019-12-27 15:17:44 +0100227 /**
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -0800228 * Translation animation evaluator.
229 */
230 private static TypeEvaluator<Insets> sEvaluator = (fraction, startValue, endValue) -> Insets.of(
Jorim Jaggi956ca412019-01-07 14:49:14 +0100231 (int) (startValue.left + fraction * (endValue.left - startValue.left)),
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -0800232 (int) (startValue.top + fraction * (endValue.top - startValue.top)),
Jorim Jaggi956ca412019-01-07 14:49:14 +0100233 (int) (startValue.right + fraction * (endValue.right - startValue.right)),
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -0800234 (int) (startValue.bottom + fraction * (endValue.bottom - startValue.bottom)));
235
236 /**
Yunfan Chen4523d5d2020-01-16 16:54:00 +0900237 * The default implementation of listener, to be used by InsetsController and InsetsPolicy to
238 * animate insets.
239 */
240 public static class InternalAnimationControlListener
241 implements WindowInsetsAnimationControlListener {
Tarandeep Singh54554e22019-11-01 14:43:05 -0700242
243 private WindowInsetsAnimationController mController;
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100244 private ValueAnimator mAnimator;
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100245 private final boolean mShow;
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100246 private final boolean mHasAnimationCallbacks;
247 private final @InsetsType int mRequestedTypes;
248 private final long mDurationMs;
Tarandeep Singh54554e22019-11-01 14:43:05 -0700249
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100250 private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
251 new ThreadLocal<AnimationHandler>() {
252 @Override
253 protected AnimationHandler initialValue() {
254 AnimationHandler handler = new AnimationHandler();
255 handler.setProvider(new SfVsyncFrameCallbackProvider());
256 return handler;
257 }
258 };
259
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100260 public InternalAnimationControlListener(boolean show, boolean hasAnimationCallbacks,
261 int requestedTypes) {
Tarandeep Singh54554e22019-11-01 14:43:05 -0700262 mShow = show;
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100263 mHasAnimationCallbacks = hasAnimationCallbacks;
264 mRequestedTypes = requestedTypes;
265 mDurationMs = calculateDurationMs();
Tarandeep Singh54554e22019-11-01 14:43:05 -0700266 }
267
268 @Override
269 public void onReady(WindowInsetsAnimationController controller, int types) {
270 mController = controller;
Jorim Jaggia51168a2019-12-27 15:17:44 +0100271
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100272 mAnimator = ValueAnimator.ofFloat(0f, 1f);
273 mAnimator.setDuration(mDurationMs);
274 mAnimator.setInterpolator(new LinearInterpolator());
275 Insets start = mShow
276 ? controller.getHiddenStateInsets()
277 : controller.getShownStateInsets();
278 Insets end = mShow
279 ? controller.getShownStateInsets()
280 : controller.getHiddenStateInsets();
281 Interpolator insetsInterpolator = getInterpolator();
282 Interpolator alphaInterpolator = getAlphaInterpolator();
283 mAnimator.addUpdateListener(animation -> {
284 float rawFraction = animation.getAnimatedFraction();
285 float alphaFraction = mShow
286 ? rawFraction
287 : 1 - rawFraction;
288 float insetsFraction = insetsInterpolator.getInterpolation(rawFraction);
289 controller.setInsetsAndAlpha(
290 sEvaluator.evaluate(insetsFraction, start, end),
291 alphaInterpolator.getInterpolation(alphaFraction),
292 rawFraction);
293 });
Tarandeep Singh54554e22019-11-01 14:43:05 -0700294 mAnimator.addListener(new AnimatorListenerAdapter() {
295
296 @Override
297 public void onAnimationEnd(Animator animation) {
298 onAnimationFinish();
299 }
300 });
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100301 if (!mHasAnimationCallbacks) {
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100302 mAnimator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get());
303 }
Tarandeep Singh54554e22019-11-01 14:43:05 -0700304 mAnimator.start();
305 }
306
307 @Override
Adrian Roos5d557ed2020-03-17 20:04:35 +0100308 public void onFinished(WindowInsetsAnimationController controller) {
309 }
310
311 @Override
312 public void onCancelled(WindowInsetsAnimationController controller) {
Tarandeep Singh54554e22019-11-01 14:43:05 -0700313 // Animator can be null when it is cancelled before onReady() completes.
314 if (mAnimator != null) {
315 mAnimator.cancel();
316 }
317 }
318
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100319 Interpolator getInterpolator() {
320 if ((mRequestedTypes & ime()) != 0) {
321 if (mHasAnimationCallbacks) {
322 return SYNC_IME_INTERPOLATOR;
323 } else if (mShow) {
324 return LINEAR_OUT_SLOW_IN_INTERPOLATOR;
325 } else {
326 return FAST_OUT_LINEAR_IN_INTERPOLATOR;
327 }
328 } else {
329 return SYSTEM_BARS_INTERPOLATOR;
330 }
Tarandeep Singh54554e22019-11-01 14:43:05 -0700331 }
332
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100333 Interpolator getAlphaInterpolator() {
334 if ((mRequestedTypes & ime()) != 0) {
335 if (mHasAnimationCallbacks) {
336 return input -> 1f;
337 } else if (mShow) {
338
339 // Alpha animation takes half the time with linear interpolation;
340 return input -> Math.min(1f, 2 * input);
341 } else {
342 return FAST_OUT_LINEAR_IN_INTERPOLATOR;
343 }
344 } else {
345 return input -> 1f;
346 }
347 }
348
349 protected void onAnimationFinish() {
350 mController.finish(mShow);
Tarandeep Singh54554e22019-11-01 14:43:05 -0700351 }
352
Yunfan Chenb5d2db72019-12-06 15:43:43 +0900353 /**
354 * To get the animation duration in MS.
355 */
356 public long getDurationMs() {
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100357 return mDurationMs;
358 }
359
360 private long calculateDurationMs() {
361 if ((mRequestedTypes & ime()) != 0) {
362 if (mHasAnimationCallbacks) {
363 return ANIMATION_DURATION_SYNC_IME_MS;
364 } else {
365 return ANIMATION_DURATION_UNSYNC_IME_MS;
366 }
367 } else {
368 return mShow ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS;
Tarandeep Singh54554e22019-11-01 14:43:05 -0700369 }
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -0800370 }
371 }
372
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100373 /**
374 * Represents a running animation
375 */
376 private static class RunningAnimation {
377
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100378 RunningAnimation(InsetsAnimationControlRunner runner, int type) {
379 this.runner = runner;
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100380 this.type = type;
381 }
382
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100383 final InsetsAnimationControlRunner runner;
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100384 final @AnimationType int type;
Jorim Jaggi580aef52020-02-26 18:28:28 +0100385
386 /**
387 * Whether {@link WindowInsetsAnimation.Callback#onStart(WindowInsetsAnimation, Bounds)} has
388 * been dispatched already for this animation.
389 */
390 boolean startDispatched;
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100391 }
392
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100393 /**
394 * Represents a control request that we had to defer because we are waiting for the IME to
395 * process our show request.
396 */
397 private static class PendingControlRequest {
398
399 PendingControlRequest(@InsetsType int types, WindowInsetsAnimationControlListener listener,
400 long durationMs, Interpolator interpolator, @AnimationType int animationType,
Adrian Roos3406fb92020-02-10 18:38:59 -0800401 @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100402 CancellationSignal cancellationSignal, boolean useInsetsAnimationThread) {
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100403 this.types = types;
404 this.listener = listener;
405 this.durationMs = durationMs;
406 this.interpolator = interpolator;
407 this.animationType = animationType;
408 this.layoutInsetsDuringAnimation = layoutInsetsDuringAnimation;
Adrian Roos3406fb92020-02-10 18:38:59 -0800409 this.cancellationSignal = cancellationSignal;
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100410 this.useInsetsAnimationThread = useInsetsAnimationThread;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100411 }
412
413 final @InsetsType int types;
414 final WindowInsetsAnimationControlListener listener;
415 final long durationMs;
416 final Interpolator interpolator;
417 final @AnimationType int animationType;
418 final @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation;
Adrian Roos3406fb92020-02-10 18:38:59 -0800419 final CancellationSignal cancellationSignal;
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100420 final boolean useInsetsAnimationThread;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100421 }
Yunfan Chen4523d5d2020-01-16 16:54:00 +0900422
Jorim Jaggie35c0592018-11-06 16:21:08 +0100423 private final String TAG = "InsetsControllerImpl";
424
Tiger Huang173480f2020-04-29 01:05:42 +0800425 /** The local state */
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200426 private final InsetsState mState = new InsetsState();
Tiger Huang173480f2020-04-29 01:05:42 +0800427
428 /** The state dispatched from server */
429 private final InsetsState mLastDispatchedState = new InsetsState();
430
431 /** The state sent to server */
432 private final InsetsState mRequestedState = new InsetsState();
Jorim Jaggie35c0592018-11-06 16:21:08 +0100433
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200434 private final Rect mFrame = new Rect();
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100435 private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator;
Jorim Jaggib6030952018-10-23 18:31:52 +0200436 private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>();
Jorim Jaggibf87c152020-04-22 17:18:25 +0200437 private final Host mHost;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100438 private final Handler mHandler;
Jorim Jaggib6030952018-10-23 18:31:52 +0200439
440 private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100441 private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>();
Jorim Jaggi580aef52020-02-26 18:28:28 +0100442 private final ArrayList<WindowInsetsAnimation> mTmpRunningAnims = new ArrayList<>();
443 private final List<WindowInsetsAnimation> mUnmodifiableTmpRunningAnims =
444 Collections.unmodifiableList(mTmpRunningAnims);
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100445 private final ArrayList<InsetsAnimationControlImpl> mTmpFinishedControls = new ArrayList<>();
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800446 private WindowInsets mLastInsets;
447
448 private boolean mAnimCallbackScheduled;
449
450 private final Runnable mAnimCallback;
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200451
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100452 /** Pending control request that is waiting on IME to be ready to be shown */
453 private PendingControlRequest mPendingImeControlRequest;
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800454
Jorim Jaggi648e5882019-01-24 13:24:02 +0100455 private int mLastLegacySoftInputMode;
Jorim Jaggi7f761872020-01-10 18:24:27 +0100456 private int mLastLegacySystemUiFlags;
Jorim Jaggi580aef52020-02-26 18:28:28 +0100457 private DisplayCutout mLastDisplayCutout;
Jorim Jaggia51168a2019-12-27 15:17:44 +0100458 private boolean mStartingAnimation;
Yunfan Chenfae0aea2020-02-22 20:57:57 +0900459 private int mCaptionInsetsHeight = 0;
Jorim Jaggi648e5882019-01-24 13:24:02 +0100460
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100461 private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
Jorim Jaggied35b172020-03-06 00:13:57 +0100462 private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
463 = new ArrayList<>();
464
465 /** Set of inset types for which an animation was started since last resetting this field */
466 private @InsetsType int mLastStartedAnimTypes;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100467
Jorim Jaggibf87c152020-04-22 17:18:25 +0200468 public InsetsController(Host host) {
469 this(host, (controller, type) -> {
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100470 if (type == ITYPE_IME) {
471 return new ImeInsetsSourceConsumer(controller.mState, Transaction::new, controller);
472 } else {
473 return new InsetsSourceConsumer(type, controller.mState, Transaction::new,
474 controller);
475 }
Jorim Jaggibf87c152020-04-22 17:18:25 +0200476 }, host.getHandler());
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100477 }
478
479 @VisibleForTesting
Jorim Jaggibf87c152020-04-22 17:18:25 +0200480 public InsetsController(Host host,
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100481 BiFunction<InsetsController, Integer, InsetsSourceConsumer> consumerCreator,
482 Handler handler) {
Jorim Jaggibf87c152020-04-22 17:18:25 +0200483 mHost = host;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100484 mConsumerCreator = consumerCreator;
485 mHandler = handler;
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800486 mAnimCallback = () -> {
487 mAnimCallbackScheduled = false;
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100488 if (mRunningAnimations.isEmpty()) {
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800489 return;
490 }
491
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100492 mTmpFinishedControls.clear();
Jorim Jaggi580aef52020-02-26 18:28:28 +0100493 mTmpRunningAnims.clear();
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800494 InsetsState state = new InsetsState(mState, true /* copySources */);
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100495 for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
Jorim Jaggi580aef52020-02-26 18:28:28 +0100496 RunningAnimation runningAnimation = mRunningAnimations.get(i);
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100497 InsetsAnimationControlRunner runner = runningAnimation.runner;
498 if (runner instanceof InsetsAnimationControlImpl) {
499 InsetsAnimationControlImpl control = (InsetsAnimationControlImpl) runner;
Jorim Jaggi580aef52020-02-26 18:28:28 +0100500
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100501 // Keep track of running animation to be dispatched. Aggregate it here such that
502 // if it gets finished within applyChangeInsets we still dispatch it to
503 // onProgress.
504 if (runningAnimation.startDispatched) {
505 mTmpRunningAnims.add(control.getAnimation());
506 }
507
508 if (control.applyChangeInsets(state)) {
509 mTmpFinishedControls.add(control);
510 }
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100511 }
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800512 }
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100513
Jorim Jaggi580aef52020-02-26 18:28:28 +0100514 WindowInsets insets = state.calculateInsets(mFrame, mState /* ignoringVisibilityState*/,
515 mLastInsets.isRound(), mLastInsets.shouldAlwaysConsumeSystemBars(),
Jorim Jaggi22488d32020-03-19 01:12:44 +0100516 mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacySystemUiFlags,
517 null /* typeSideMap */);
Jorim Jaggibf87c152020-04-22 17:18:25 +0200518 mHost.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims);
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100519
520 for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) {
Adrian Roosdb5b0c22020-02-12 15:05:27 -0800521 dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation());
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100522 }
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800523 };
Jorim Jaggic8d60382018-10-31 17:06:06 +0100524 }
525
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100526 @VisibleForTesting
527 public void onFrameChanged(Rect frame) {
Tarandeep Singha6f35612019-01-11 19:50:46 -0800528 if (mFrame.equals(frame)) {
529 return;
530 }
Jorim Jaggibf87c152020-04-22 17:18:25 +0200531 mHost.notifyInsetsChanged();
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200532 mFrame.set(frame);
533 }
534
Tiger Huang4a7835f2019-11-06 00:07:56 +0800535 @Override
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200536 public InsetsState getState() {
537 return mState;
538 }
539
Jorim Jaggi49b9f6c2020-03-24 22:28:38 +0100540 @Override
541 public boolean isRequestedVisible(int type) {
542 return getSourceConsumer(type).isRequestedVisible();
543 }
544
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100545 public InsetsState getLastDispatchedState() {
Tiger Huang173480f2020-04-29 01:05:42 +0800546 return mLastDispatchedState;
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100547 }
548
549 @VisibleForTesting
550 public boolean onStateChanged(InsetsState state) {
Yunfan Chenfae0aea2020-02-22 20:57:57 +0900551 boolean localStateChanged = !mState.equals(state, true /* excludingCaptionInsets */)
552 || !captionInsetsUnchanged();
Tiger Huang173480f2020-04-29 01:05:42 +0800553 if (!localStateChanged && mLastDispatchedState.equals(state)) {
Jorim Jaggic8d60382018-10-31 17:06:06 +0100554 return false;
555 }
Jorim Jaggi33a21832020-04-06 14:15:46 +0200556 updateState(state);
Tiger Huang173480f2020-04-29 01:05:42 +0800557 mLastDispatchedState.set(state, true /* copySources */);
Jorim Jaggic8d60382018-10-31 17:06:06 +0100558 applyLocalVisibilityOverride();
Jorim Jaggi22488d32020-03-19 01:12:44 +0100559 if (localStateChanged) {
Jorim Jaggibf87c152020-04-22 17:18:25 +0200560 mHost.notifyInsetsChanged();
Jorim Jaggi22488d32020-03-19 01:12:44 +0100561 }
Tiger Huang173480f2020-04-29 01:05:42 +0800562 if (!mState.equals(mLastDispatchedState, true /* excludingCaptionInsets */)) {
563 updateRequestedState();
Jorim Jaggie35c0592018-11-06 16:21:08 +0100564 }
Jorim Jaggi33a21832020-04-06 14:15:46 +0200565 return true;
566 }
567
568 private void updateState(InsetsState newState) {
569 mState.setDisplayFrame(newState.getDisplayFrame());
570 for (int i = newState.getSourcesCount() - 1; i >= 0; i--) {
571 InsetsSource source = newState.sourceAt(i);
572 getSourceConsumer(source.getType()).updateSource(source);
573 }
574 for (int i = mState.getSourcesCount() - 1; i >= 0; i--) {
575 InsetsSource source = mState.sourceAt(i);
576 if (newState.peekSource(source.getType()) == null) {
577 mState.removeSource(source.getType());
578 }
579 }
Yunfan Chenfae0aea2020-02-22 20:57:57 +0900580 if (mCaptionInsetsHeight != 0) {
581 mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(mFrame.left, mFrame.top,
582 mFrame.right, mFrame.top + mCaptionInsetsHeight));
583 }
584 }
585
586 private boolean captionInsetsUnchanged() {
587 if (mState.peekSource(ITYPE_CAPTION_BAR) == null
588 && mCaptionInsetsHeight == 0) {
589 return true;
590 }
591 if (mState.peekSource(ITYPE_CAPTION_BAR) != null
592 && mCaptionInsetsHeight
593 == mState.peekSource(ITYPE_CAPTION_BAR).getFrame().height()) {
594 return true;
595 }
596 return false;
Jorim Jaggi2751c292020-03-20 23:46:38 +0100597 }
598
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200599 /**
600 * @see InsetsState#calculateInsets
601 */
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100602 @VisibleForTesting
603 public WindowInsets calculateInsets(boolean isScreenRound,
Jorim Jaggi22488d32020-03-19 01:12:44 +0100604 boolean alwaysConsumeSystemBars, DisplayCutout cutout,
605 int legacySoftInputMode, int legacySystemUiFlags) {
Jorim Jaggi648e5882019-01-24 13:24:02 +0100606 mLastLegacySoftInputMode = legacySoftInputMode;
Jorim Jaggi7f761872020-01-10 18:24:27 +0100607 mLastLegacySystemUiFlags = legacySystemUiFlags;
Jorim Jaggi580aef52020-02-26 18:28:28 +0100608 mLastDisplayCutout = cutout;
609 mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState*/,
Jorim Jaggi22488d32020-03-19 01:12:44 +0100610 isScreenRound, alwaysConsumeSystemBars, cutout,
611 legacySoftInputMode, legacySystemUiFlags,
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100612 null /* typeSideMap */);
Jorim Jaggi02a741f2018-12-12 17:40:19 -0800613 return mLastInsets;
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200614 }
615
Jorim Jaggib6030952018-10-23 18:31:52 +0200616 /**
Jorim Jaggi22488d32020-03-19 01:12:44 +0100617 * @see InsetsState#calculateVisibleInsets(Rect, int)
Jorim Jaggi4e04eb22020-01-09 16:42:14 +0100618 */
Jorim Jaggi22488d32020-03-19 01:12:44 +0100619 public Rect calculateVisibleInsets(@SoftInputModeFlags int softInputMode) {
620 return mState.calculateVisibleInsets(mFrame, softInputMode);
Jorim Jaggi4e04eb22020-01-09 16:42:14 +0100621 }
622
623 /**
Jorim Jaggib6030952018-10-23 18:31:52 +0200624 * Called when the server has dispatched us a new set of inset controls.
625 */
626 public void onControlsChanged(InsetsSourceControl[] activeControls) {
627 if (activeControls != null) {
628 for (InsetsSourceControl activeControl : activeControls) {
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -0800629 if (activeControl != null) {
630 // TODO(b/122982984): Figure out why it can be null.
631 mTmpControlArray.put(activeControl.getType(), activeControl);
632 }
Jorim Jaggib6030952018-10-23 18:31:52 +0200633 }
634 }
635
Tiger Huang173480f2020-04-29 01:05:42 +0800636 final boolean hasControl = mTmpControlArray.size() > 0;
637 final int[] showTypes = new int[1];
638 final int[] hideTypes = new int[1];
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100639
Jorim Jaggib6030952018-10-23 18:31:52 +0200640 // Ensure to update all existing source consumers
641 for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
642 final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
643 final InsetsSourceControl control = mTmpControlArray.get(consumer.getType());
644
645 // control may be null, but we still need to update the control to null if it got
646 // revoked.
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100647 consumer.setControl(control, showTypes, hideTypes);
Jorim Jaggib6030952018-10-23 18:31:52 +0200648 }
649
650 // Ensure to create source consumers if not available yet.
651 for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
652 final InsetsSourceControl control = mTmpControlArray.valueAt(i);
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100653 InsetsSourceConsumer consumer = getSourceConsumer(control.getType());
654 consumer.setControl(control, showTypes, hideTypes);
655
Jorim Jaggib6030952018-10-23 18:31:52 +0200656 }
657 mTmpControlArray.clear();
Jorim Jaggied35b172020-03-06 00:13:57 +0100658
659 // Do not override any animations that the app started in the OnControllableInsetsChanged
660 // listeners.
661 int animatingTypes = invokeControllableInsetsChangedListeners();
662 showTypes[0] &= ~animatingTypes;
663 hideTypes[0] &= ~animatingTypes;
664
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100665 if (showTypes[0] != 0) {
666 applyAnimation(showTypes[0], true /* show */, false /* fromIme */);
667 }
668 if (hideTypes[0] != 0) {
669 applyAnimation(hideTypes[0], false /* show */, false /* fromIme */);
670 }
Tiger Huangfbfc3ab2020-05-06 01:02:31 +0800671 if (hasControl && mRequestedState.getSourcesCount() > 0) {
Tiger Huang173480f2020-04-29 01:05:42 +0800672 // We might have changed our requested visibilities while we don't have the control,
673 // so we need to update our requested state once we have control. Otherwise, our
674 // requested state at the server side might be incorrect.
675 updateRequestedState();
676 }
Jorim Jaggib6030952018-10-23 18:31:52 +0200677 }
678
679 @Override
Tiger Huang332793b2019-10-29 23:21:27 +0800680 public void show(@InsetsType int types) {
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800681 show(types, false /* fromIme */);
682 }
683
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100684 @VisibleForTesting
685 public void show(@InsetsType int types, boolean fromIme) {
686
687 // Handle pending request ready in case there was one set.
688 if (fromIme && mPendingImeControlRequest != null) {
689 PendingControlRequest pendingRequest = mPendingImeControlRequest;
690 mPendingImeControlRequest = null;
691 mHandler.removeCallbacks(mPendingControlTimeout);
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000692 controlAnimationUnchecked(
693 pendingRequest.types, pendingRequest.cancellationSignal,
Adrian Roos3406fb92020-02-10 18:38:59 -0800694 pendingRequest.listener, mFrame,
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100695 true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator,
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100696 pendingRequest.animationType,
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100697 pendingRequest.layoutInsetsDuringAnimation,
698 pendingRequest.useInsetsAnimationThread);
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100699 return;
700 }
701
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800702 // TODO: Support a ResultReceiver for IME.
703 // TODO(b/123718661): Make show() work for multi-session IME.
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -0800704 int typesReady = 0;
Jorim Jaggib6030952018-10-23 18:31:52 +0200705 final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
706 for (int i = internalTypes.size() - 1; i >= 0; i--) {
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100707 @InternalInsetsType int internalType = internalTypes.valueAt(i);
708 @AnimationType int animationType = getAnimationType(internalType);
709 InsetsSourceConsumer consumer = getSourceConsumer(internalType);
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100710 if (consumer.isRequestedVisible() && animationType == ANIMATION_TYPE_NONE
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100711 || animationType == ANIMATION_TYPE_SHOW) {
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800712 // no-op: already shown or animating in (because window visibility is
713 // applied before starting animation).
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -0800714 continue;
715 }
716 typesReady |= InsetsState.toPublicType(consumer.getType());
Jorim Jaggib6030952018-10-23 18:31:52 +0200717 }
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800718 applyAnimation(typesReady, true /* show */, fromIme);
Jorim Jaggib6030952018-10-23 18:31:52 +0200719 }
720
721 @Override
Tiger Huang332793b2019-10-29 23:21:27 +0800722 public void hide(@InsetsType int types) {
Taran Singhd7fc5862019-10-10 14:45:17 +0200723 hide(types, false /* fromIme */);
724 }
725
Tiger Huang332793b2019-10-29 23:21:27 +0800726 void hide(@InsetsType int types, boolean fromIme) {
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -0800727 int typesReady = 0;
Jorim Jaggib6030952018-10-23 18:31:52 +0200728 final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
729 for (int i = internalTypes.size() - 1; i >= 0; i--) {
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100730 @InternalInsetsType int internalType = internalTypes.valueAt(i);
731 @AnimationType int animationType = getAnimationType(internalType);
732 InsetsSourceConsumer consumer = getSourceConsumer(internalType);
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100733 if (!consumer.isRequestedVisible() && animationType == ANIMATION_TYPE_NONE
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100734 || animationType == ANIMATION_TYPE_HIDE) {
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -0800735 // no-op: already hidden or animating out.
736 continue;
737 }
738 typesReady |= InsetsState.toPublicType(consumer.getType());
Jorim Jaggib6030952018-10-23 18:31:52 +0200739 }
Taran Singhd7fc5862019-10-10 14:45:17 +0200740 applyAnimation(typesReady, false /* show */, fromIme /* fromIme */);
Jorim Jaggib6030952018-10-23 18:31:52 +0200741 }
742
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100743 @Override
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000744 public void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
Jorim Jaggidd3304e2020-01-20 17:24:51 +0100745 @Nullable Interpolator interpolator,
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000746 @Nullable CancellationSignal cancellationSignal,
Jorim Jaggidd3304e2020-01-20 17:24:51 +0100747 @NonNull WindowInsetsAnimationControlListener listener) {
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000748 controlWindowInsetsAnimation(types, cancellationSignal, listener,
749 false /* fromIme */, durationMillis, interpolator, ANIMATION_TYPE_USER);
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800750 }
751
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000752 private void controlWindowInsetsAnimation(@InsetsType int types,
753 @Nullable CancellationSignal cancellationSignal,
754 WindowInsetsAnimationControlListener listener,
755 boolean fromIme, long durationMs, @Nullable Interpolator interpolator,
756 @AnimationType int animationType) {
Jorim Jaggied35b172020-03-06 00:13:57 +0100757 if (!checkDisplayFramesForControlling()) {
Adrian Roos5d557ed2020-03-17 20:04:35 +0100758 listener.onCancelled(null);
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000759 return;
Tarandeep Singha6f35612019-01-11 19:50:46 -0800760 }
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100761
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000762 controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100763 interpolator, animationType, getLayoutInsetsDuringAnimationMode(types),
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100764 false /* useInsetsAnimationThread */);
Tarandeep Singha6f35612019-01-11 19:50:46 -0800765 }
766
Jorim Jaggied35b172020-03-06 00:13:57 +0100767 private boolean checkDisplayFramesForControlling() {
768
769 // If the frame of our window doesn't span the entire display, the control API makes very
770 // little sense, as we don't deal with negative insets. So just cancel immediately.
771 return mState.getDisplayFrame().equals(mFrame);
772 }
773
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000774 private void controlAnimationUnchecked(@InsetsType int types,
775 @Nullable CancellationSignal cancellationSignal,
Tarandeep Singh54554e22019-11-01 14:43:05 -0700776 WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100777 long durationMs, Interpolator interpolator,
Jorim Jaggidd3304e2020-01-20 17:24:51 +0100778 @AnimationType int animationType,
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100779 @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
780 boolean useInsetsAnimationThread) {
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800781 if (types == 0) {
782 // nothing to animate.
Adrian Roos5d557ed2020-03-17 20:04:35 +0100783 listener.onCancelled(null);
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000784 return;
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800785 }
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100786 cancelExistingControllers(types);
Jorim Jaggied35b172020-03-06 00:13:57 +0100787 mLastStartedAnimTypes |= types;
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100788
Tiger Huang969c6082019-12-24 20:08:57 +0800789 final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
Yunfan Chen02abf552019-12-05 14:51:09 +0900790 final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800791
Yunfan Chen02abf552019-12-05 14:51:09 +0900792 Pair<Integer, Boolean> typesReadyPair = collectSourceControls(
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100793 fromIme, internalTypes, controls, animationType);
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800794 int typesReady = typesReadyPair.first;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100795 boolean imeReady = typesReadyPair.second;
796 if (!imeReady) {
797 // IME isn't ready, all requested types will be animated once IME is ready
798 abortPendingImeControlRequest();
Adrian Roos3406fb92020-02-10 18:38:59 -0800799 final PendingControlRequest request = new PendingControlRequest(types,
800 listener, durationMs,
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100801 interpolator, animationType, layoutInsetsDuringAnimation, cancellationSignal,
802 useInsetsAnimationThread);
Adrian Roos3406fb92020-02-10 18:38:59 -0800803 mPendingImeControlRequest = request;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100804 mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS);
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000805 if (cancellationSignal != null) {
806 cancellationSignal.setOnCancelListener(() -> {
807 if (mPendingImeControlRequest == request) {
808 abortPendingImeControlRequest();
809 }
810 });
811 }
812 return;
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800813 }
814
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800815 if (typesReady == 0) {
Adrian Roos5d557ed2020-03-17 20:04:35 +0100816 listener.onCancelled(null);
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000817 return;
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800818 }
819
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100820
821 final InsetsAnimationControlRunner runner = useInsetsAnimationThread
822 ? new InsetsAnimationThreadControlRunner(controls,
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100823 frame, mState, listener, typesReady, this, durationMs, interpolator,
Jorim Jaggibf87c152020-04-22 17:18:25 +0200824 animationType, mHost.getHandler())
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100825 : new InsetsAnimationControlImpl(controls,
Jorim Jaggi5875cca2020-03-17 13:44:57 +0100826 frame, mState, listener, typesReady, this, durationMs, interpolator,
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100827 animationType);
828 mRunningAnimations.add(new RunningAnimation(runner, animationType));
Adrian Roos5ad8cd22020-03-12 18:30:54 +0000829 if (cancellationSignal != null) {
830 cancellationSignal.setOnCancelListener(runner::cancel);
831 }
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100832 if (layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
833 showDirectly(types);
834 } else {
835 hideDirectly(types, false /* animationFinished */, animationType);
836 }
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800837 }
838
839 /**
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100840 * @return Pair of (types ready to animate, IME ready to animate).
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800841 */
Yunfan Chen02abf552019-12-05 14:51:09 +0900842 private Pair<Integer, Boolean> collectSourceControls(boolean fromIme,
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100843 ArraySet<Integer> internalTypes, SparseArray<InsetsSourceControl> controls,
844 @AnimationType int animationType) {
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800845 int typesReady = 0;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100846 boolean imeReady = true;
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100847 for (int i = internalTypes.size() - 1; i >= 0; i--) {
Tarandeep Singhb9538cd2020-02-20 17:51:18 -0800848 final InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100849 boolean show = animationType == ANIMATION_TYPE_SHOW
850 || animationType == ANIMATION_TYPE_USER;
851 boolean canRun = false;
852 if (show) {
Taran Singhd7fc5862019-10-10 14:45:17 +0200853 // Show request
854 switch(consumer.requestShow(fromIme)) {
855 case ShowResult.SHOW_IMMEDIATELY:
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100856 canRun = true;
Taran Singhd7fc5862019-10-10 14:45:17 +0200857 break;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100858 case ShowResult.IME_SHOW_DELAYED:
859 imeReady = false;
Taran Singhd7fc5862019-10-10 14:45:17 +0200860 break;
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100861 case ShowResult.IME_SHOW_FAILED:
Taran Singhd7fc5862019-10-10 14:45:17 +0200862 // IME cannot be shown (since it didn't have focus), proceed
863 // with animation of other types.
Taran Singhd7fc5862019-10-10 14:45:17 +0200864 break;
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800865 }
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100866 } else {
Taran Singhd7fc5862019-10-10 14:45:17 +0200867 // Hide request
868 // TODO: Move notifyHidden() to beginning of the hide animation
869 // (when visibility actually changes using hideDirectly()).
870 if (!fromIme) {
871 consumer.notifyHidden();
872 }
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100873 canRun = true;
874 }
875 if (!canRun) {
876 continue;
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100877 }
Tiger Huang969c6082019-12-24 20:08:57 +0800878 final InsetsSourceControl control = consumer.getControl();
879 if (control != null) {
Rob Carr3a367c42020-03-10 15:51:35 -0700880 controls.put(consumer.getType(), new InsetsSourceControl(control));
Jorim Jaggi3182ef12020-01-30 00:16:18 +0100881 typesReady |= toPublicType(consumer.getType());
882 } else if (animationType == ANIMATION_TYPE_SHOW) {
883
884 // We don't have a control at the moment. However, we still want to update requested
885 // visibility state such that in case we get control, we can apply show animation.
886 consumer.show(fromIme);
887 } else if (animationType == ANIMATION_TYPE_HIDE) {
888 consumer.hide();
Tiger Huang969c6082019-12-24 20:08:57 +0800889 }
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100890 }
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100891 return new Pair<>(typesReady, imeReady);
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100892 }
893
Jorim Jaggia51168a2019-12-27 15:17:44 +0100894 private @LayoutInsetsDuringAnimation int getLayoutInsetsDuringAnimationMode(
895 @InsetsType int types) {
896
897 final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
898
899 // Generally, we want to layout the opposite of the current state. This is to make animation
900 // callbacks easy to use: The can capture the layout values and then treat that as end-state
901 // during the animation.
902 //
903 // However, if controlling multiple sources, we want to treat it as shown if any of the
904 // types is currently hidden.
905 for (int i = internalTypes.size() - 1; i >= 0; i--) {
906 InsetsSourceConsumer consumer = mSourceConsumers.get(internalTypes.valueAt(i));
907 if (consumer == null) {
908 continue;
909 }
910 if (!consumer.isRequestedVisible()) {
911 return LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
912 }
913 }
914 return LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
915 }
916
Tiger Huang332793b2019-10-29 23:21:27 +0800917 private void cancelExistingControllers(@InsetsType int types) {
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100918 for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100919 InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100920 if ((control.getTypes() & types) != 0) {
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100921 cancelAnimation(control, true /* invokeCallback */);
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100922 }
923 }
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100924 if ((types & ime()) != 0) {
925 abortPendingImeControlRequest();
926 }
927 }
928
929 private void abortPendingImeControlRequest() {
930 if (mPendingImeControlRequest != null) {
Adrian Roos5d557ed2020-03-17 20:04:35 +0100931 mPendingImeControlRequest.listener.onCancelled(null);
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100932 mPendingImeControlRequest = null;
933 mHandler.removeCallbacks(mPendingControlTimeout);
934 }
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100935 }
936
937 @VisibleForTesting
Yunfan Chen02abf552019-12-05 14:51:09 +0900938 @Override
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100939 public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
940 cancelAnimation(runner, false /* invokeCallback */);
Tarandeep Singh54554e22019-11-01 14:43:05 -0700941 if (shown) {
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100942 showDirectly(runner.getTypes());
Tarandeep Singh54554e22019-11-01 14:43:05 -0700943 } else {
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100944 hideDirectly(runner.getTypes(), true /* animationFinished */,
945 runner.getAnimationType());
Tarandeep Singh54554e22019-11-01 14:43:05 -0700946 }
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100947 }
948
Yunfan Chen02abf552019-12-05 14:51:09 +0900949 @Override
950 public void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
Jorim Jaggibf87c152020-04-22 17:18:25 +0200951 mHost.applySurfaceParams(params);
Yunfan Chen02abf552019-12-05 14:51:09 +0900952 }
953
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100954 void notifyControlRevoked(InsetsSourceConsumer consumer) {
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100955 for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100956 InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100957 if ((control.getTypes() & toPublicType(consumer.getType())) != 0) {
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100958 cancelAnimation(control, true /* invokeCallback */);
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100959 }
960 }
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100961 if (consumer.getType() == ITYPE_IME) {
962 abortPendingImeControlRequest();
963 }
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100964 }
965
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100966 private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100967 if (invokeCallback) {
Jorim Jaggi6d5c8012020-02-28 01:40:27 +0100968 control.cancel();
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100969 }
970 for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
Jorim Jaggi33a21832020-04-06 14:15:46 +0200971 RunningAnimation runningAnimation = mRunningAnimations.get(i);
972 if (runningAnimation.runner == control) {
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100973 mRunningAnimations.remove(i);
Jorim Jaggi33a21832020-04-06 14:15:46 +0200974 ArraySet<Integer> types = toInternalType(control.getTypes());
975 for (int j = types.size() - 1; j >= 0; j--) {
976 if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) {
Jorim Jaggibf87c152020-04-22 17:18:25 +0200977 mHost.notifyInsetsChanged();
Jorim Jaggi33a21832020-04-06 14:15:46 +0200978 }
979 }
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +0100980 break;
981 }
982 }
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +0100983 }
984
Jorim Jaggic8d60382018-10-31 17:06:06 +0100985 private void applyLocalVisibilityOverride() {
986 for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
987 final InsetsSourceConsumer controller = mSourceConsumers.valueAt(i);
988 controller.applyLocalVisibilityOverride();
989 }
990 }
991
Jorim Jaggib6030952018-10-23 18:31:52 +0200992 @VisibleForTesting
Tiger Huang332793b2019-10-29 23:21:27 +0800993 public @NonNull InsetsSourceConsumer getSourceConsumer(@InternalInsetsType int type) {
Jorim Jaggib6030952018-10-23 18:31:52 +0200994 InsetsSourceConsumer controller = mSourceConsumers.get(type);
995 if (controller != null) {
996 return controller;
997 }
Jorim Jaggid7f10ed2020-01-08 21:41:55 +0100998 controller = mConsumerCreator.apply(this, type);
Jorim Jaggib6030952018-10-23 18:31:52 +0200999 mSourceConsumers.put(type, controller);
1000 return controller;
1001 }
1002
Jorim Jaggi5bb571d2018-11-06 14:42:04 +01001003 @VisibleForTesting
1004 public void notifyVisibilityChanged() {
Jorim Jaggibf87c152020-04-22 17:18:25 +02001005 mHost.notifyInsetsChanged();
Tiger Huang173480f2020-04-29 01:05:42 +08001006 updateRequestedState();
Jorim Jaggie35c0592018-11-06 16:21:08 +01001007 }
1008
1009 /**
Tiger Huang41ae5e82020-01-17 18:17:20 +08001010 * @see ViewRootImpl#updateCompatSysUiVisibility(int, boolean, boolean)
1011 */
1012 public void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible,
1013 boolean hasControl) {
Jorim Jaggibf87c152020-04-22 17:18:25 +02001014 mHost.updateCompatSysUiVisibility(type, visible, hasControl);
Tiger Huang41ae5e82020-01-17 18:17:20 +08001015 }
1016
1017 /**
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08001018 * Called when current window gains focus.
1019 */
1020 public void onWindowFocusGained() {
Tiger Huang332793b2019-10-29 23:21:27 +08001021 getSourceConsumer(ITYPE_IME).onWindowFocusGained();
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08001022 }
1023
1024 /**
1025 * Called when current window loses focus.
1026 */
1027 public void onWindowFocusLost() {
Tiger Huang332793b2019-10-29 23:21:27 +08001028 getSourceConsumer(ITYPE_IME).onWindowFocusLost();
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08001029 }
1030
Tarandeep Singh46d59f02019-01-29 18:09:15 -08001031 /**
1032 * Used by {@link ImeInsetsSourceConsumer} when IME decides to be shown/hidden.
1033 * @hide
1034 */
1035 @VisibleForTesting
1036 public void applyImeVisibility(boolean setVisible) {
1037 if (setVisible) {
1038 show(Type.IME, true /* fromIme */);
1039 } else {
1040 hide(Type.IME);
1041 }
1042 }
1043
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +01001044 @VisibleForTesting
1045 public @AnimationType int getAnimationType(@InternalInsetsType int type) {
1046 for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
Jorim Jaggi6d5c8012020-02-28 01:40:27 +01001047 InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
Jorim Jaggi1f2c7eb2020-01-08 00:07:13 +01001048 if (control.controlsInternalType(type)) {
1049 return mRunningAnimations.get(i).type;
1050 }
1051 }
1052 return ANIMATION_TYPE_NONE;
Tarandeep Singh93ea15a2019-11-26 11:09:14 -08001053 }
1054
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08001055 /**
Tiger Huang173480f2020-04-29 01:05:42 +08001056 * Sends the local visibility state back to window manager if it is changed.
Jorim Jaggie35c0592018-11-06 16:21:08 +01001057 */
Tiger Huang173480f2020-04-29 01:05:42 +08001058 private void updateRequestedState() {
1059 boolean changed = false;
Jorim Jaggie35c0592018-11-06 16:21:08 +01001060 for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
1061 final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
Tiger Huang173480f2020-04-29 01:05:42 +08001062 final @InternalInsetsType int type = consumer.getType();
1063 if (type == ITYPE_CAPTION_BAR) {
1064 continue;
1065 }
Jorim Jaggie35c0592018-11-06 16:21:08 +01001066 if (consumer.getControl() != null) {
Tiger Huang173480f2020-04-29 01:05:42 +08001067 final InsetsSource localSource = mState.getSource(type);
1068 if (!localSource.equals(mRequestedState.peekSource(type))) {
Tiger Huangfbfc3ab2020-05-06 01:02:31 +08001069 // Our requested state is stale. Update it here and send it to window manager.
Tiger Huang173480f2020-04-29 01:05:42 +08001070 mRequestedState.addSource(new InsetsSource(localSource));
1071 changed = true;
1072 }
Tiger Huangfbfc3ab2020-05-06 01:02:31 +08001073 if (!localSource.equals(mLastDispatchedState.peekSource(type))) {
1074 // The server state is not what we expected. This can happen while we don't have
1075 // the control. Since we have the control now, we need to send our request again
1076 // to modify the server state.
1077 changed = true;
1078 }
Jorim Jaggie35c0592018-11-06 16:21:08 +01001079 }
1080 }
Tiger Huang173480f2020-04-29 01:05:42 +08001081 if (!changed) {
1082 return;
1083 }
1084 mHost.onInsetsModified(mRequestedState);
Jorim Jaggic8d60382018-10-31 17:06:06 +01001085 }
1086
Taran Singh8321a2a42020-04-21 17:26:50 -07001087 @VisibleForTesting
1088 public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme) {
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -08001089 if (types == 0) {
1090 // nothing to animate.
1091 return;
1092 }
Tarandeep Singha6f35612019-01-11 19:50:46 -08001093
Jorim Jaggibf87c152020-04-22 17:18:25 +02001094 boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
Adrian Roosbbf42402020-01-28 18:23:39 +01001095 final InternalAnimationControlListener listener =
Jorim Jaggi5875cca2020-03-17 13:44:57 +01001096 new InternalAnimationControlListener(show, hasAnimationCallbacks, types);
1097
Tarandeep Singha6f35612019-01-11 19:50:46 -08001098 // Show/hide animations always need to be relative to the display frame, in order that shown
1099 // and hidden state insets are correct.
Tarandeep Singh54554e22019-11-01 14:43:05 -07001100 controlAnimationUnchecked(
Adrian Roos5ad8cd22020-03-12 18:30:54 +00001101 types, null /* cancellationSignal */, listener, mState.getDisplayFrame(), fromIme,
Jorim Jaggi5875cca2020-03-17 13:44:57 +01001102 listener.getDurationMs(), listener.getInterpolator(),
1103 show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
1104 show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
1105 !hasAnimationCallbacks /* useInsetsAnimationThread */);
1106
Jorim Jaggi6d5c8012020-02-28 01:40:27 +01001107 }
1108
Tarandeep Singhb9538cd2020-02-20 17:51:18 -08001109 private void hideDirectly(
1110 @InsetsType int types, boolean animationFinished, @AnimationType int animationType) {
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -08001111 final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
1112 for (int i = internalTypes.size() - 1; i >= 0; i--) {
Tarandeep Singhb9538cd2020-02-20 17:51:18 -08001113 getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType);
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -08001114 }
1115 }
1116
Tiger Huang332793b2019-10-29 23:21:27 +08001117 private void showDirectly(@InsetsType int types) {
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -08001118 final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
1119 for (int i = internalTypes.size() - 1; i >= 0; i--) {
Jorim Jaggi3182ef12020-01-30 00:16:18 +01001120 getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */);
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -08001121 }
1122 }
1123
1124 /**
Tiger Huang332793b2019-10-29 23:21:27 +08001125 * Cancel on-going animation to show/hide {@link InsetsType}.
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -08001126 */
1127 @VisibleForTesting
Jorim Jaggi31e52542020-05-04 23:23:25 +02001128 public void cancelExistingAnimations() {
Jorim Jaggi5ed50cc2019-01-23 16:59:42 +01001129 cancelExistingControllers(all());
Tarandeep Singh22f2b4c2019-01-10 19:41:30 -08001130 }
1131
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001132 void dump(String prefix, PrintWriter pw) {
1133 pw.println(prefix); pw.println("InsetsController:");
1134 mState.dump(prefix + " ", pw);
1135 }
Jorim Jaggi02a741f2018-12-12 17:40:19 -08001136
Jorim Jaggifae3e272019-01-14 14:05:05 +01001137 @VisibleForTesting
Yunfan Chen02abf552019-12-05 14:51:09 +09001138 @Override
Jorim Jaggia51168a2019-12-27 15:17:44 +01001139 public void startAnimation(InsetsAnimationControlImpl controller,
Adrian Roosdb5b0c22020-02-12 15:05:27 -08001140 WindowInsetsAnimationControlListener listener, int types,
Jorim Jaggi6d5c8012020-02-28 01:40:27 +01001141 WindowInsetsAnimation animation, Bounds bounds) {
Jorim Jaggibf87c152020-04-22 17:18:25 +02001142 mHost.dispatchWindowInsetsAnimationPrepare(animation);
1143 mHost.addOnPreDrawRunnable(() -> {
1144 if (controller.isCancelled()) {
1145 return;
Jorim Jaggia51168a2019-12-27 15:17:44 +01001146 }
Jorim Jaggicb28ae62020-05-14 17:46:32 +02001147 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW,
1148 "InsetsAnimation: " + WindowInsets.Type.toString(types), types);
Jorim Jaggibf87c152020-04-22 17:18:25 +02001149 for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
1150 RunningAnimation runningAnimation = mRunningAnimations.get(i);
1151 if (runningAnimation.runner == controller) {
1152 runningAnimation.startDispatched = true;
1153 }
1154 }
1155 mHost.dispatchWindowInsetsAnimationStart(animation, bounds);
1156 mStartingAnimation = true;
1157 controller.mReadyDispatched = true;
1158 listener.onReady(controller, types);
1159 mStartingAnimation = false;
Jorim Jaggia51168a2019-12-27 15:17:44 +01001160 });
Jorim Jaggi02a741f2018-12-12 17:40:19 -08001161 }
1162
Jorim Jaggifae3e272019-01-14 14:05:05 +01001163 @VisibleForTesting
Adrian Roosdb5b0c22020-02-12 15:05:27 -08001164 public void dispatchAnimationEnd(WindowInsetsAnimation animation) {
Jorim Jaggicb28ae62020-05-14 17:46:32 +02001165 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW,
1166 "InsetsAnimation: " + WindowInsets.Type.toString(animation.getTypeMask()),
1167 animation.getTypeMask());
Jorim Jaggibf87c152020-04-22 17:18:25 +02001168 mHost.dispatchWindowInsetsAnimationEnd(animation);
Jorim Jaggi02a741f2018-12-12 17:40:19 -08001169 }
1170
Jorim Jaggifae3e272019-01-14 14:05:05 +01001171 @VisibleForTesting
Yunfan Chen02abf552019-12-05 14:51:09 +09001172 @Override
Adrian Roos6a4448f2020-04-01 15:01:08 +02001173 public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) {
1174 if (mStartingAnimation || runner.getAnimationType() == ANIMATION_TYPE_USER) {
Jorim Jaggia51168a2019-12-27 15:17:44 +01001175 mAnimCallback.run();
1176 mAnimCallbackScheduled = false;
1177 return;
1178 }
Jorim Jaggi02a741f2018-12-12 17:40:19 -08001179 if (!mAnimCallbackScheduled) {
Jorim Jaggibf87c152020-04-22 17:18:25 +02001180 mHost.postInsetsAnimationCallback(mAnimCallback);
Jorim Jaggi02a741f2018-12-12 17:40:19 -08001181 mAnimCallbackScheduled = true;
1182 }
1183 }
Jorim Jaggib7848b72018-12-28 14:38:21 +01001184
1185 @Override
Tiger Huang7238a052020-01-10 20:37:01 +08001186 public void setSystemBarsAppearance(@Appearance int appearance, @Appearance int mask) {
Jorim Jaggibf87c152020-04-22 17:18:25 +02001187 mHost.setSystemBarsAppearance(appearance, mask);
Jorim Jaggib7848b72018-12-28 14:38:21 +01001188 }
1189
1190 @Override
Tiger Huang7238a052020-01-10 20:37:01 +08001191 public @Appearance int getSystemBarsAppearance() {
Jorim Jaggibf87c152020-04-22 17:18:25 +02001192 return mHost.getSystemBarsAppearance();
Tiger Huang7238a052020-01-10 20:37:01 +08001193 }
1194
1195 @Override
Yunfan Chenfae0aea2020-02-22 20:57:57 +09001196 public void setCaptionInsetsHeight(int height) {
1197 mCaptionInsetsHeight = height;
1198 }
1199
1200 @Override
Jorim Jaggib7848b72018-12-28 14:38:21 +01001201 public void setSystemBarsBehavior(@Behavior int behavior) {
Jorim Jaggibf87c152020-04-22 17:18:25 +02001202 mHost.setSystemBarsBehavior(behavior);
Jorim Jaggib7848b72018-12-28 14:38:21 +01001203 }
Tiger Huang7238a052020-01-10 20:37:01 +08001204
1205 @Override
1206 public @Appearance int getSystemBarsBehavior() {
Jorim Jaggibf87c152020-04-22 17:18:25 +02001207 return mHost.getSystemBarsBehavior();
Tiger Huang7238a052020-01-10 20:37:01 +08001208 }
Rob Carr521e3632020-03-09 11:22:30 -07001209
Jorim Jaggied35b172020-03-06 00:13:57 +01001210 private @InsetsType int calculateControllableTypes() {
1211 if (!checkDisplayFramesForControlling()) {
1212 return 0;
1213 }
1214 @InsetsType int result = 0;
1215 for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
1216 InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
1217 if (consumer.getControl() != null) {
1218 result |= toPublicType(consumer.mType);
1219 }
1220 }
1221 return result;
1222 }
1223
1224 /**
1225 * @return The types that are now animating due to a listener invoking control/show/hide
1226 */
1227 private @InsetsType int invokeControllableInsetsChangedListeners() {
1228 mLastStartedAnimTypes = 0;
1229 @InsetsType int types = calculateControllableTypes();
1230 int size = mControllableInsetsChangedListeners.size();
1231 for (int i = 0; i < size; i++) {
1232 mControllableInsetsChangedListeners.get(i).onControllableInsetsChanged(this, types);
1233 }
1234 return mLastStartedAnimTypes;
1235 }
1236
1237 @Override
1238 public void addOnControllableInsetsChangedListener(
1239 OnControllableInsetsChangedListener listener) {
1240 Objects.requireNonNull(listener);
1241 mControllableInsetsChangedListeners.add(listener);
1242 listener.onControllableInsetsChanged(this, calculateControllableTypes());
1243 }
1244
1245 @Override
1246 public void removeOnControllableInsetsChangedListener(
1247 OnControllableInsetsChangedListener listener) {
1248 Objects.requireNonNull(listener);
1249 mControllableInsetsChangedListeners.remove(listener);
1250 }
1251
Jorim Jaggibf87c152020-04-22 17:18:25 +02001252 @Override
Rob Carr521e3632020-03-09 11:22:30 -07001253 public void releaseSurfaceControlFromRt(SurfaceControl sc) {
Jorim Jaggibf87c152020-04-22 17:18:25 +02001254 mHost.releaseSurfaceControlFromRt(sc);
1255 }
1256
1257 Host getHost() {
1258 return mHost;
Rob Carr521e3632020-03-09 11:22:30 -07001259 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001260}