• 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.wm.shell.common;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.ValueAnimator;
22 import android.annotation.IntDef;
23 import android.content.Context;
24 import android.content.res.Configuration;
25 import android.graphics.Point;
26 import android.graphics.Rect;
27 import android.os.RemoteException;
28 import android.os.ServiceManager;
29 import android.util.Slog;
30 import android.util.SparseArray;
31 import android.view.IDisplayWindowInsetsController;
32 import android.view.IWindowManager;
33 import android.view.InsetsSource;
34 import android.view.InsetsSourceControl;
35 import android.view.InsetsState;
36 import android.view.Surface;
37 import android.view.SurfaceControl;
38 import android.view.WindowInsets;
39 import android.view.animation.Interpolator;
40 import android.view.animation.PathInterpolator;
41 
42 import androidx.annotation.BinderThread;
43 import androidx.annotation.VisibleForTesting;
44 
45 import com.android.internal.view.IInputMethodManager;
46 
47 import java.util.ArrayList;
48 import java.util.concurrent.Executor;
49 
50 /**
51  * Manages IME control at the display-level. This occurs when IME comes up in multi-window mode.
52  */
53 public class DisplayImeController implements DisplayController.OnDisplaysChangedListener {
54     private static final String TAG = "DisplayImeController";
55 
56     private static final boolean DEBUG = false;
57 
58     // NOTE: All these constants came from InsetsController.
59     public static final int ANIMATION_DURATION_SHOW_MS = 275;
60     public static final int ANIMATION_DURATION_HIDE_MS = 340;
61     public static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
62     private static final int DIRECTION_NONE = 0;
63     private static final int DIRECTION_SHOW = 1;
64     private static final int DIRECTION_HIDE = 2;
65     private static final int FLOATING_IME_BOTTOM_INSET = -80;
66 
67     protected final IWindowManager mWmService;
68     protected final Executor mMainExecutor;
69     private final TransactionPool mTransactionPool;
70     private final DisplayController mDisplayController;
71     private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
72     private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
73 
74 
DisplayImeController(IWindowManager wmService, DisplayController displayController, Executor mainExecutor, TransactionPool transactionPool)75     public DisplayImeController(IWindowManager wmService, DisplayController displayController,
76             Executor mainExecutor, TransactionPool transactionPool) {
77         mWmService = wmService;
78         mDisplayController = displayController;
79         mMainExecutor = mainExecutor;
80         mTransactionPool = transactionPool;
81     }
82 
83     /** Starts monitor displays changes and set insets controller for each displays. */
startMonitorDisplays()84     public void startMonitorDisplays() {
85         mDisplayController.addDisplayWindowListener(this);
86     }
87 
88     @Override
onDisplayAdded(int displayId)89     public void onDisplayAdded(int displayId) {
90         // Add's a system-ui window-manager specifically for ime. This type is special because
91         // WM will defer IME inset handling to it in multi-window scenarious.
92         PerDisplay pd = new PerDisplay(displayId,
93                 mDisplayController.getDisplayLayout(displayId).rotation());
94         pd.register();
95         mImePerDisplay.put(displayId, pd);
96     }
97 
98     @Override
onDisplayConfigurationChanged(int displayId, Configuration newConfig)99     public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
100         PerDisplay pd = mImePerDisplay.get(displayId);
101         if (pd == null) {
102             return;
103         }
104         if (mDisplayController.getDisplayLayout(displayId).rotation()
105                 != pd.mRotation && isImeShowing(displayId)) {
106             pd.startAnimation(true, false /* forceRestart */);
107         }
108     }
109 
110     @Override
onDisplayRemoved(int displayId)111     public void onDisplayRemoved(int displayId) {
112         try {
113             mWmService.setDisplayWindowInsetsController(displayId, null);
114         } catch (RemoteException e) {
115             Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
116         }
117         mImePerDisplay.remove(displayId);
118     }
119 
isImeShowing(int displayId)120     private boolean isImeShowing(int displayId) {
121         PerDisplay pd = mImePerDisplay.get(displayId);
122         if (pd == null) {
123             return false;
124         }
125         final InsetsSource imeSource = pd.mInsetsState.getSource(InsetsState.ITYPE_IME);
126         return imeSource != null && pd.mImeSourceControl != null && imeSource.isVisible();
127     }
128 
dispatchPositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t)129     private void dispatchPositionChanged(int displayId, int imeTop,
130             SurfaceControl.Transaction t) {
131         synchronized (mPositionProcessors) {
132             for (ImePositionProcessor pp : mPositionProcessors) {
133                 pp.onImePositionChanged(displayId, imeTop, t);
134             }
135         }
136     }
137 
138     @ImePositionProcessor.ImeAnimationFlags
dispatchStartPositioning(int displayId, int hiddenTop, int shownTop, boolean show, boolean isFloating, SurfaceControl.Transaction t)139     private int dispatchStartPositioning(int displayId, int hiddenTop, int shownTop,
140             boolean show, boolean isFloating, SurfaceControl.Transaction t) {
141         synchronized (mPositionProcessors) {
142             int flags = 0;
143             for (ImePositionProcessor pp : mPositionProcessors) {
144                 flags |= pp.onImeStartPositioning(
145                         displayId, hiddenTop, shownTop, show, isFloating, t);
146             }
147             return flags;
148         }
149     }
150 
dispatchEndPositioning(int displayId, boolean cancel, SurfaceControl.Transaction t)151     private void dispatchEndPositioning(int displayId, boolean cancel,
152             SurfaceControl.Transaction t) {
153         synchronized (mPositionProcessors) {
154             for (ImePositionProcessor pp : mPositionProcessors) {
155                 pp.onImeEndPositioning(displayId, cancel, t);
156             }
157         }
158     }
159 
dispatchImeControlTargetChanged(int displayId, boolean controlling)160     private void dispatchImeControlTargetChanged(int displayId, boolean controlling) {
161         synchronized (mPositionProcessors) {
162             for (ImePositionProcessor pp : mPositionProcessors) {
163                 pp.onImeControlTargetChanged(displayId, controlling);
164             }
165         }
166     }
167 
dispatchVisibilityChanged(int displayId, boolean isShowing)168     private void dispatchVisibilityChanged(int displayId, boolean isShowing) {
169         synchronized (mPositionProcessors) {
170             for (ImePositionProcessor pp : mPositionProcessors) {
171                 pp.onImeVisibilityChanged(displayId, isShowing);
172             }
173         }
174     }
175 
176     /**
177      * Adds an {@link ImePositionProcessor} to be called during ime position updates.
178      */
addPositionProcessor(ImePositionProcessor processor)179     public void addPositionProcessor(ImePositionProcessor processor) {
180         synchronized (mPositionProcessors) {
181             if (mPositionProcessors.contains(processor)) {
182                 return;
183             }
184             mPositionProcessors.add(processor);
185         }
186     }
187 
188     /**
189      * Removes an {@link ImePositionProcessor} to be called during ime position updates.
190      */
removePositionProcessor(ImePositionProcessor processor)191     public void removePositionProcessor(ImePositionProcessor processor) {
192         synchronized (mPositionProcessors) {
193             mPositionProcessors.remove(processor);
194         }
195     }
196 
197     /** An implementation of {@link IDisplayWindowInsetsController} for a given display id. */
198     public class PerDisplay {
199         final int mDisplayId;
200         final InsetsState mInsetsState = new InsetsState();
201         protected final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
202                 new DisplayWindowInsetsControllerImpl();
203         InsetsSourceControl mImeSourceControl = null;
204         int mAnimationDirection = DIRECTION_NONE;
205         ValueAnimator mAnimation = null;
206         int mRotation = Surface.ROTATION_0;
207         boolean mImeShowing = false;
208         final Rect mImeFrame = new Rect();
209         boolean mAnimateAlpha = true;
210 
PerDisplay(int displayId, int initialRotation)211         public PerDisplay(int displayId, int initialRotation) {
212             mDisplayId = displayId;
213             mRotation = initialRotation;
214         }
215 
register()216         public void register() {
217             try {
218                 mWmService.setDisplayWindowInsetsController(mDisplayId, mInsetsControllerImpl);
219             } catch (RemoteException e) {
220                 Slog.w(TAG, "Unable to set insets controller on display " + mDisplayId);
221             }
222         }
223 
insetsChanged(InsetsState insetsState)224         protected void insetsChanged(InsetsState insetsState) {
225             if (mInsetsState.equals(insetsState)) {
226                 return;
227             }
228 
229             updateImeVisibility(insetsState.getSourceOrDefaultVisibility(InsetsState.ITYPE_IME));
230 
231             final InsetsSource newSource = insetsState.getSource(InsetsState.ITYPE_IME);
232             final Rect newFrame = newSource.getFrame();
233             final Rect oldFrame = mInsetsState.getSource(InsetsState.ITYPE_IME).getFrame();
234 
235             mInsetsState.set(insetsState, true /* copySources */);
236             if (mImeShowing && !newFrame.equals(oldFrame) && newSource.isVisible()) {
237                 if (DEBUG) Slog.d(TAG, "insetsChanged when IME showing, restart animation");
238                 startAnimation(mImeShowing, true /* forceRestart */);
239             }
240         }
241 
242         @VisibleForTesting
insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)243         protected void insetsControlChanged(InsetsState insetsState,
244                 InsetsSourceControl[] activeControls) {
245             insetsChanged(insetsState);
246             InsetsSourceControl imeSourceControl = null;
247             if (activeControls != null) {
248                 for (InsetsSourceControl activeControl : activeControls) {
249                     if (activeControl == null) {
250                         continue;
251                     }
252                     if (activeControl.getType() == InsetsState.ITYPE_IME) {
253                         imeSourceControl = activeControl;
254                     }
255                 }
256             }
257 
258             final boolean hadImeSourceControl = mImeSourceControl != null;
259             final boolean hasImeSourceControl = imeSourceControl != null;
260             if (hadImeSourceControl != hasImeSourceControl) {
261                 dispatchImeControlTargetChanged(mDisplayId, hasImeSourceControl);
262             }
263 
264             if (hasImeSourceControl) {
265                 final Point lastSurfacePosition = mImeSourceControl != null
266                         ? mImeSourceControl.getSurfacePosition() : null;
267                 final boolean positionChanged =
268                         !imeSourceControl.getSurfacePosition().equals(lastSurfacePosition);
269                 final boolean leashChanged =
270                         !haveSameLeash(mImeSourceControl, imeSourceControl);
271                 if (mAnimation != null) {
272                     if (positionChanged) {
273                         startAnimation(mImeShowing, true /* forceRestart */);
274                     }
275                 } else {
276                     if (leashChanged) {
277                         applyVisibilityToLeash(imeSourceControl);
278                     }
279                     if (!mImeShowing) {
280                         removeImeSurface();
281                     }
282                 }
283                 if (mImeSourceControl != null) {
284                     mImeSourceControl.release(SurfaceControl::release);
285                 }
286                 mImeSourceControl = imeSourceControl;
287             }
288         }
289 
applyVisibilityToLeash(InsetsSourceControl imeSourceControl)290         private void applyVisibilityToLeash(InsetsSourceControl imeSourceControl) {
291             SurfaceControl leash = imeSourceControl.getLeash();
292             if (leash != null) {
293                 SurfaceControl.Transaction t = mTransactionPool.acquire();
294                 if (mImeShowing) {
295                     t.show(leash);
296                 } else {
297                     t.hide(leash);
298                 }
299                 t.apply();
300                 mTransactionPool.release(t);
301             }
302         }
303 
showInsets(int types, boolean fromIme)304         protected void showInsets(int types, boolean fromIme) {
305             if ((types & WindowInsets.Type.ime()) == 0) {
306                 return;
307             }
308             if (DEBUG) Slog.d(TAG, "Got showInsets for ime");
309             startAnimation(true /* show */, false /* forceRestart */);
310         }
311 
312 
hideInsets(int types, boolean fromIme)313         protected void hideInsets(int types, boolean fromIme) {
314             if ((types & WindowInsets.Type.ime()) == 0) {
315                 return;
316             }
317             if (DEBUG) Slog.d(TAG, "Got hideInsets for ime");
318             startAnimation(false /* show */, false /* forceRestart */);
319         }
320 
topFocusedWindowChanged(String packageName)321         public void topFocusedWindowChanged(String packageName) {
322             // Do nothing
323         }
324 
325         /**
326          * Sends the local visibility state back to window manager. Needed for legacy adjustForIme.
327          */
setVisibleDirectly(boolean visible)328         private void setVisibleDirectly(boolean visible) {
329             mInsetsState.getSource(InsetsState.ITYPE_IME).setVisible(visible);
330             try {
331                 mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState);
332             } catch (RemoteException e) {
333             }
334         }
335 
imeTop(float surfaceOffset)336         private int imeTop(float surfaceOffset) {
337             return mImeFrame.top + (int) surfaceOffset;
338         }
339 
calcIsFloating(InsetsSource imeSource)340         private boolean calcIsFloating(InsetsSource imeSource) {
341             final Rect frame = imeSource.getFrame();
342             if (frame.height() == 0) {
343                 return true;
344             }
345             // Some Floating Input Methods will still report a frame, but the frame is actually
346             // a nav-bar inset created by WM and not part of the IME (despite being reported as
347             // an IME inset). For now, we assume that no non-floating IME will be <= this nav bar
348             // frame height so any reported frame that is <= nav-bar frame height is assumed to
349             // be floating.
350             return frame.height() <= mDisplayController.getDisplayLayout(mDisplayId)
351                     .navBarFrameHeight();
352         }
353 
startAnimation(final boolean show, final boolean forceRestart)354         private void startAnimation(final boolean show, final boolean forceRestart) {
355             final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
356             if (imeSource == null || mImeSourceControl == null) {
357                 return;
358             }
359             final Rect newFrame = imeSource.getFrame();
360             final boolean isFloating = calcIsFloating(imeSource) && show;
361             if (isFloating) {
362                 // This is a "floating" or "expanded" IME, so to get animations, just
363                 // pretend the ime has some size just below the screen.
364                 mImeFrame.set(newFrame);
365                 final int floatingInset = (int) (mDisplayController.getDisplayLayout(mDisplayId)
366                         .density() * FLOATING_IME_BOTTOM_INSET);
367                 mImeFrame.bottom -= floatingInset;
368             } else if (newFrame.height() != 0) {
369                 // Don't set a new frame if it's empty and hiding -- this maintains continuity
370                 mImeFrame.set(newFrame);
371             }
372             if (DEBUG) {
373                 Slog.d(TAG, "Run startAnim  show:" + show + "  was:"
374                         + (mAnimationDirection == DIRECTION_SHOW ? "SHOW"
375                         : (mAnimationDirection == DIRECTION_HIDE ? "HIDE" : "NONE")));
376             }
377             if (!forceRestart && (mAnimationDirection == DIRECTION_SHOW && show)
378                     || (mAnimationDirection == DIRECTION_HIDE && !show)) {
379                 return;
380             }
381             boolean seek = false;
382             float seekValue = 0;
383             if (mAnimation != null) {
384                 if (mAnimation.isRunning()) {
385                     seekValue = (float) mAnimation.getAnimatedValue();
386                     seek = true;
387                 }
388                 mAnimation.cancel();
389             }
390             final float defaultY = mImeSourceControl.getSurfacePosition().y;
391             final float x = mImeSourceControl.getSurfacePosition().x;
392             final float hiddenY = defaultY + mImeFrame.height();
393             final float shownY = defaultY;
394             final float startY = show ? hiddenY : shownY;
395             final float endY = show ? shownY : hiddenY;
396             if (mAnimationDirection == DIRECTION_NONE && mImeShowing && show) {
397                 // IME is already showing, so set seek to end
398                 seekValue = shownY;
399                 seek = true;
400             }
401             mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
402             updateImeVisibility(show);
403             mAnimation = ValueAnimator.ofFloat(startY, endY);
404             mAnimation.setDuration(
405                     show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS);
406             if (seek) {
407                 mAnimation.setCurrentFraction((seekValue - startY) / (endY - startY));
408             }
409 
410             mAnimation.addUpdateListener(animation -> {
411                 SurfaceControl.Transaction t = mTransactionPool.acquire();
412                 float value = (float) animation.getAnimatedValue();
413                 t.setPosition(mImeSourceControl.getLeash(), x, value);
414                 final float alpha = (mAnimateAlpha || isFloating)
415                         ? (value - hiddenY) / (shownY - hiddenY) : 1.f;
416                 t.setAlpha(mImeSourceControl.getLeash(), alpha);
417                 dispatchPositionChanged(mDisplayId, imeTop(value), t);
418                 t.apply();
419                 mTransactionPool.release(t);
420             });
421             mAnimation.setInterpolator(INTERPOLATOR);
422             mAnimation.addListener(new AnimatorListenerAdapter() {
423                 private boolean mCancelled = false;
424 
425                 @Override
426                 public void onAnimationStart(Animator animation) {
427                     SurfaceControl.Transaction t = mTransactionPool.acquire();
428                     t.setPosition(mImeSourceControl.getLeash(), x, startY);
429                     if (DEBUG) {
430                         Slog.d(TAG, "onAnimationStart d:" + mDisplayId + " top:"
431                                 + imeTop(hiddenY) + "->" + imeTop(shownY)
432                                 + " showing:" + (mAnimationDirection == DIRECTION_SHOW));
433                     }
434                     int flags = dispatchStartPositioning(mDisplayId, imeTop(hiddenY),
435                             imeTop(shownY), mAnimationDirection == DIRECTION_SHOW, isFloating, t);
436                     mAnimateAlpha = (flags & ImePositionProcessor.IME_ANIMATION_NO_ALPHA) == 0;
437                     final float alpha = (mAnimateAlpha || isFloating)
438                             ? (startY - hiddenY) / (shownY - hiddenY)
439                             : 1.f;
440                     t.setAlpha(mImeSourceControl.getLeash(), alpha);
441                     if (mAnimationDirection == DIRECTION_SHOW) {
442                         t.show(mImeSourceControl.getLeash());
443                     }
444                     t.apply();
445                     mTransactionPool.release(t);
446                 }
447 
448                 @Override
449                 public void onAnimationCancel(Animator animation) {
450                     mCancelled = true;
451                 }
452 
453                 @Override
454                 public void onAnimationEnd(Animator animation) {
455                     if (DEBUG) Slog.d(TAG, "onAnimationEnd " + mCancelled);
456                     SurfaceControl.Transaction t = mTransactionPool.acquire();
457                     if (!mCancelled) {
458                         t.setPosition(mImeSourceControl.getLeash(), x, endY);
459                         t.setAlpha(mImeSourceControl.getLeash(), 1.f);
460                     }
461                     dispatchEndPositioning(mDisplayId, mCancelled, t);
462                     if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
463                         t.hide(mImeSourceControl.getLeash());
464                         removeImeSurface();
465                     }
466                     t.apply();
467                     mTransactionPool.release(t);
468 
469                     mAnimationDirection = DIRECTION_NONE;
470                     mAnimation = null;
471                 }
472             });
473             if (!show) {
474                 // When going away, queue up insets change first, otherwise any bounds changes
475                 // can have a "flicker" of ime-provided insets.
476                 setVisibleDirectly(false /* visible */);
477             }
478             mAnimation.start();
479             if (show) {
480                 // When showing away, queue up insets change last, otherwise any bounds changes
481                 // can have a "flicker" of ime-provided insets.
482                 setVisibleDirectly(true /* visible */);
483             }
484         }
485 
updateImeVisibility(boolean isShowing)486         private void updateImeVisibility(boolean isShowing) {
487             if (mImeShowing != isShowing) {
488                 mImeShowing = isShowing;
489                 dispatchVisibilityChanged(mDisplayId, isShowing);
490             }
491         }
492 
493         @VisibleForTesting
494         @BinderThread
495         public class DisplayWindowInsetsControllerImpl
496                 extends IDisplayWindowInsetsController.Stub {
497             @Override
topFocusedWindowChanged(String packageName)498             public void topFocusedWindowChanged(String packageName) throws RemoteException {
499                 mMainExecutor.execute(() -> {
500                     PerDisplay.this.topFocusedWindowChanged(packageName);
501                 });
502             }
503 
504             @Override
insetsChanged(InsetsState insetsState)505             public void insetsChanged(InsetsState insetsState) throws RemoteException {
506                 mMainExecutor.execute(() -> {
507                     PerDisplay.this.insetsChanged(insetsState);
508                 });
509             }
510 
511             @Override
insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)512             public void insetsControlChanged(InsetsState insetsState,
513                     InsetsSourceControl[] activeControls) throws RemoteException {
514                 mMainExecutor.execute(() -> {
515                     PerDisplay.this.insetsControlChanged(insetsState, activeControls);
516                 });
517             }
518 
519             @Override
showInsets(int types, boolean fromIme)520             public void showInsets(int types, boolean fromIme) throws RemoteException {
521                 mMainExecutor.execute(() -> {
522                     PerDisplay.this.showInsets(types, fromIme);
523                 });
524             }
525 
526             @Override
hideInsets(int types, boolean fromIme)527             public void hideInsets(int types, boolean fromIme) throws RemoteException {
528                 mMainExecutor.execute(() -> {
529                     PerDisplay.this.hideInsets(types, fromIme);
530                 });
531             }
532         }
533     }
534 
removeImeSurface()535     void removeImeSurface() {
536         final IInputMethodManager imms = getImms();
537         if (imms != null) {
538             try {
539                 // Remove the IME surface to make the insets invisible for
540                 // non-client controlled insets.
541                 imms.removeImeSurface();
542             } catch (RemoteException e) {
543                 Slog.e(TAG, "Failed to remove IME surface.", e);
544             }
545         }
546     }
547 
548     /**
549      * Allows other things to synchronize with the ime position
550      */
551     public interface ImePositionProcessor {
552         /**
553          * Indicates that ime shouldn't animate alpha. It will always be opaque. Used when stuff
554          * behind the IME shouldn't be visible (for example during split-screen adjustment where
555          * there is nothing behind the ime).
556          */
557         int IME_ANIMATION_NO_ALPHA = 1;
558 
559         /** @hide */
560         @IntDef(prefix = {"IME_ANIMATION_"}, value = {
561                 IME_ANIMATION_NO_ALPHA,
562         })
563         @interface ImeAnimationFlags {
564         }
565 
566         /**
567          * Called when the IME position is starting to animate.
568          *
569          * @param hiddenTop  The y position of the top of the IME surface when it is hidden.
570          * @param shownTop   The y position of the top of the IME surface when it is shown.
571          * @param showing    {@code true} when we are animating from hidden to shown, {@code false}
572          *                   when animating from shown to hidden.
573          * @param isFloating {@code true} when the ime is a floating ime (doesn't inset).
574          * @return flags that may alter how ime itself is animated (eg. no-alpha).
575          */
576         @ImeAnimationFlags
onImeStartPositioning(int displayId, int hiddenTop, int shownTop, boolean showing, boolean isFloating, SurfaceControl.Transaction t)577         default int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
578                 boolean showing, boolean isFloating, SurfaceControl.Transaction t) {
579             return 0;
580         }
581 
582         /**
583          * Called when the ime position changed. This is expected to be a synchronous call on the
584          * animation thread. Operations can be added to the transaction to be applied in sync.
585          *
586          * @param imeTop The current y position of the top of the IME surface.
587          */
onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t)588         default void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) {
589         }
590 
591         /**
592          * Called when the IME position is done animating.
593          *
594          * @param cancel {@code true} if this was cancelled. This implies another start is coming.
595          */
onImeEndPositioning(int displayId, boolean cancel, SurfaceControl.Transaction t)596         default void onImeEndPositioning(int displayId, boolean cancel,
597                 SurfaceControl.Transaction t) {
598         }
599 
600         /**
601          * Called when the IME control target changed. So that the processor can restore its
602          * adjusted layout when the IME insets is not controlling by the current controller anymore.
603          *
604          * @param controlling indicates whether the current controller is controlling IME insets.
605          */
onImeControlTargetChanged(int displayId, boolean controlling)606         default void onImeControlTargetChanged(int displayId, boolean controlling) {
607         }
608 
609         /**
610          * Called when the IME visibility changed.
611          *
612          * @param isShowing {@code true} if the IME is shown.
613          */
onImeVisibilityChanged(int displayId, boolean isShowing)614         default void onImeVisibilityChanged(int displayId, boolean isShowing) {
615 
616         }
617     }
618 
getImms()619     public IInputMethodManager getImms() {
620         return IInputMethodManager.Stub.asInterface(
621                 ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
622     }
623 
haveSameLeash(InsetsSourceControl a, InsetsSourceControl b)624     private static boolean haveSameLeash(InsetsSourceControl a, InsetsSourceControl b) {
625         if (a == b) {
626             return true;
627         }
628         if (a == null || b == null) {
629             return false;
630         }
631         if (a.getLeash() == b.getLeash()) {
632             return true;
633         }
634         if (a.getLeash() == null || b.getLeash() == null) {
635             return false;
636         }
637         return a.getLeash().isSameSurface(b.getLeash());
638     }
639 }
640