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