• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 
17 package com.android.server.wm;
18 
19 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
20 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
23 import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
24 import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
25 import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
26 import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
27 import static android.view.InsetsState.ITYPE_IME;
28 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
29 import static android.view.InsetsState.ITYPE_STATUS_BAR;
30 import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
31 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
32 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
33 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
34 
35 import android.annotation.NonNull;
36 import android.annotation.Nullable;
37 import android.app.StatusBarManager;
38 import android.util.IntArray;
39 import android.util.SparseArray;
40 import android.view.InsetsAnimationControlCallbacks;
41 import android.view.InsetsAnimationControlImpl;
42 import android.view.InsetsAnimationControlRunner;
43 import android.view.InsetsController;
44 import android.view.InsetsSource;
45 import android.view.InsetsSourceControl;
46 import android.view.InsetsState;
47 import android.view.InsetsState.InternalInsetsType;
48 import android.view.SurfaceControl;
49 import android.view.SyncRtSurfaceTransactionApplier;
50 import android.view.WindowInsetsAnimation;
51 import android.view.WindowInsetsAnimation.Bounds;
52 import android.view.WindowInsetsAnimationControlListener;
53 import android.view.WindowManager;
54 
55 import com.android.internal.R;
56 import com.android.internal.annotations.VisibleForTesting;
57 import com.android.server.DisplayThread;
58 
59 /**
60  * Policy that implements who gets control over the windows generating insets.
61  */
62 class InsetsPolicy {
63 
64     private final InsetsStateController mStateController;
65     private final DisplayContent mDisplayContent;
66     private final DisplayPolicy mPolicy;
67     private final IntArray mShowingTransientTypes = new IntArray();
68 
69     /** For resetting visibilities of insets sources. */
70     private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() {
71 
72         @Override
73         public void notifyInsetsControlChanged() {
74             boolean hasLeash = false;
75             final InsetsSourceControl[] controls =
76                     mStateController.getControlsForDispatch(this);
77             if (controls == null) {
78                 return;
79             }
80             for (InsetsSourceControl control : controls) {
81                 final @InternalInsetsType int type = control.getType();
82                 if (mShowingTransientTypes.indexOf(type) != -1) {
83                     // The visibilities of transient bars will be handled with animations.
84                     continue;
85                 }
86                 final SurfaceControl leash = control.getLeash();
87                 if (leash != null) {
88                     hasLeash = true;
89 
90                     // We use alpha to control the visibility here which aligns the logic at
91                     // SurfaceAnimator.createAnimationLeash
92                     mDisplayContent.getPendingTransaction().setAlpha(
93                             leash, InsetsState.getDefaultVisibility(type) ? 1f : 0f);
94                 }
95             }
96             if (hasLeash) {
97                 mDisplayContent.scheduleAnimation();
98             }
99         }
100     };
101 
102     private WindowState mFocusedWin;
103     private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
104     private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
105     private boolean mAnimatingShown;
106     /**
107      * Let remote insets controller control system bars regardless of other settings.
108      */
109     private boolean mRemoteInsetsControllerControlsSystemBars;
110     private final float[] mTmpFloat9 = new float[9];
111 
InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent)112     InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
113         mStateController = stateController;
114         mDisplayContent = displayContent;
115         mPolicy = displayContent.getDisplayPolicy();
116         mRemoteInsetsControllerControlsSystemBars = mPolicy.getContext().getResources().getBoolean(
117                 R.bool.config_remoteInsetsControllerControlsSystemBars);
118     }
119 
getRemoteInsetsControllerControlsSystemBars()120     boolean getRemoteInsetsControllerControlsSystemBars() {
121         return mRemoteInsetsControllerControlsSystemBars;
122     }
123 
124     /**
125      * Used only for testing.
126      */
127     @VisibleForTesting
setRemoteInsetsControllerControlsSystemBars(boolean controlsSystemBars)128     void setRemoteInsetsControllerControlsSystemBars(boolean controlsSystemBars) {
129         mRemoteInsetsControllerControlsSystemBars = controlsSystemBars;
130     }
131 
132     /** Updates the target which can control system bars. */
updateBarControlTarget(@ullable WindowState focusedWin)133     void updateBarControlTarget(@Nullable WindowState focusedWin) {
134         if (mFocusedWin != focusedWin){
135             abortTransient();
136         }
137         mFocusedWin = focusedWin;
138         boolean forceShowsSystemBarsForWindowingMode = forceShowsSystemBarsForWindowingMode();
139         InsetsControlTarget statusControlTarget = getStatusControlTarget(focusedWin,
140                 forceShowsSystemBarsForWindowingMode);
141         InsetsControlTarget navControlTarget = getNavControlTarget(focusedWin,
142                 forceShowsSystemBarsForWindowingMode);
143         mStateController.onBarControlTargetChanged(statusControlTarget,
144                 getFakeControlTarget(focusedWin, statusControlTarget),
145                 navControlTarget,
146                 getFakeControlTarget(focusedWin, navControlTarget));
147         mStatusBar.updateVisibility(statusControlTarget, ITYPE_STATUS_BAR);
148         mNavBar.updateVisibility(navControlTarget, ITYPE_NAVIGATION_BAR);
149     }
150 
isHidden(@nternalInsetsType int type)151     boolean isHidden(@InternalInsetsType int type) {
152         final InsetsSourceProvider provider =  mStateController.peekSourceProvider(type);
153         return provider != null && provider.hasWindow() && !provider.getSource().isVisible();
154     }
155 
showTransient(@nternalInsetsType int[] types)156     void showTransient(@InternalInsetsType int[] types) {
157         boolean changed = false;
158         for (int i = types.length - 1; i >= 0; i--) {
159             final @InternalInsetsType int type = types[i];
160             if (!isHidden(type)) {
161                 continue;
162             }
163             if (mShowingTransientTypes.indexOf(type) != -1) {
164                 continue;
165             }
166             mShowingTransientTypes.add(type);
167             changed = true;
168         }
169         if (changed) {
170             mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(),
171                     mShowingTransientTypes.toArray());
172             updateBarControlTarget(mFocusedWin);
173 
174             // The leashes can be created while updating bar control target. The surface transaction
175             // of the new leashes might not be applied yet. The callback posted here ensures we can
176             // get the valid leashes because the surface transaction will be applied in the next
177             // animation frame which will be triggered if a new leash is created.
178             mDisplayContent.mWmService.mAnimator.getChoreographer().postFrameCallback(time -> {
179                 synchronized (mDisplayContent.mWmService.mGlobalLock) {
180                     startAnimation(true /* show */, null /* callback */);
181                 }
182             });
183         }
184     }
185 
hideTransient()186     void hideTransient() {
187         if (mShowingTransientTypes.size() == 0) {
188             return;
189         }
190         startAnimation(false /* show */, () -> {
191             synchronized (mDisplayContent.mWmService.mGlobalLock) {
192                 for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
193                     // We are about to clear mShowingTransientTypes, we don't want the transient bar
194                     // can cause insets on the client. Restore the client visibility.
195                     final @InternalInsetsType int type = mShowingTransientTypes.get(i);
196                     mStateController.getSourceProvider(type).setClientVisible(false);
197                 }
198                 mShowingTransientTypes.clear();
199                 updateBarControlTarget(mFocusedWin);
200             }
201         });
202     }
203 
isTransient(@nternalInsetsType int type)204     boolean isTransient(@InternalInsetsType int type) {
205         return mShowingTransientTypes.indexOf(type) != -1;
206     }
207 
208     /**
209      * @see InsetsStateController#getInsetsForWindow
210      */
getInsetsForWindow(WindowState target)211     InsetsState getInsetsForWindow(WindowState target) {
212         final InsetsState originalState = mStateController.getInsetsForWindow(target);
213         final InsetsState state = adjustVisibilityForTransientTypes(originalState);
214         return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state;
215     }
216 
217     /**
218      * @see InsetsStateController#getInsetsForWindowMetrics
219      */
getInsetsForWindowMetrics(@onNull WindowManager.LayoutParams attrs)220     InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
221         final InsetsState originalState = mStateController.getInsetsForWindowMetrics(attrs);
222         return adjustVisibilityForTransientTypes(originalState);
223     }
224 
adjustVisibilityForTransientTypes(InsetsState originalState)225     private InsetsState adjustVisibilityForTransientTypes(InsetsState originalState) {
226         InsetsState state = originalState;
227         for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
228             final @InternalInsetsType int type = mShowingTransientTypes.get(i);
229             final InsetsSource originalSource = state.peekSource(type);
230             if (originalSource != null && originalSource.isVisible()) {
231                 if (state == originalState) {
232                     // The source will be modified, create a non-deep copy to store the new one.
233                     state = new InsetsState(originalState);
234                 }
235                 // Replace the source with a copy in invisible state.
236                 final InsetsSource source = new InsetsSource(originalSource);
237                 source.setVisible(false);
238                 state.addSource(source);
239             }
240         }
241         return state;
242     }
243 
244     // Navigation bar insets is always visible to IME.
adjustVisibilityForIme(InsetsState originalState, boolean copyState)245     private static InsetsState adjustVisibilityForIme(InsetsState originalState,
246             boolean copyState) {
247         final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
248         if (originalNavSource != null && !originalNavSource.isVisible()) {
249             final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
250             final InsetsSource navSource = new InsetsSource(originalNavSource);
251             navSource.setVisible(true);
252             state.addSource(navSource);
253             return state;
254         }
255         return originalState;
256     }
257 
onInsetsModified(InsetsControlTarget caller)258     void onInsetsModified(InsetsControlTarget caller) {
259         mStateController.onInsetsModified(caller);
260         checkAbortTransient(caller);
261         updateBarControlTarget(mFocusedWin);
262     }
263 
264     /**
265      * Called when a control target modified the insets state. If the target set a insets source to
266      * visible while it is shown transiently, we need to abort the transient state. While IME is
267      * requested visible, we also need to abort the transient state of navigation bar if it is shown
268      * transiently.
269      *
270      * @param caller who changed the insets state.
271      */
checkAbortTransient(InsetsControlTarget caller)272     private void checkAbortTransient(InsetsControlTarget caller) {
273         if (mShowingTransientTypes.size() != 0) {
274             final IntArray abortTypes = new IntArray();
275             final boolean imeRequestedVisible = caller.getRequestedVisibility(ITYPE_IME);
276             for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
277                 final @InternalInsetsType int type = mShowingTransientTypes.get(i);
278                 if ((mStateController.isFakeTarget(type, caller)
279                                 && caller.getRequestedVisibility(type))
280                         || (type == ITYPE_NAVIGATION_BAR && imeRequestedVisible)) {
281                     mShowingTransientTypes.remove(i);
282                     abortTypes.add(type);
283                 }
284             }
285             if (abortTypes.size() > 0) {
286                 mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(),
287                         abortTypes.toArray());
288             }
289         }
290     }
291 
292     /**
293      * If the caller is not {@link #updateBarControlTarget}, it should call
294      * updateBarControlTarget(mFocusedWin) after this invocation.
295      */
abortTransient()296     private void abortTransient() {
297         mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(),
298                 mShowingTransientTypes.toArray());
299         mShowingTransientTypes.clear();
300     }
301 
getFakeControlTarget(@ullable WindowState focused, InsetsControlTarget realControlTarget)302     private @Nullable InsetsControlTarget getFakeControlTarget(@Nullable WindowState focused,
303             InsetsControlTarget realControlTarget) {
304         return realControlTarget == mDummyControlTarget ? focused : null;
305     }
306 
getStatusControlTarget(@ullable WindowState focusedWin, boolean forceShowsSystemBarsForWindowingMode)307     private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
308             boolean forceShowsSystemBarsForWindowingMode) {
309         if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
310             return mDummyControlTarget;
311         }
312         final WindowState notificationShade = mPolicy.getNotificationShade();
313         if (focusedWin == notificationShade) {
314             // Notification shade has control anyways, no reason to force anything.
315             return focusedWin;
316         }
317         if (remoteInsetsControllerControlsSystemBars(focusedWin)) {
318             mDisplayContent.mRemoteInsetsControlTarget.topFocusedWindowChanged(
319                     focusedWin.mAttrs.packageName);
320             return mDisplayContent.mRemoteInsetsControlTarget;
321         }
322         if (forceShowsSystemBarsForWindowingMode) {
323             // Status bar is forcibly shown for the windowing mode which is a steady state.
324             // We don't want the client to control the status bar, and we will dispatch the real
325             // visibility of status bar to the client.
326             return null;
327         }
328         if (forceShowsStatusBarTransiently()) {
329             // Status bar is forcibly shown transiently, and its new visibility won't be
330             // dispatched to the client so that we can keep the layout stable. We will dispatch the
331             // fake control to the client, so that it can re-show the bar during this scenario.
332             return mDummyControlTarget;
333         }
334         if (!canBeTopFullscreenOpaqueWindow(focusedWin) && mPolicy.topAppHidesStatusBar()
335                 && (notificationShade == null || !notificationShade.canReceiveKeys())) {
336             // Non-fullscreen focused window should not break the state that the top-fullscreen-app
337             // window hides status bar, unless the notification shade can receive keys.
338             return mPolicy.getTopFullscreenOpaqueWindow();
339         }
340         return focusedWin;
341     }
342 
canBeTopFullscreenOpaqueWindow(@ullable WindowState win)343     private static boolean canBeTopFullscreenOpaqueWindow(@Nullable WindowState win) {
344         // The condition doesn't use WindowState#canAffectSystemUiFlags because the window may
345         // haven't drawn or committed the visibility.
346         final boolean nonAttachedAppWindow = win != null
347                 && win.mAttrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
348                 && win.mAttrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
349         return nonAttachedAppWindow && win.mAttrs.isFullscreen() && !win.isFullyTransparent()
350                 && !win.inMultiWindowMode();
351     }
352 
getNavControlTarget(@ullable WindowState focusedWin, boolean forceShowsSystemBarsForWindowingMode)353     private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin,
354             boolean forceShowsSystemBarsForWindowingMode) {
355         final WindowState imeWin = mDisplayContent.mInputMethodWindow;
356         if (imeWin != null && imeWin.isVisible()) {
357             // Force showing navigation bar while IME is visible.
358             return null;
359         }
360         if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
361             return mDummyControlTarget;
362         }
363         if (focusedWin == mPolicy.getNotificationShade()) {
364             // Notification shade has control anyways, no reason to force anything.
365             return focusedWin;
366         }
367         if (remoteInsetsControllerControlsSystemBars(focusedWin)) {
368             mDisplayContent.mRemoteInsetsControlTarget.topFocusedWindowChanged(
369                     focusedWin.mAttrs.packageName);
370             return mDisplayContent.mRemoteInsetsControlTarget;
371         }
372         if (forceShowsSystemBarsForWindowingMode) {
373             // Navigation bar is forcibly shown for the windowing mode which is a steady state.
374             // We don't want the client to control the navigation bar, and we will dispatch the real
375             // visibility of navigation bar to the client.
376             return null;
377         }
378         if (forceShowsNavigationBarTransiently()) {
379             // Navigation bar is forcibly shown transiently, and its new visibility won't be
380             // dispatched to the client so that we can keep the layout stable. We will dispatch the
381             // fake control to the client, so that it can re-show the bar during this scenario.
382             return mDummyControlTarget;
383         }
384         return focusedWin;
385     }
386 
387     /**
388      * Determines whether the remote insets controller should take control of system bars for all
389      * windows.
390      */
remoteInsetsControllerControlsSystemBars(@ullable WindowState focusedWin)391     boolean remoteInsetsControllerControlsSystemBars(@Nullable WindowState focusedWin) {
392         if (focusedWin == null) {
393             return false;
394         }
395         if (!mRemoteInsetsControllerControlsSystemBars) {
396             return false;
397         }
398         if (mDisplayContent == null || mDisplayContent.mRemoteInsetsControlTarget == null) {
399             // No remote insets control target to take control of insets.
400             return false;
401         }
402         // If necessary, auto can control application windows when
403         // config_remoteInsetsControllerControlsSystemBars is set to true. This is useful in cases
404         // where we want to dictate system bar inset state for applications.
405         return focusedWin.getAttrs().type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
406                 && focusedWin.getAttrs().type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
407     }
408 
forceShowsStatusBarTransiently()409     private boolean forceShowsStatusBarTransiently() {
410         final WindowState win = mPolicy.getStatusBar();
411         return win != null && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
412     }
413 
forceShowsNavigationBarTransiently()414     private boolean forceShowsNavigationBarTransiently() {
415         final WindowState win = mPolicy.getNotificationShade();
416         return win != null
417                 && (win.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
418     }
419 
forceShowsSystemBarsForWindowingMode()420     private boolean forceShowsSystemBarsForWindowingMode() {
421         final boolean isDockedRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea()
422                 .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
423         final boolean isFreeformRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea()
424                 .isRootTaskVisible(WINDOWING_MODE_FREEFORM);
425         final boolean isResizing = mDisplayContent.getDockedDividerController().isResizing();
426 
427         // We need to force system bars when the docked root task is visible, when the freeform
428         // root task is visible but also when we are resizing for the transitions when docked
429         // root task visibility changes.
430         return isDockedRootTaskVisible || isFreeformRootTaskVisible || isResizing;
431     }
432 
433     @VisibleForTesting
startAnimation(boolean show, Runnable callback)434     void startAnimation(boolean show, Runnable callback) {
435         int typesReady = 0;
436         final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
437         final IntArray showingTransientTypes = mShowingTransientTypes;
438         for (int i = showingTransientTypes.size() - 1; i >= 0; i--) {
439             final @InternalInsetsType int type = showingTransientTypes.get(i);
440             InsetsSourceProvider provider = mStateController.getSourceProvider(type);
441             InsetsSourceControl control = provider.getControl(mDummyControlTarget);
442             if (control == null || control.getLeash() == null) {
443                 continue;
444             }
445             typesReady |= InsetsState.toPublicType(type);
446             controls.put(control.getType(), new InsetsSourceControl(control));
447         }
448         controlAnimationUnchecked(typesReady, controls, show, callback);
449     }
450 
controlAnimationUnchecked(int typesReady, SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback)451     private void controlAnimationUnchecked(int typesReady,
452             SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) {
453         InsetsPolicyAnimationControlListener listener =
454                 new InsetsPolicyAnimationControlListener(show, callback, typesReady);
455         listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show);
456     }
457 
458     private class BarWindow {
459 
460         private final int mId;
461         private  @StatusBarManager.WindowVisibleState int mState =
462                 StatusBarManager.WINDOW_STATE_SHOWING;
463 
BarWindow(int id)464         BarWindow(int id) {
465             mId = id;
466         }
467 
updateVisibility(@ullable InsetsControlTarget controlTarget, @InternalInsetsType int type)468         private void updateVisibility(@Nullable InsetsControlTarget controlTarget,
469                 @InternalInsetsType int type) {
470             setVisible(controlTarget == null || controlTarget.getRequestedVisibility(type));
471         }
472 
setVisible(boolean visible)473         private void setVisible(boolean visible) {
474             final int state = visible ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN;
475             if (mState != state) {
476                 mState = state;
477                 mPolicy.getStatusBarManagerInternal().setWindowState(
478                         mDisplayContent.getDisplayId(), mId, state);
479             }
480         }
481     }
482 
483     private class InsetsPolicyAnimationControlListener extends
484             InsetsController.InternalAnimationControlListener {
485         Runnable mFinishCallback;
486         InsetsPolicyAnimationControlCallbacks mControlCallbacks;
487 
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types)488         InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) {
489             super(show, false /* hasCallbacks */, types, BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
490                     false /* disable */, 0 /* floatingImeBottomInsets */);
491             mFinishCallback = finishCallback;
492             mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
493         }
494 
495         @Override
onAnimationFinish()496         protected void onAnimationFinish() {
497             super.onAnimationFinish();
498             if (mFinishCallback != null) {
499                 DisplayThread.getHandler().post(mFinishCallback);
500             }
501         }
502 
503         private class InsetsPolicyAnimationControlCallbacks implements
504                 InsetsAnimationControlCallbacks {
505             private InsetsAnimationControlImpl mAnimationControl = null;
506             private InsetsPolicyAnimationControlListener mListener;
507 
InsetsPolicyAnimationControlCallbacks(InsetsPolicyAnimationControlListener listener)508             InsetsPolicyAnimationControlCallbacks(InsetsPolicyAnimationControlListener listener) {
509                 mListener = listener;
510             }
511 
controlAnimationUnchecked(int typesReady, SparseArray<InsetsSourceControl> controls, boolean show)512             private void controlAnimationUnchecked(int typesReady,
513                     SparseArray<InsetsSourceControl> controls, boolean show) {
514                 if (typesReady == 0) {
515                     // nothing to animate.
516                     return;
517                 }
518                 mAnimatingShown = show;
519 
520                 final InsetsState state = getInsetsForWindow(mFocusedWin);
521 
522                 // We are about to playing the default animation. Passing a null frame indicates
523                 // the controlled types should be animated regardless of the frame.
524                 mAnimationControl = new InsetsAnimationControlImpl(controls,
525                         null /* frame */, state, mListener, typesReady, this,
526                         mListener.getDurationMs(), getInsetsInterpolator(),
527                         show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE, show
528                                 ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
529                                 : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
530                         null /* translator */);
531                 SurfaceAnimationThread.getHandler().post(
532                         () -> mListener.onReady(mAnimationControl, typesReady));
533             }
534 
535             /** Called on SurfaceAnimationThread without global WM lock held. */
536             @Override
scheduleApplyChangeInsets(InsetsAnimationControlRunner runner)537             public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) {
538                 if (mAnimationControl.applyChangeInsets(null /* outState */)) {
539                     mAnimationControl.finish(mAnimatingShown);
540                 }
541             }
542 
543             @Override
notifyFinished(InsetsAnimationControlRunner runner, boolean shown)544             public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
545                 // Nothing's needed here. Finish steps is handled in the listener
546                 // onAnimationFinished callback.
547             }
548 
549             /** Called on SurfaceAnimationThread without global WM lock held. */
550             @Override
applySurfaceParams( final SyncRtSurfaceTransactionApplier.SurfaceParams... params)551             public void applySurfaceParams(
552                     final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
553                 SurfaceControl.Transaction t = new SurfaceControl.Transaction();
554                 for (int i = params.length - 1; i >= 0; i--) {
555                     SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i];
556                     applyParams(t, surfaceParams, mTmpFloat9);
557                 }
558                 t.apply();
559                 t.close();
560             }
561 
562             // Since we don't push applySurfaceParams to a Handler-queue we don't need
563             // to push release in this case.
564             @Override
releaseSurfaceControlFromRt(SurfaceControl sc)565             public void releaseSurfaceControlFromRt(SurfaceControl sc) {
566                 sc.release();
567             }
568 
569             @Override
startAnimation(InsetsAnimationControlImpl controller, WindowInsetsAnimationControlListener listener, int types, WindowInsetsAnimation animation, Bounds bounds)570             public void startAnimation(InsetsAnimationControlImpl controller,
571                     WindowInsetsAnimationControlListener listener, int types,
572                     WindowInsetsAnimation animation,
573                     Bounds bounds) {
574             }
575 
576             @Override
reportPerceptible(int types, boolean perceptible)577             public void reportPerceptible(int types, boolean perceptible) {
578                 // No-op for now - only client windows report perceptibility for now, with policy
579                 // controllers assumed to always be perceptible.
580             }
581         }
582     }
583 }
584