1  /*
2   * Copyright (C) 2006 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 android.view;
18  
19  import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS;
20  import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED;
21  import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND;
22  import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID;
23  import static android.view.Display.DEFAULT_DISPLAY;
24  import static android.view.Display.INVALID_DISPLAY;
25  import static android.view.InputDevice.SOURCE_CLASS_NONE;
26  import static android.view.InsetsSource.ID_IME;
27  import static android.view.View.PFLAG_DRAW_ANIMATION;
28  import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
29  import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
30  import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
31  import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
32  import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
33  import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
34  import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
35  import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
36  import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
37  import static android.view.ViewRootImplProto.ADDED;
38  import static android.view.ViewRootImplProto.APP_VISIBLE;
39  import static android.view.ViewRootImplProto.CUR_SCROLL_Y;
40  import static android.view.ViewRootImplProto.DISPLAY_ID;
41  import static android.view.ViewRootImplProto.HEIGHT;
42  import static android.view.ViewRootImplProto.IS_ANIMATING;
43  import static android.view.ViewRootImplProto.IS_DRAWING;
44  import static android.view.ViewRootImplProto.LAST_WINDOW_INSETS;
45  import static android.view.ViewRootImplProto.REMOVED;
46  import static android.view.ViewRootImplProto.SCROLL_Y;
47  import static android.view.ViewRootImplProto.SOFT_INPUT_MODE;
48  import static android.view.ViewRootImplProto.VIEW;
49  import static android.view.ViewRootImplProto.VISIBLE_RECT;
50  import static android.view.ViewRootImplProto.WIDTH;
51  import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
52  import static android.view.ViewRootImplProto.WIN_FRAME;
53  import static android.view.ViewRootRefreshRateController.RefreshRatePref.LOWER;
54  import static android.view.ViewRootRefreshRateController.RefreshRatePref.RESTORE;
55  import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
56  import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
57  import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
58  import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
59  import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
60  import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
61  import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
62  import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
63  import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
64  import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
65  import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
66  import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
67  import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
68  import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
69  import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
70  import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
71  import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
72  import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
73  import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
74  import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
75  import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
76  import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
77  import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
78  import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
79  import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
80  import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
81  import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
82  import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
83  import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
84  import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
85  import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS;
86  import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
87  import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
88  import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
89  import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
90  import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
91  
92  import android.Manifest;
93  import android.accessibilityservice.AccessibilityService;
94  import android.animation.AnimationHandler;
95  import android.animation.LayoutTransition;
96  import android.annotation.AnyThread;
97  import android.annotation.NonNull;
98  import android.annotation.Nullable;
99  import android.annotation.Size;
100  import android.annotation.UiContext;
101  import android.annotation.UiThread;
102  import android.app.ActivityManager;
103  import android.app.ActivityThread;
104  import android.app.ICompatCameraControlCallback;
105  import android.app.ResourcesManager;
106  import android.app.WindowConfiguration;
107  import android.app.compat.CompatChanges;
108  import android.compat.annotation.UnsupportedAppUsage;
109  import android.content.ClipData;
110  import android.content.ClipDescription;
111  import android.content.Context;
112  import android.content.pm.ActivityInfo;
113  import android.content.pm.PackageManager;
114  import android.content.res.CompatibilityInfo;
115  import android.content.res.Configuration;
116  import android.content.res.Resources;
117  import android.content.res.TypedArray;
118  import android.graphics.BLASTBufferQueue;
119  import android.graphics.Canvas;
120  import android.graphics.Color;
121  import android.graphics.FrameInfo;
122  import android.graphics.HardwareRenderer;
123  import android.graphics.HardwareRenderer.FrameDrawingCallback;
124  import android.graphics.HardwareRendererObserver;
125  import android.graphics.Insets;
126  import android.graphics.Matrix;
127  import android.graphics.PixelFormat;
128  import android.graphics.Point;
129  import android.graphics.PointF;
130  import android.graphics.PorterDuff;
131  import android.graphics.RecordingCanvas;
132  import android.graphics.Rect;
133  import android.graphics.RectF;
134  import android.graphics.Region;
135  import android.graphics.RenderNode;
136  import android.graphics.drawable.Drawable;
137  import android.graphics.drawable.GradientDrawable;
138  import android.hardware.display.DisplayManager;
139  import android.hardware.display.DisplayManager.DisplayListener;
140  import android.hardware.display.DisplayManagerGlobal;
141  import android.hardware.input.InputManagerGlobal;
142  import android.hardware.input.InputSettings;
143  import android.media.AudioManager;
144  import android.os.Binder;
145  import android.os.Build;
146  import android.os.Bundle;
147  import android.os.Debug;
148  import android.os.Handler;
149  import android.os.IBinder;
150  import android.os.Looper;
151  import android.os.Message;
152  import android.os.ParcelFileDescriptor;
153  import android.os.Process;
154  import android.os.RemoteException;
155  import android.os.SystemClock;
156  import android.os.SystemProperties;
157  import android.os.Trace;
158  import android.os.UserHandle;
159  import android.sysprop.DisplayProperties;
160  import android.text.TextUtils;
161  import android.util.AndroidRuntimeException;
162  import android.util.DisplayMetrics;
163  import android.util.EventLog;
164  import android.util.IndentingPrintWriter;
165  import android.util.Log;
166  import android.util.LongArray;
167  import android.util.MergedConfiguration;
168  import android.util.Slog;
169  import android.util.SparseArray;
170  import android.util.TimeUtils;
171  import android.util.TypedValue;
172  import android.util.proto.ProtoOutputStream;
173  import android.view.InputDevice.InputSourceClass;
174  import android.view.Surface.OutOfResourcesException;
175  import android.view.SurfaceControl.Transaction;
176  import android.view.View.AttachInfo;
177  import android.view.View.FocusDirection;
178  import android.view.View.MeasureSpec;
179  import android.view.Window.OnContentApplyWindowInsetsListener;
180  import android.view.WindowInsets.Type;
181  import android.view.WindowInsets.Type.InsetsType;
182  import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
183  import android.view.accessibility.AccessibilityEvent;
184  import android.view.accessibility.AccessibilityInteractionClient;
185  import android.view.accessibility.AccessibilityManager;
186  import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
187  import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
188  import android.view.accessibility.AccessibilityNodeIdManager;
189  import android.view.accessibility.AccessibilityNodeInfo;
190  import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
191  import android.view.accessibility.AccessibilityNodeProvider;
192  import android.view.accessibility.AccessibilityWindowAttributes;
193  import android.view.accessibility.AccessibilityWindowInfo;
194  import android.view.accessibility.IAccessibilityEmbeddedConnection;
195  import android.view.accessibility.IAccessibilityInteractionConnection;
196  import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
197  import android.view.animation.AccelerateDecelerateInterpolator;
198  import android.view.animation.Interpolator;
199  import android.view.autofill.AutofillId;
200  import android.view.autofill.AutofillManager;
201  import android.view.contentcapture.ContentCaptureManager;
202  import android.view.contentcapture.ContentCaptureSession;
203  import android.view.contentcapture.MainContentCaptureSession;
204  import android.view.inputmethod.ImeTracker;
205  import android.view.inputmethod.InputMethodManager;
206  import android.widget.Scroller;
207  import android.window.BackEvent;
208  import android.window.ClientWindowFrames;
209  import android.window.CompatOnBackInvokedCallback;
210  import android.window.OnBackAnimationCallback;
211  import android.window.OnBackInvokedCallback;
212  import android.window.OnBackInvokedDispatcher;
213  import android.window.ScreenCapture;
214  import android.window.SurfaceSyncGroup;
215  import android.window.WindowOnBackInvokedDispatcher;
216  
217  import com.android.internal.R;
218  import com.android.internal.annotations.GuardedBy;
219  import com.android.internal.annotations.VisibleForTesting;
220  import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
221  import com.android.internal.inputmethod.ImeTracing;
222  import com.android.internal.inputmethod.InputMethodDebug;
223  import com.android.internal.os.IResultReceiver;
224  import com.android.internal.os.SomeArgs;
225  import com.android.internal.policy.DecorView;
226  import com.android.internal.policy.PhoneFallbackEventHandler;
227  import com.android.internal.util.Preconditions;
228  import com.android.internal.view.BaseSurfaceHolder;
229  import com.android.internal.view.RootViewSurfaceTaker;
230  import com.android.internal.view.SurfaceCallbackHelper;
231  
232  import java.io.IOException;
233  import java.io.OutputStream;
234  import java.io.PrintWriter;
235  import java.io.StringWriter;
236  import java.lang.ref.WeakReference;
237  import java.util.ArrayDeque;
238  import java.util.ArrayList;
239  import java.util.HashSet;
240  import java.util.List;
241  import java.util.Objects;
242  import java.util.OptionalInt;
243  import java.util.Queue;
244  import java.util.concurrent.CountDownLatch;
245  import java.util.concurrent.Executor;
246  import java.util.concurrent.atomic.AtomicReference;
247  import java.util.function.Consumer;
248  
249  /**
250   * The top of a view hierarchy, implementing the needed protocol between View
251   * and the WindowManager.  This is for the most part an internal implementation
252   * detail of {@link WindowManagerGlobal}.
253   *
254   * {@hide}
255   */
256  @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
257  public final class ViewRootImpl implements ViewParent,
258          View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
259          AttachedSurfaceControl {
260      private static final String TAG = "ViewRootImpl";
261      private static final boolean DBG = false;
262      private static final boolean LOCAL_LOGV = false;
263      /** @noinspection PointlessBooleanExpression*/
264      private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
265      private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
266      private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
267      private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
268      private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
269      private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
270      private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
271      private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
272      private static final boolean DEBUG_FPS = false;
273      private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
274      private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
275      private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV;
276      private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV;
277      private static final boolean DEBUG_TOUCH_NAVIGATION = false || LOCAL_LOGV;
278      private static final boolean DEBUG_BLAST = false || LOCAL_LOGV;
279      private static final int LOGTAG_INPUT_FOCUS = 62001;
280  
281      /**
282       * Set to false if we do not want to use the multi threaded renderer even though
283       * threaded renderer (aka hardware renderering) is used. Note that by disabling
284       * this, WindowCallbacks will not fire.
285       */
286      private static final boolean MT_RENDERER_AVAILABLE = true;
287  
288      /**
289       * Whether or not to report end-to-end input latency. Can be disabled temporarily as a
290       * risk mitigation against potential jank caused by acquiring a weak reference
291       * per frame.
292       */
293      private static final boolean ENABLE_INPUT_LATENCY_TRACKING = true;
294  
295      /**
296       * Controls whether to use the new oneway performHapticFeedback call. This returns
297       * true in a few more conditions, but doesn't affect which haptics happen. Notably, it
298       * makes the call to performHapticFeedback non-blocking, which reduces potential UI jank.
299       * This is intended as a temporary flag, ultimately becoming permanently 'true'.
300       */
301      private static final boolean USE_ASYNC_PERFORM_HAPTIC_FEEDBACK = true;
302  
303      /**
304       * Whether the caption is drawn by the shell.
305       * @hide
306       */
307      public static final boolean CAPTION_ON_SHELL =
308              SystemProperties.getBoolean("persist.wm.debug.caption_on_shell", true);
309  
310      /**
311       * Whether the client (system UI) is handling the transient gesture and the corresponding
312       * animation.
313       * @hide
314       */
315      public static final boolean CLIENT_TRANSIENT =
316              SystemProperties.getBoolean("persist.wm.debug.client_transient", false);
317  
318      /**
319       * Whether the client (system UI) is handling the immersive confirmation window. If
320       * {@link CLIENT_TRANSIENT} is set to true, the immersive confirmation window will always be the
321       * client instance and this flag will be ignored. Otherwise, the immersive confirmation window
322       * can be switched freely by this flag.
323       * @hide
324       */
325      public static final boolean CLIENT_IMMERSIVE_CONFIRMATION =
326              SystemProperties.getBoolean("persist.wm.debug.client_immersive_confirmation", false);
327  
328      /**
329       * Whether the client should compute the window frame on its own.
330       * @hide
331       */
332      public static final boolean LOCAL_LAYOUT =
333              SystemProperties.getBoolean("persist.debug.local_layout", true);
334  
335      /**
336       * Set this system property to true to force the view hierarchy to render
337       * at 60 Hz. This can be used to measure the potential framerate.
338       */
339      private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
340  
341      /**
342       * Maximum time we allow the user to roll the trackball enough to generate
343       * a key event, before resetting the counters.
344       */
345      static final int MAX_TRACKBALL_DELAY = 250;
346  
347      /**
348       * Initial value for {@link #mContentCaptureEnabled}.
349       */
350      private static final int CONTENT_CAPTURE_ENABLED_NOT_CHECKED = 0;
351  
352      /**
353       * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code true}.
354       */
355      private static final int CONTENT_CAPTURE_ENABLED_TRUE = 1;
356  
357      /**
358       * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code false}.
359       */
360      private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2;
361  
362      /**
363       * Maximum time to wait for {@link View#dispatchScrollCaptureSearch} to complete.
364       */
365      private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500;
366  
367      private static final int UNSET_SYNC_ID = -1;
368  
369      /**
370       * Minimum time to wait before reporting changes to keep clear areas.
371       */
372      private static final int KEEP_CLEAR_AREA_REPORT_RATE_MILLIS = 100;
373  
374      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
375      static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
376  
377      static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<>();
378      static boolean sFirstDrawComplete = false;
379  
380      private ArrayList<OnBufferTransformHintChangedListener> mTransformHintListeners =
381              new ArrayList<>();
382      private @SurfaceControl.BufferTransform
383              int mPreviousTransformHint = SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
384      /**
385       * The top level {@link OnBackInvokedDispatcher}.
386       */
387      private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
388      /**
389       * Compatibility {@link OnBackInvokedCallback} that dispatches KEYCODE_BACK events
390       * to view root for apps using legacy back behavior.
391       */
392      private CompatOnBackInvokedCallback mCompatOnBackInvokedCallback;
393  
394      /**
395       * Callback for notifying about global configuration changes.
396       */
397      public interface ConfigChangedCallback {
398  
399          /** Notifies about global config change. */
onConfigurationChanged(Configuration globalConfig)400          void onConfigurationChanged(Configuration globalConfig);
401      }
402  
403      private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>();
404  
405      /**
406       * Callback for notifying activities.
407       */
408      public interface ActivityConfigCallback {
409  
410          /**
411           * Notifies about override config change and/or move to different display.
412           * @param overrideConfig New override config to apply to activity.
413           * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed.
414           */
onConfigurationChanged(Configuration overrideConfig, int newDisplayId)415          void onConfigurationChanged(Configuration overrideConfig, int newDisplayId);
416  
417          /**
418           * Notify the corresponding activity about the request to show or hide a camera compat
419           * control for stretched issues in the viewfinder.
420           *
421           * @param showControl Whether the control should be shown or hidden.
422           * @param transformationApplied Whether the treatment is already applied.
423           * @param callback The callback executed when the user clicks on a control.
424           */
requestCompatCameraControl(boolean showControl, boolean transformationApplied, ICompatCameraControlCallback callback)425          void requestCompatCameraControl(boolean showControl, boolean transformationApplied,
426                  ICompatCameraControlCallback callback);
427      }
428  
429      /**
430       * Used to notify if the user is typing or not.
431       * @hide
432       */
433      public interface TypingHintNotifier {
434          /**
435           * Called when the typing hint is changed. This would be invoked by the
436           * {@link android.view.inputmethod.RemoteInputConnectionImpl}
437           * to hint if the user is typing when it is {@link #isActive() active}.
438           *
439           * The operation in this method should be dispatched to the UI thread to
440           * keep the sequence.
441           *
442           * @param isTyping {@code true} if the user is typing.
443           * @param deactivate {code true} if the input connection deactivate
444           */
onTypingHintChanged(boolean isTyping, boolean deactivate)445          void onTypingHintChanged(boolean isTyping, boolean deactivate);
446  
447          /**
448           * Indicates whether the notifier is currently in active state or not.
449           *
450           * @see #deactivate()
451           */
isActive()452          boolean isActive();
453  
454          /**
455           * Deactivate the notifier when no longer in use. Mostly invoked when finishing the typing.
456           */
deactivate()457          void deactivate();
458      }
459  
460      /**
461       * The {@link TypingHintNotifier} implementation used to handle
462       * the refresh rate preference when the typing state is changed.
463       */
464      private static class TypingHintNotifierImpl implements TypingHintNotifier {
465  
466          private final AtomicReference<TypingHintNotifier> mActiveNotifier;
467  
468          @NonNull
469          private final ViewRootRefreshRateController mController;
470  
471          @NonNull
472          private final Handler mHandler;
473  
474          @NonNull
475          private final Thread mThread;
476  
TypingHintNotifierImpl(@onNull AtomicReference<TypingHintNotifier> notifier, @NonNull ViewRootRefreshRateController controller, @NonNull Handler handler, @NonNull Thread thread)477          TypingHintNotifierImpl(@NonNull AtomicReference<TypingHintNotifier> notifier,
478                  @NonNull ViewRootRefreshRateController controller, @NonNull Handler handler,
479                  @NonNull Thread thread) {
480              mController = controller;
481              mActiveNotifier = notifier;
482              mHandler = handler;
483              mThread = thread;
484          }
485  
486          @Override
onTypingHintChanged(boolean isTyping, boolean deactivate)487          public void onTypingHintChanged(boolean isTyping, boolean deactivate) {
488              final Runnable runnable = () -> {
489                  if (!isActive()) {
490                      // No-op when the listener was deactivated.
491                      return;
492                  }
493                  mController.updateRefreshRatePreference(isTyping ? LOWER : RESTORE);
494                  if (deactivate) {
495                      deactivate();
496                  }
497              };
498  
499              if (Thread.currentThread() == mThread) {
500                  // Run directly if it's on the UiThread.
501                  runnable.run();
502              } else {
503                  mHandler.post(runnable);
504              }
505          }
506  
507          @Override
isActive()508          public boolean isActive() {
509              return mActiveNotifier.get() == this;
510          }
511  
512          @Override
deactivate()513          public void deactivate() {
514              mActiveNotifier.compareAndSet(this, null);
515          }
516      }
517  
518      /**
519       * Callback used to notify corresponding activity about camera compat control changes, override
520       * configuration change and make sure that all resources are set correctly before updating the
521       * ViewRootImpl's internal state.
522       */
523      private ActivityConfigCallback mActivityConfigCallback;
524  
525      /**
526       * The current active {@link TypingHintNotifier} to handle
527       * typing hint change operations.
528       */
529      private final AtomicReference<TypingHintNotifier> mActiveTypingHintNotifier =
530              new AtomicReference<>(null);
531  
532      /**
533       * Create a {@link TypingHintNotifier} if the client support variable
534       * refresh rate for typing. The {@link TypingHintNotifier} is created
535       * and mapped to a new active input connection each time.
536       *
537       * @hide
538       */
539      @Nullable
createTypingHintNotifierIfSupported()540      public TypingHintNotifier createTypingHintNotifierIfSupported() {
541          if (mRefreshRateController == null) {
542              return null;
543          }
544          final TypingHintNotifier newNotifier = new TypingHintNotifierImpl(mActiveTypingHintNotifier,
545                  mRefreshRateController, mHandler, mThread);
546          mActiveTypingHintNotifier.set(newNotifier);
547  
548          return newNotifier;
549      }
550  
551      /**
552       * Used when configuration change first updates the config of corresponding activity.
553       * In that case we receive a call back from {@link ActivityThread} and this flag is used to
554       * preserve the initial value.
555       *
556       * @see #performConfigurationChange(MergedConfiguration, boolean, int)
557       */
558      private boolean mForceNextConfigUpdate;
559  
560      private boolean mUseBLASTAdapter;
561      private boolean mForceDisableBLAST;
562  
563      /** lazily-initialized in getAudioManager() */
564      private boolean mFastScrollSoundEffectsEnabled = false;
565  
566      /**
567       * Signals that compatibility booleans have been initialized according to
568       * target SDK versions.
569       */
570      private static boolean sCompatibilityDone = false;
571  
572      /**
573       * Always assign focus if a focusable View is available.
574       */
575      private static boolean sAlwaysAssignFocus;
576  
577      /**
578       * This list must only be modified by the main thread.
579       */
580      final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
581      @UnsupportedAppUsage
582      @UiContext
583      public final Context mContext;
584  
585      @UnsupportedAppUsage
586      final IWindowSession mWindowSession;
587      @NonNull Display mDisplay;
588      final String mBasePackageName;
589  
590      // If we would like to keep a particular eye on the corresponding package.
591      final boolean mExtraDisplayListenerLogging;
592  
593      final int[] mTmpLocation = new int[2];
594  
595      final TypedValue mTmpValue = new TypedValue();
596  
597      final Thread mThread;
598  
599      final WindowLeaked mLocation;
600  
601      public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
602  
603      final W mWindow;
604  
605      final IBinder mLeashToken;
606  
607      final int mTargetSdkVersion;
608  
609      @UnsupportedAppUsage
610      View mView;
611  
612      View mAccessibilityFocusedHost;
613      // Accessibility-focused virtual view. The bounds and sourceNodeId of
614      // mAccessibilityFocusedVirtualView is up-to-date while other fields may be stale.
615      AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
616  
617      // True if the window currently has pointer capture enabled.
618      boolean mPointerCapture;
619  
620      int mViewVisibility;
621      boolean mAppVisible = true;
622      // For recents to freeform transition we need to keep drawing after the app receives information
623      // that it became invisible. This will ignore that information and depend on the decor view
624      // visibility to control drawing. The decor view visibility will get adjusted when the app get
625      // stopped and that's when the app will stop drawing further frames.
626      private boolean mForceDecorViewVisibility = false;
627      // Used for tracking app visibility updates separately in case we get double change. This will
628      // make sure that we always call relayout for the corresponding window.
629      private boolean mAppVisibilityChanged;
630      int mOrigWindowType = -1;
631  
632      // Set to true if the owner of this window is in the stopped state,
633      // so the window should no longer be active.
634      @UnsupportedAppUsage
635      boolean mStopped = false;
636  
637      // Set to true if the owner of this window is in ambient mode,
638      // which means it won't receive input events.
639      boolean mIsAmbientMode = false;
640  
641      // Set to true to stop input during an Activity Transition.
642      boolean mPausedForTransition = false;
643  
644      boolean mLastInCompatMode = false;
645  
646      SurfaceHolder.Callback2 mSurfaceHolderCallback;
647      BaseSurfaceHolder mSurfaceHolder;
648      boolean mIsCreating;
649      boolean mDrawingAllowed;
650  
651      final Region mTransparentRegion;
652      final Region mPreviousTransparentRegion;
653  
654      Region mTouchableRegion;
655      Region mPreviousTouchableRegion;
656  
657      private int mMeasuredWidth;
658      private int mMeasuredHeight;
659  
660      // This indicates that we've already known the window size but without measuring the views.
661      // If this is true, we must measure the views before laying out them.
662      private boolean mViewMeasureDeferred;
663  
664      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
665      int mWidth;
666      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
667      int mHeight;
668      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
669      private Rect mDirty;
670      public boolean mIsAnimating;
671  
672      private boolean mUseMTRenderer;
673      private boolean mPendingDragResizing;
674      private boolean mDragResizing;
675      private boolean mInvalidateRootRequested;
676      private int mCanvasOffsetX;
677      private int mCanvasOffsetY;
678      CompatibilityInfo.Translator mTranslator;
679  
680      @UnsupportedAppUsage
681      final View.AttachInfo mAttachInfo;
682      final SystemUiVisibilityInfo mCompatibleVisibilityInfo;
683      int mDispatchedSystemUiVisibility;
684      int mDispatchedSystemBarAppearance;
685      InputQueue.Callback mInputQueueCallback;
686      InputQueue mInputQueue;
687      @UnsupportedAppUsage
688      FallbackEventHandler mFallbackEventHandler;
689      final Choreographer mChoreographer;
690      protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo();
691      private final InputEventAssigner mInputEventAssigner = new InputEventAssigner();
692  
693      // Whether to draw this surface as DISPLAY_DECORATION.
694      boolean mDisplayDecorationCached = false;
695  
696      // Is the stylus pointer icon enabled
697      private final boolean mIsStylusPointerIconEnabled;
698  
699      /**
700       * Update the Choreographer's FrameInfo object with the timing information for the current
701       * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next
702       * frame.
703       * @return the updated FrameInfo object
704       */
getUpdatedFrameInfo()705      protected @NonNull FrameInfo getUpdatedFrameInfo() {
706          // Since Choreographer is a thread-local singleton while we can have multiple
707          // ViewRootImpl's, populate the frame information from the current viewRootImpl before
708          // starting the draw
709          FrameInfo frameInfo = mChoreographer.mFrameInfo;
710          mViewFrameInfo.populateFrameInfo(frameInfo);
711          mViewFrameInfo.reset();
712          mInputEventAssigner.notifyFrameProcessed();
713          return frameInfo;
714      }
715  
716      // used in relayout to get SurfaceControl size
717      // for BLAST adapter surface setup
718      private final Point mSurfaceSize = new Point();
719      private final Point mLastSurfaceSize = new Point();
720  
721      private final Rect mVisRect = new Rect(); // used to retrieve visible rect of focused view.
722      private final Rect mTempRect = new Rect();
723  
724      private final WindowLayout mWindowLayout;
725  
726      // This is used to reduce the race between window focus changes being dispatched from
727      // the window manager and input events coming through the input system.
728      @GuardedBy("this")
729      boolean mWindowFocusChanged;
730      @GuardedBy("this")
731      boolean mUpcomingWindowFocus;
732      @GuardedBy("this")
733      boolean mUpcomingInTouchMode;
734  
735      public boolean mTraversalScheduled;
736      int mTraversalBarrier;
737      boolean mWillDrawSoon;
738      /** Set to true while in performTraversals for detecting when die(true) is called from internal
739       * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
740      boolean mIsInTraversal;
741      boolean mApplyInsetsRequested;
742      boolean mLayoutRequested;
743      boolean mFirst;
744  
745      @Nullable
746      int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
747      boolean mPerformContentCapture;
748  
749      boolean mReportNextDraw;
750      /** Set only while mReportNextDraw=true, indicating the last reason that was triggered */
751      String mLastReportNextDrawReason;
752      /** The reaason the last call to performDraw() returned false */
753      String mLastPerformDrawSkippedReason;
754      /** The reason the last call to performTraversals() returned without drawing */
755      String mLastPerformTraversalsSkipDrawReason;
756      /** The state of the WMS requested sync, if one is in progress. Can be one of the states
757       * below. */
758      int mWmsRequestSyncGroupState;
759  
760      // The possible states of the WMS requested sync, see createSyncIfNeeded()
761      private static final int WMS_SYNC_NONE = 0;
762      private static final int WMS_SYNC_PENDING = 1;
763      private static final int WMS_SYNC_RETURNED = 2;
764      private static final int WMS_SYNC_MERGED = 3;
765  
766      /**
767       * Set whether the requested SurfaceSyncGroup should sync the buffer. When set to true, VRI will
768       * create a sync transaction with BBQ and send the resulting buffer back to the
769       * SurfaceSyncGroup. If false, VRI will not try to sync a buffer in BBQ, but still report when a
770       * draw occurred.
771       */
772      private boolean mSyncBuffer = false;
773  
774      /**
775       * Flag to determine whether the client needs to check with WMS if it can draw. WMS will notify
776       * the client that it can't draw if we're still in the middle of a sync set that includes this
777       * window. Once the sync is complete, the window can resume drawing. This is to ensure we don't
778       * deadlock the client by trying to request draws when there may not be any buffers available.
779       */
780      private boolean mCheckIfCanDraw = false;
781  
782      private boolean mDrewOnceForSync = false;
783  
784      int mSyncSeqId = 0;
785      int mLastSyncSeqId = 0;
786  
787      private boolean mUpdateSurfaceNeeded;
788      boolean mFullRedrawNeeded;
789      boolean mNewSurfaceNeeded;
790      boolean mForceNextWindowRelayout;
791      CountDownLatch mWindowDrawCountDown;
792  
793      /**
794       * Value to indicate whether someone has called {@link #applyTransactionOnDraw}before the
795       * traversal. This is used to determine whether a RT frame callback needs to be registered to
796       * merge the transaction with the next frame. The value is cleared after the VRI has run a
797       * traversal pass.
798       */
799      boolean mHasPendingTransactions;
800      /**
801       * The combined transactions passed in from {@link #applyTransactionOnDraw}
802       */
803      private Transaction mPendingTransaction = new Transaction();
804  
805  
806      boolean mIsDrawing;
807      int mLastSystemUiVisibility;
808      int mClientWindowLayoutFlags;
809  
810      // Pool of queued input events.
811      private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
812      private QueuedInputEvent mQueuedInputEventPool;
813      private int mQueuedInputEventPoolSize;
814  
815      /* Input event queue.
816       * Pending input events are input events waiting to be delivered to the input stages
817       * and handled by the application.
818       */
819      QueuedInputEvent mPendingInputEventHead;
820      QueuedInputEvent mPendingInputEventTail;
821      int mPendingInputEventCount;
822      boolean mProcessInputEventsScheduled;
823      boolean mUnbufferedInputDispatch;
824      @InputSourceClass
825      int mUnbufferedInputSource = SOURCE_CLASS_NONE;
826  
827      String mPendingInputEventQueueLengthCounterName = "pq";
828  
829      InputStage mFirstInputStage;
830      InputStage mFirstPostImeInputStage;
831      InputStage mSyntheticInputStage;
832  
833      private final UnhandledKeyManager mUnhandledKeyManager = new UnhandledKeyManager();
834  
835      boolean mWindowAttributesChanged = false;
836  
837      // These can be accessed by any thread, must be protected with a lock.
838      // Surface can never be reassigned or cleared (use Surface.clear()).
839      @UnsupportedAppUsage
840      public final Surface mSurface = new Surface();
841      private final SurfaceControl mSurfaceControl = new SurfaceControl();
842  
843      private BLASTBufferQueue mBlastBufferQueue;
844  
845      private boolean mUpdateHdrSdrRatioInfo = false;
846      private float mDesiredHdrSdrRatio = 1f;
847      private float mRenderHdrSdrRatio = 1f;
848      private Consumer<Display> mHdrSdrRatioChangedListener = null;
849  
850      /**
851       * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to
852       * the surface insets. This surface is created only if a client requests it via
853       * {@link #updateAndGetBoundsLayer(Transaction)}. By parenting to this bounds surface, child
854       * surfaces can ensure they do not draw into the surface inset region set by the parent window.
855       */
856      private SurfaceControl mBoundsLayer;
857      private final SurfaceSession mSurfaceSession = new SurfaceSession();
858      private final Transaction mTransaction = new Transaction();
859  
860      @UnsupportedAppUsage
861      boolean mAdded;
862      boolean mAddedTouchMode;
863  
864      /**
865       * It usually keeps the latest layout result from {@link IWindow#resized} or
866       * {@link IWindowSession#relayout}.
867       */
868      private final ClientWindowFrames mTmpFrames = new ClientWindowFrames();
869  
870      // These are accessed by multiple threads.
871      final Rect mWinFrame; // frame given by window manager.
872      private final Rect mLastLayoutFrame;
873      Rect mOverrideInsetsFrame;
874  
875      final Rect mPendingBackDropFrame = new Rect();
876  
877      boolean mPendingAlwaysConsumeSystemBars;
878      private int mRelayoutSeq;
879      private final Rect mWinFrameInScreen = new Rect();
880      private final InsetsState mTempInsets = new InsetsState();
881      private final InsetsSourceControl.Array mTempControls = new InsetsSourceControl.Array();
882      private final WindowConfiguration mTempWinConfig = new WindowConfiguration();
883      private float mInvCompatScale = 1f;
884      final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
885              = new ViewTreeObserver.InternalInsetsInfo();
886  
887      private WindowInsets mLastWindowInsets;
888  
889      // Insets types hidden by legacy window flags or system UI flags.
890      private @InsetsType int mTypesHiddenByFlags = 0;
891  
892      /** Last applied configuration obtained from resources. */
893      private final Configuration mLastConfigurationFromResources = new Configuration();
894      /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */
895      private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration();
896      /** Configurations waiting to be applied. */
897      private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration();
898  
899      boolean mScrollMayChange;
900      @SoftInputModeFlags
901      int mSoftInputMode;
902      @UnsupportedAppUsage
903      WeakReference<View> mLastScrolledFocus;
904      int mScrollY;
905      int mCurScrollY;
906      Scroller mScroller;
907      static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
908      private ArrayList<LayoutTransition> mPendingTransitions;
909  
910      final ViewConfiguration mViewConfiguration;
911  
912      /* Drag/drop */
913      ClipDescription mDragDescription;
914      View mCurrentDragView;
915      View mStartedDragViewForA11y;
916      volatile Object mLocalDragState;
917      final PointF mDragPoint = new PointF();
918      final PointF mLastTouchPoint = new PointF();
919      int mLastTouchSource;
920      /** Tracks last {@link MotionEvent#getToolType(int)} with {@link MotionEvent#ACTION_UP}. **/
921      private int mLastClickToolType;
922  
923      private boolean mProfileRendering;
924      private Choreographer.FrameCallback mRenderProfiler;
925      private boolean mRenderProfilingEnabled;
926  
927      // Variables to track frames per second, enabled via DEBUG_FPS flag
928      private long mFpsStartTime = -1;
929      private long mFpsPrevTime = -1;
930      private int mFpsNumFrames;
931  
932      /**
933       * The resolved pointer icon type requested by this window.
934       * A null value indicates the resolved pointer icon has not yet been calculated.
935       */
936      @Nullable
937      private Integer mPointerIconType = null;
938      private PointerIcon mCustomPointerIcon = null;
939  
940      /**
941       * see {@link #playSoundEffect(int)}
942       */
943      AudioManager mAudioManager;
944  
945      final AccessibilityManager mAccessibilityManager;
946  
947      AccessibilityInteractionController mAccessibilityInteractionController;
948  
949      final AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager =
950              new AccessibilityInteractionConnectionManager();
951      final HighContrastTextManager mHighContrastTextManager;
952  
953      SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
954  
955      HashSet<View> mTempHashSet;
956  
957      private final int mDensity;
958      private final int mNoncompatDensity;
959  
960      private boolean mInLayout = false;
961      ArrayList<View> mLayoutRequesters = new ArrayList<View>();
962      boolean mHandlingLayoutInLayoutRequest = false;
963  
964      private int mViewLayoutDirectionInitial;
965  
966      /** Set to true once doDie() has been called. */
967      private boolean mRemoved;
968  
969      private boolean mNeedsRendererSetup;
970  
971      private final InputEventCompatProcessor mInputCompatProcessor;
972  
973      /**
974       * Consistency verifier for debugging purposes.
975       */
976      protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
977              InputEventConsistencyVerifier.isInstrumentationEnabled() ?
978                      new InputEventConsistencyVerifier(this, 0) : null;
979  
980      private final InsetsController mInsetsController;
981      private final ImeFocusController mImeFocusController;
982  
983      private ViewRootRefreshRateController mRefreshRateController;
984  
985      private boolean mIsSurfaceOpaque;
986  
987      private final BackgroundBlurDrawable.Aggregator mBlurRegionAggregator =
988              new BackgroundBlurDrawable.Aggregator(this);
989  
990      /**
991       * @return {@link ImeFocusController} for this instance.
992       */
993      @NonNull
getImeFocusController()994      public ImeFocusController getImeFocusController() {
995          return mImeFocusController;
996      }
997  
998      private final ViewRootRectTracker mGestureExclusionTracker =
999              new ViewRootRectTracker(v -> v.getSystemGestureExclusionRects());
1000      private final ViewRootRectTracker mKeepClearRectsTracker =
1001              new ViewRootRectTracker(v -> v.collectPreferKeepClearRects());
1002      private final ViewRootRectTracker mUnrestrictedKeepClearRectsTracker =
1003              new ViewRootRectTracker(v -> v.collectUnrestrictedPreferKeepClearRects());
1004      private boolean mHasPendingKeepClearAreaChange;
1005      private Rect mKeepClearAccessibilityFocusRect;
1006  
1007      private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
1008  
1009      static final class SystemUiVisibilityInfo {
1010          int globalVisibility;
1011          int localValue;
1012          int localChanges;
1013      }
1014  
1015      private final HandwritingInitiator mHandwritingInitiator;
1016  
1017      /**
1018       * Used by InputMethodManager.
1019       * @hide
1020       */
1021      @NonNull
getHandwritingInitiator()1022      public HandwritingInitiator getHandwritingInitiator() {
1023          return mHandwritingInitiator;
1024      }
1025  
1026      /**
1027       * A SurfaceSyncGroup that is created when WMS requested to sync the buffer
1028       */
1029      private SurfaceSyncGroup mWmsRequestSyncGroup;
1030  
1031      /**
1032       * The SurfaceSyncGroup that represents the active VRI SurfaceSyncGroup. This is non null if
1033       * anyone requested the SurfaceSyncGroup for this VRI to ensure that anyone trying to sync with
1034       * this VRI are collected together. The SurfaceSyncGroup is cleared when the VRI draws since
1035       * that is the stop point where all changes are have been applied. A new SurfaceSyncGroup is
1036       * created after that point when something wants to sync VRI again.
1037       */
1038      private SurfaceSyncGroup mActiveSurfaceSyncGroup;
1039  
1040  
1041      private final Object mPreviousSyncSafeguardLock = new Object();
1042  
1043      /**
1044       * Wraps the TransactionCommitted callback for the previous SSG so it can be added to the next
1045       * SSG if started before previous has completed.
1046       */
1047      @GuardedBy("mPreviousSyncSafeguardLock")
1048      private SurfaceSyncGroup mPreviousSyncSafeguard;
1049  
1050      private static final Object sSyncProgressLock = new Object();
1051      // The count needs to be static since it's used to enable or disable RT animations which is
1052      // done at a global level per process. If any VRI syncs are in progress, we can't enable RT
1053      // animations until all are done.
1054      private static int sNumSyncsInProgress = 0;
1055  
1056      private int mNumPausedForSync = 0;
1057  
1058      private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
1059  
1060      private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
1061  
1062      /**
1063       * Increment this value when the surface has been replaced.
1064       */
1065      private int mSurfaceSequenceId = 0;
1066  
1067      private boolean mRelayoutRequested;
1068  
1069      /**
1070       * Whether sandboxing of {@link android.view.View#getBoundsOnScreen},
1071       * {@link android.view.View#getLocationOnScreen(int[])},
1072       * {@link android.view.View#getWindowDisplayFrame} and
1073       * {@link android.view.View#getWindowVisibleDisplayFrame}
1074       * within Activity bounds is enabled for the current application.
1075       */
1076      private final boolean mViewBoundsSandboxingEnabled;
1077  
1078      private int mLastTransformHint = Integer.MIN_VALUE;
1079  
1080      private AccessibilityWindowAttributes mAccessibilityWindowAttributes;
1081  
1082      /**
1083       * A temporary object used so relayoutWindow can return the latest SyncSeqId
1084       * system. The SyncSeqId system was designed to work without synchronous relayout
1085       * window, and actually synchronous relayout window presents a problem.  We could have
1086       * a sequence like this:
1087       *    1. We send MSG_RESIZED to the client with a new syncSeqId to begin a new sync
1088       *    2. Due to scheduling the client executes performTraversals before calling MSG_RESIZED
1089       *    3. Coincidentally for some random reason it also calls relayout
1090       *    4. It observes the new state from relayout, and so the next frame will contain the state
1091       * However it hasn't received the seqId yet, and so under the designed operation of
1092       * seqId flowing through MSG_RESIZED, the next frame wouldn't be synced. Since it
1093       * contains our target sync state, we need to sync it! This problem won't come up once
1094       * we get rid of synchronous relayout, until then, we use this bundle to channel the
1095       * integer back over relayout.
1096       */
1097      private Bundle mRelayoutBundle = new Bundle();
1098  
1099      private static volatile boolean sAnrReported = false;
1100      static BLASTBufferQueue.TransactionHangCallback sTransactionHangCallback =
1101          new BLASTBufferQueue.TransactionHangCallback() {
1102              @Override
1103              public void onTransactionHang(String reason) {
1104                  if (sAnrReported) {
1105                      return;
1106                  }
1107  
1108                  sAnrReported = true;
1109                  // If we're making an in-process call to ActivityManagerService
1110                  // and the previous binder call on this thread was oneway, the
1111                  // calling PID will be 0. Clearing the calling identity fixes
1112                  // this and ensures ActivityManager gets the correct calling
1113                  // pid.
1114                  final long identityToken = Binder.clearCallingIdentity();
1115                  try {
1116                      ActivityManager.getService().appNotResponding(reason);
1117                  } catch (RemoteException e) {
1118                      // We asked the system to crash us, but the system
1119                      // already crashed. Unfortunately things may be
1120                      // out of control.
1121                  } finally {
1122                      Binder.restoreCallingIdentity(identityToken);
1123                  }
1124              }
1125          };
1126      private final Rect mChildBoundingInsets = new Rect();
1127      private boolean mChildBoundingInsetsChanged = false;
1128  
1129      private String mTag = TAG;
1130  
ViewRootImpl(Context context, Display display)1131      public ViewRootImpl(Context context, Display display) {
1132          this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout());
1133      }
1134  
ViewRootImpl(@iContext Context context, Display display, IWindowSession session, WindowLayout windowLayout)1135      public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
1136              WindowLayout windowLayout) {
1137          mContext = context;
1138          mWindowSession = session;
1139          mWindowLayout = windowLayout;
1140          mDisplay = display;
1141          mBasePackageName = context.getBasePackageName();
1142          final String name = DisplayProperties.debug_vri_package().orElse(null);
1143          mExtraDisplayListenerLogging = !TextUtils.isEmpty(name) && name.equals(mBasePackageName);
1144          mThread = Thread.currentThread();
1145          mLocation = new WindowLeaked(null);
1146          mLocation.fillInStackTrace();
1147          mWidth = -1;
1148          mHeight = -1;
1149          mDirty = new Rect();
1150          mWinFrame = new Rect();
1151          mLastLayoutFrame = new Rect();
1152          mWindow = new W(this);
1153          mLeashToken = new Binder();
1154          mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
1155          mViewVisibility = View.GONE;
1156          mTransparentRegion = new Region();
1157          mPreviousTransparentRegion = new Region();
1158          mFirst = true; // true for the first time the view is added
1159          mPerformContentCapture = true; // also true for the first time the view is added
1160          mAdded = false;
1161          mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
1162                  context);
1163          mCompatibleVisibilityInfo = new SystemUiVisibilityInfo();
1164          mAccessibilityManager = AccessibilityManager.getInstance(context);
1165          mHighContrastTextManager = new HighContrastTextManager();
1166          mViewConfiguration = ViewConfiguration.get(context);
1167          mDensity = context.getResources().getDisplayMetrics().densityDpi;
1168          mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
1169          mFallbackEventHandler = new PhoneFallbackEventHandler(context);
1170          // TODO(b/222696368): remove getSfInstance usage and use vsyncId for transactions
1171          mChoreographer = Choreographer.getInstance();
1172          mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));
1173          mHandwritingInitiator = new HandwritingInitiator(
1174                  mViewConfiguration,
1175                  mContext.getSystemService(InputMethodManager.class));
1176  
1177          // Whether the variable refresh rate for typing is supported.
1178          boolean useVariableRefreshRateWhenTyping = context.getResources().getBoolean(
1179                  R.bool.config_variableRefreshRateTypingSupported);
1180          if (useVariableRefreshRateWhenTyping) {
1181              mRefreshRateController = new ViewRootRefreshRateController(this);
1182          }
1183  
1184          mViewBoundsSandboxingEnabled = getViewBoundsSandboxingEnabled();
1185          mIsStylusPointerIconEnabled =
1186                  InputSettings.isStylusPointerIconEnabled(mContext);
1187  
1188          String processorOverrideName = context.getResources().getString(
1189                                      R.string.config_inputEventCompatProcessorOverrideClassName);
1190          if (processorOverrideName.isEmpty()) {
1191              // No compatibility processor override, using default.
1192              mInputCompatProcessor = new InputEventCompatProcessor(context);
1193          } else {
1194              InputEventCompatProcessor compatProcessor = null;
1195              try {
1196                  final Class<? extends InputEventCompatProcessor> klass =
1197                          (Class<? extends InputEventCompatProcessor>) Class.forName(
1198                                  processorOverrideName);
1199                  compatProcessor = klass.getConstructor(Context.class).newInstance(context);
1200              } catch (Exception e) {
1201                  Log.e(TAG, "Unable to create the InputEventCompatProcessor. ", e);
1202              } finally {
1203                  mInputCompatProcessor = compatProcessor;
1204              }
1205          }
1206  
1207          if (!sCompatibilityDone) {
1208              sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
1209  
1210              sCompatibilityDone = true;
1211          }
1212  
1213          loadSystemProperties();
1214          mImeFocusController = new ImeFocusController(this);
1215  
1216          mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
1217          mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context);
1218      }
1219  
1220      public static void addFirstDrawHandler(Runnable callback) {
1221          synchronized (sFirstDrawHandlers) {
1222              if (!sFirstDrawComplete) {
1223                  sFirstDrawHandlers.add(callback);
1224              }
1225          }
1226      }
1227  
1228      /** Add static config callback to be notified about global config changes. */
1229      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1230      public static void addConfigCallback(ConfigChangedCallback callback) {
1231          synchronized (sConfigCallbacks) {
1232              sConfigCallbacks.add(callback);
1233          }
1234      }
1235  
1236      /** Remove a static config callback. */
1237      public static void removeConfigCallback(ConfigChangedCallback callback) {
1238          synchronized (sConfigCallbacks) {
1239              sConfigCallbacks.remove(callback);
1240          }
1241      }
1242  
1243      /**
1244       * Add activity config callback to be notified about override config changes and camera
1245       * compat control state updates.
1246       */
1247      public void setActivityConfigCallback(ActivityConfigCallback callback) {
1248          mActivityConfigCallback = callback;
1249      }
1250  
1251      public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
1252          mAttachInfo.mContentOnApplyWindowInsetsListener = listener;
1253  
1254          // System windows will be fitted on first traversal, so no reason to request additional
1255          // (possibly getting executed after the first traversal).
1256          if (!mFirst) {
1257              requestFitSystemWindows();
1258          }
1259      }
1260  
1261      public void addWindowCallbacks(WindowCallbacks callback) {
1262          mWindowCallbacks.add(callback);
1263      }
1264  
1265      public void removeWindowCallbacks(WindowCallbacks callback) {
1266          mWindowCallbacks.remove(callback);
1267      }
1268  
1269      public void reportDrawFinish() {
1270          if (mWindowDrawCountDown != null) {
1271              mWindowDrawCountDown.countDown();
1272          }
1273      }
1274  
1275      // FIXME for perf testing only
1276      private boolean mProfile = false;
1277  
1278      /**
1279       * Call this to profile the next traversal call.
1280       * FIXME for perf testing only. Remove eventually
1281       */
1282      public void profile() {
1283          mProfile = true;
1284      }
1285  
1286      private boolean isInTouchMode() {
1287          IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService();
1288          if (windowManager != null) {
1289              try {
1290                  return windowManager.isInTouchMode(getDisplayId());
1291              } catch (RemoteException e) {
1292              }
1293          }
1294          return false;
1295      }
1296  
1297      /**
1298       * Notifies us that our child has been rebuilt, following
1299       * a window preservation operation. In these cases we
1300       * keep the same DecorView, but the activity controlling it
1301       * is a different instance, and we need to update our
1302       * callbacks.
1303       *
1304       * @hide
1305       */
1306      public void notifyChildRebuilt() {
1307          if (mView instanceof RootViewSurfaceTaker) {
1308              if (mSurfaceHolderCallback != null) {
1309                  mSurfaceHolder.removeCallback(mSurfaceHolderCallback);
1310              }
1311  
1312              mSurfaceHolderCallback =
1313                  ((RootViewSurfaceTaker)mView).willYouTakeTheSurface();
1314  
1315              if (mSurfaceHolderCallback != null) {
1316                  mSurfaceHolder = new TakenSurfaceHolder();
1317                  mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
1318                  mSurfaceHolder.addCallback(mSurfaceHolderCallback);
1319              } else {
1320                  mSurfaceHolder = null;
1321              }
1322  
1323              mInputQueueCallback =
1324                  ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue();
1325              if (mInputQueueCallback != null) {
1326                  mInputQueueCallback.onInputQueueCreated(mInputQueue);
1327              }
1328          }
1329  
1330          // Update the last resource config in case the resource configuration was changed while
1331          // activity relaunched.
1332          updateLastConfigurationFromResources(getConfiguration());
1333          // Make sure to report the completion of draw for relaunch with preserved window.
1334          reportNextDraw("rebuilt");
1335          // Make sure to resume this root view when relaunching its host activity which was stopped.
1336          if (mStopped) {
1337              setWindowStopped(false);
1338          }
1339      }
1340  
1341      private Configuration getConfiguration() {
1342          return mContext.getResources().getConfiguration();
1343      }
1344  
1345      private WindowConfiguration getCompatWindowConfiguration() {
1346          final WindowConfiguration winConfig = getConfiguration().windowConfiguration;
1347          if (mInvCompatScale == 1f) {
1348              return winConfig;
1349          }
1350          mTempWinConfig.setTo(winConfig);
1351          mTempWinConfig.scale(mInvCompatScale);
1352          return mTempWinConfig;
1353      }
1354  
1355      /**
1356       * We have one child
1357       */
1358      public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
1359          setView(view, attrs, panelParentView, UserHandle.myUserId());
1360      }
1361  
1362      /**
1363       * We have one child
1364       */
1365      public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
1366              int userId) {
1367          synchronized (this) {
1368              if (mView == null) {
1369                  mView = view;
1370  
1371                  mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
1372                  mFallbackEventHandler.setView(view);
1373                  mWindowAttributes.copyFrom(attrs);
1374                  if (mWindowAttributes.packageName == null) {
1375                      mWindowAttributes.packageName = mBasePackageName;
1376                  }
1377                  mWindowAttributes.privateFlags |=
1378                          WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
1379  
1380                  attrs = mWindowAttributes;
1381                  setTag();
1382  
1383                  if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
1384                          & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
1385                          && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
1386                      Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
1387                  }
1388                  // Keep track of the actual window flags supplied by the client.
1389                  mClientWindowLayoutFlags = attrs.flags;
1390  
1391                  setAccessibilityFocus(null, null);
1392  
1393                  if (view instanceof RootViewSurfaceTaker) {
1394                      mSurfaceHolderCallback =
1395                              ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
1396                      if (mSurfaceHolderCallback != null) {
1397                          mSurfaceHolder = new TakenSurfaceHolder();
1398                          mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
1399                          mSurfaceHolder.addCallback(mSurfaceHolderCallback);
1400                      }
1401                  }
1402  
1403                  // Compute surface insets required to draw at specified Z value.
1404                  // TODO: Use real shadow insets for a constant max Z.
1405                  if (!attrs.hasManualSurfaceInsets) {
1406                      attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
1407                  }
1408  
1409                  CompatibilityInfo compatibilityInfo =
1410                          mDisplay.getDisplayAdjustments().getCompatibilityInfo();
1411                  mTranslator = compatibilityInfo.getTranslator();
1412  
1413                  // If the application owns the surface, don't enable hardware acceleration
1414                  if (mSurfaceHolder == null) {
1415                      // While this is supposed to enable only, it can effectively disable
1416                      // the acceleration too.
1417                      enableHardwareAcceleration(attrs);
1418                      final boolean useMTRenderer = MT_RENDERER_AVAILABLE
1419                              && mAttachInfo.mThreadedRenderer != null;
1420                      if (mUseMTRenderer != useMTRenderer) {
1421                          // Shouldn't be resizing, as it's done only in window setup,
1422                          // but end just in case.
1423                          endDragResizing();
1424                          mUseMTRenderer = useMTRenderer;
1425                      }
1426                  }
1427  
1428                  boolean restore = false;
1429                  if (mTranslator != null) {
1430                      mSurface.setCompatibilityTranslator(mTranslator);
1431                      restore = true;
1432                      attrs.backup();
1433                      mTranslator.translateWindowLayout(attrs);
1434                  }
1435                  if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
1436  
1437                  if (!compatibilityInfo.supportsScreen()) {
1438                      attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
1439                      mLastInCompatMode = true;
1440                  }
1441  
1442                  mSoftInputMode = attrs.softInputMode;
1443                  mWindowAttributesChanged = true;
1444                  mAttachInfo.mRootView = view;
1445                  mAttachInfo.mScalingRequired = mTranslator != null;
1446                  mAttachInfo.mApplicationScale =
1447                          mTranslator == null ? 1.0f : mTranslator.applicationScale;
1448                  if (panelParentView != null) {
1449                      mAttachInfo.mPanelParentWindowToken
1450                              = panelParentView.getApplicationWindowToken();
1451                  }
1452                  mAdded = true;
1453                  int res; /* = WindowManagerImpl.ADD_OKAY; */
1454  
1455                  // Schedule the first layout -before- adding to the window
1456                  // manager, to make sure we do the relayout before receiving
1457                  // any other events from the system.
1458                  requestLayout();
1459                  InputChannel inputChannel = null;
1460                  if ((mWindowAttributes.inputFeatures
1461                          & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
1462                      inputChannel = new InputChannel();
1463                  }
1464                  mForceDecorViewVisibility = (mWindowAttributes.privateFlags
1465                          & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
1466  
1467                  if (mView instanceof RootViewSurfaceTaker) {
1468                      PendingInsetsController pendingInsetsController =
1469                              ((RootViewSurfaceTaker) mView).providePendingInsetsController();
1470                      if (pendingInsetsController != null) {
1471                          pendingInsetsController.replayAndAttach(mInsetsController);
1472                      }
1473                  }
1474  
1475                  try {
1476                      mOrigWindowType = mWindowAttributes.type;
1477                      mAttachInfo.mRecomputeGlobalAttributes = true;
1478                      collectViewAttributes();
1479                      adjustLayoutParamsForCompatibility(mWindowAttributes);
1480                      controlInsetsForCompatibility(mWindowAttributes);
1481  
1482                      Rect attachedFrame = new Rect();
1483                      final float[] compatScale = { 1f };
1484                      res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
1485                              getHostVisibility(), mDisplay.getDisplayId(), userId,
1486                              mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
1487                              mTempControls, attachedFrame, compatScale);
1488                      if (!attachedFrame.isValid()) {
1489                          attachedFrame = null;
1490                      }
1491                      if (mTranslator != null) {
1492                          mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
1493                          mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls.get());
1494                          mTranslator.translateRectInScreenToAppWindow(attachedFrame);
1495                      }
1496                      mTmpFrames.attachedFrame = attachedFrame;
1497                      mTmpFrames.compatScale = compatScale[0];
1498                      mInvCompatScale = 1f / compatScale[0];
1499                  } catch (RemoteException | RuntimeException e) {
1500                      mAdded = false;
1501                      mView = null;
1502                      mAttachInfo.mRootView = null;
1503                      mFallbackEventHandler.setView(null);
1504                      unscheduleTraversals();
1505                      setAccessibilityFocus(null, null);
1506                      throw new RuntimeException("Adding window failed", e);
1507                  } finally {
1508                      if (restore) {
1509                          attrs.restore();
1510                      }
1511                  }
1512  
1513                  mAttachInfo.mAlwaysConsumeSystemBars =
1514                          (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0;
1515                  mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;
1516                  mInsetsController.onStateChanged(mTempInsets);
1517                  mInsetsController.onControlsChanged(mTempControls.get());
1518                  final InsetsState state = mInsetsController.getState();
1519                  final Rect displayCutoutSafe = mTempRect;
1520                  state.getDisplayCutoutSafe(displayCutoutSafe);
1521                  final WindowConfiguration winConfig = getCompatWindowConfiguration();
1522                  mWindowLayout.computeFrames(mWindowAttributes, state,
1523                          displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
1524                          UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
1525                          mInsetsController.getRequestedVisibleTypes(), 1f /* compactScale */,
1526                          mTmpFrames);
1527                  setFrame(mTmpFrames.frame, true /* withinRelayout */);
1528                  registerBackCallbackOnWindow();
1529                  if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
1530                  if (res < WindowManagerGlobal.ADD_OKAY) {
1531                      mAttachInfo.mRootView = null;
1532                      mAdded = false;
1533                      mFallbackEventHandler.setView(null);
1534                      unscheduleTraversals();
1535                      setAccessibilityFocus(null, null);
1536                      switch (res) {
1537                          case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
1538                          case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
1539                              throw new WindowManager.BadTokenException(
1540                                      "Unable to add window -- token " + attrs.token
1541                                      + " is not valid; is your activity running?");
1542                          case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
1543                              throw new WindowManager.BadTokenException(
1544                                      "Unable to add window -- token " + attrs.token
1545                                      + " is not for an application");
1546                          case WindowManagerGlobal.ADD_APP_EXITING:
1547                              throw new WindowManager.BadTokenException(
1548                                      "Unable to add window -- app for token " + attrs.token
1549                                      + " is exiting");
1550                          case WindowManagerGlobal.ADD_DUPLICATE_ADD:
1551                              throw new WindowManager.BadTokenException(
1552                                      "Unable to add window -- window " + mWindow
1553                                      + " has already been added");
1554                          case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
1555                              // Silently ignore -- we would have just removed it
1556                              // right away, anyway.
1557                              return;
1558                          case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
1559                              throw new WindowManager.BadTokenException("Unable to add window "
1560                                      + mWindow + " -- another window of type "
1561                                      + mWindowAttributes.type + " already exists");
1562                          case WindowManagerGlobal.ADD_PERMISSION_DENIED:
1563                              throw new WindowManager.BadTokenException("Unable to add window "
1564                                      + mWindow + " -- permission denied for window type "
1565                                      + mWindowAttributes.type);
1566                          case WindowManagerGlobal.ADD_INVALID_DISPLAY:
1567                              throw new WindowManager.InvalidDisplayException("Unable to add window "
1568                                      + mWindow + " -- the specified display can not be found");
1569                          case WindowManagerGlobal.ADD_INVALID_TYPE:
1570                              throw new WindowManager.InvalidDisplayException("Unable to add window "
1571                                      + mWindow + " -- the specified window type "
1572                                      + mWindowAttributes.type + " is not valid");
1573                          case WindowManagerGlobal.ADD_INVALID_USER:
1574                              throw new WindowManager.BadTokenException("Unable to add Window "
1575                                      + mWindow + " -- requested userId is not valid");
1576                      }
1577                      throw new RuntimeException(
1578                              "Unable to add window -- unknown error code " + res);
1579                  }
1580  
1581                  registerListeners();
1582                  // We should update mAttachInfo.mDisplayState after registerDisplayListener
1583                  // because displayState might be changed before registerDisplayListener.
1584                  mAttachInfo.mDisplayState = mDisplay.getState();
1585                  if (mExtraDisplayListenerLogging) {
1586                      Slog.i(mTag, "(" + mBasePackageName + ") Initial DisplayState: "
1587                              + mAttachInfo.mDisplayState, new Throwable());
1588                  }
1589                  if ((res & WindowManagerGlobal.ADD_FLAG_USE_BLAST) != 0) {
1590                      mUseBLASTAdapter = true;
1591                  }
1592  
1593                  if (view instanceof RootViewSurfaceTaker) {
1594                      mInputQueueCallback =
1595                          ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
1596                  }
1597                  if (inputChannel != null) {
1598                      if (mInputQueueCallback != null) {
1599                          mInputQueue = new InputQueue();
1600                          mInputQueueCallback.onInputQueueCreated(mInputQueue);
1601                      }
1602                      mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
1603                              Looper.myLooper());
1604  
1605                      if (ENABLE_INPUT_LATENCY_TRACKING && mAttachInfo.mThreadedRenderer != null) {
1606                          InputMetricsListener listener = new InputMetricsListener();
1607                          mHardwareRendererObserver = new HardwareRendererObserver(
1608                                  listener, listener.data, mHandler, true /*waitForPresentTime*/);
1609                          mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
1610                      }
1611                      // Update unbuffered request when set the root view.
1612                      mUnbufferedInputSource = mView.mUnbufferedInputSource;
1613                  }
1614  
1615                  view.assignParent(this);
1616                  mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
1617                  mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
1618  
1619                  if (mAccessibilityManager.isEnabled()) {
1620                      mAccessibilityInteractionConnectionManager.ensureConnection();
1621                      setAccessibilityWindowAttributesIfNeeded();
1622                  }
1623  
1624                  if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
1625                      view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
1626                  }
1627  
1628                  // Set up the input pipeline.
1629                  CharSequence counterSuffix = attrs.getTitle();
1630                  mSyntheticInputStage = new SyntheticInputStage();
1631                  InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
1632                  InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
1633                          "aq:native-post-ime:" + counterSuffix);
1634                  InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
1635                  InputStage imeStage = new ImeInputStage(earlyPostImeStage,
1636                          "aq:ime:" + counterSuffix);
1637                  InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
1638                  InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
1639                          "aq:native-pre-ime:" + counterSuffix);
1640  
1641                  mFirstInputStage = nativePreImeStage;
1642                  mFirstPostImeInputStage = earlyPostImeStage;
1643                  mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
1644  
1645                  if (!mRemoved || !mAppVisible) {
1646                      AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
1647                  } else if (LOCAL_LOGV) {
1648                      Log.v(mTag, "setView() enabling visibility when removed");
1649                  }
1650              }
1651          }
1652      }
1653  
1654      private void setAccessibilityWindowAttributesIfNeeded() {
1655          final boolean registered = mAttachInfo.mAccessibilityWindowId
1656                  != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1657          if (registered) {
1658              final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
1659                      mWindowAttributes, mContext.getResources().getConfiguration().getLocales());
1660              if (!attributes.equals(mAccessibilityWindowAttributes)) {
1661                  mAccessibilityWindowAttributes = attributes;
1662                  mAccessibilityManager.setAccessibilityWindowAttributes(getDisplayId(),
1663                          mAttachInfo.mAccessibilityWindowId, attributes);
1664              }
1665  
1666          }
1667      }
1668  
1669      /**
1670       * Register any kind of listeners if setView was success.
1671       */
1672      private void registerListeners() {
1673          if (mExtraDisplayListenerLogging) {
1674              Slog.i(mTag, "Register listeners: " + mBasePackageName);
1675          }
1676          mAccessibilityManager.addAccessibilityStateChangeListener(
1677                  mAccessibilityInteractionConnectionManager, mHandler);
1678          mAccessibilityManager.addHighTextContrastStateChangeListener(
1679                  mHighContrastTextManager, mHandler);
1680          DisplayManagerGlobal
1681                  .getInstance()
1682                  .registerDisplayListener(
1683                          mDisplayListener,
1684                          mHandler,
1685                          DisplayManager.EVENT_FLAG_DISPLAY_ADDED
1686                          | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
1687                          | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
1688      }
1689  
1690      /**
1691       * Unregister all listeners while detachedFromWindow.
1692       */
1693      private void unregisterListeners() {
1694          mAccessibilityManager.removeAccessibilityStateChangeListener(
1695                  mAccessibilityInteractionConnectionManager);
1696          mAccessibilityManager.removeHighTextContrastStateChangeListener(
1697                  mHighContrastTextManager);
1698          DisplayManagerGlobal
1699                  .getInstance()
1700                  .unregisterDisplayListener(mDisplayListener);
1701          if (mExtraDisplayListenerLogging) {
1702              Slog.w(mTag, "Unregister listeners: " + mBasePackageName, new Throwable());
1703          }
1704      }
1705  
1706      private void setTag() {
1707          final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
1708          if (split.length > 0) {
1709              mTag =  "VRI[" + split[split.length - 1] + "]";
1710          }
1711      }
1712  
1713      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1714      public int getWindowFlags() {
1715          return mWindowAttributes.flags;
1716      }
1717  
1718      public int getDisplayId() {
1719          return mDisplay.getDisplayId();
1720      }
1721  
1722      public CharSequence getTitle() {
1723          return mWindowAttributes.getTitle();
1724      }
1725  
1726      /**
1727       * @return the width of the root view. Note that this will return {@code -1} until the first
1728       *         layout traversal, when the width is set.
1729       *
1730       * @hide
1731       */
1732      public int getWidth() {
1733          return mWidth;
1734      }
1735  
1736      /**
1737       * @return the height of the root view. Note that this will return {@code -1} until the first
1738       *         layout traversal, when the height is set.
1739       *
1740       * @hide
1741       */
1742      public int getHeight() {
1743          return mHeight;
1744      }
1745  
1746      /**
1747       * Destroys hardware rendering resources for this ViewRootImpl
1748       *
1749       * May be called on any thread
1750       */
1751      @AnyThread
1752      void destroyHardwareResources() {
1753          final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
1754          if (renderer != null) {
1755              // This is called by WindowManagerGlobal which may or may not be on the right thread
1756              if (Looper.myLooper() != mAttachInfo.mHandler.getLooper()) {
1757                  mAttachInfo.mHandler.postAtFrontOfQueue(this::destroyHardwareResources);
1758                  return;
1759              }
1760              renderer.destroyHardwareResources(mView);
1761              renderer.destroy();
1762          }
1763      }
1764  
1765      /**
1766       * Does nothing; Here only because of @UnsupportedAppUsage
1767       */
1768      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
1769              publicAlternatives = "Use {@link android.webkit.WebView} instead")
1770      public void detachFunctor(long functor) { }
1771  
1772      /**
1773       * Does nothing; Here only because of @UnsupportedAppUsage
1774       */
1775      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
1776              publicAlternatives = "Use {@link android.webkit.WebView} instead")
1777      public static void invokeFunctor(long functor, boolean waitForCompletion) { }
1778  
1779      /**
1780       * @param animator animator to register with the hardware renderer
1781       */
1782      public void registerAnimatingRenderNode(RenderNode animator) {
1783          if (mAttachInfo.mThreadedRenderer != null) {
1784              mAttachInfo.mThreadedRenderer.registerAnimatingRenderNode(animator);
1785          } else {
1786              if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
1787                  mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
1788              }
1789              mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
1790          }
1791      }
1792  
1793      /**
1794       * @param animator animator to register with the hardware renderer
1795       */
1796      public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) {
1797          if (mAttachInfo.mThreadedRenderer != null) {
1798              mAttachInfo.mThreadedRenderer.registerVectorDrawableAnimator(animator);
1799          }
1800      }
1801  
1802      /**
1803       * Registers a callback to be executed when the next frame is being drawn on RenderThread. This
1804       * callback will be executed on a RenderThread worker thread, and only used for the next frame
1805       * and thus it will only fire once.
1806       *
1807       * @param callback The callback to register.
1808       */
1809      public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) {
1810          if (mAttachInfo.mThreadedRenderer != null) {
1811              mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
1812                  @Override
1813                  public void onFrameDraw(long frame) {
1814                  }
1815  
1816                  @Override
1817                  public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult,
1818                          long frame) {
1819                      try {
1820                          return callback.onFrameDraw(syncResult, frame);
1821                      } catch (Exception e) {
1822                          Log.e(TAG, "Exception while executing onFrameDraw", e);
1823                      }
1824                      return null;
1825                  }
1826              });
1827          }
1828      }
1829  
1830      @UnsupportedAppUsage
1831      private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
1832          mAttachInfo.mHardwareAccelerated = false;
1833          mAttachInfo.mHardwareAccelerationRequested = false;
1834  
1835          // Don't enable hardware acceleration when the application is in compatibility mode
1836          if (mTranslator != null) return;
1837  
1838          // Try to enable hardware acceleration if requested
1839          final boolean hardwareAccelerated =
1840                  (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
1841  
1842          if (hardwareAccelerated) {
1843              // Persistent processes (including the system) should not do
1844              // accelerated rendering on low-end devices.  In that case,
1845              // sRendererDisabled will be set.  In addition, the system process
1846              // itself should never do accelerated rendering.  In that case, both
1847              // sRendererDisabled and sSystemRendererDisabled are set.  When
1848              // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
1849              // can be used by code on the system process to escape that and enable
1850              // HW accelerated drawing.  (This is basically for the lock screen.)
1851  
1852              final boolean forceHwAccelerated = (attrs.privateFlags &
1853                      WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
1854  
1855              if (ThreadedRenderer.sRendererEnabled || forceHwAccelerated) {
1856                  if (mAttachInfo.mThreadedRenderer != null) {
1857                      mAttachInfo.mThreadedRenderer.destroy();
1858                  }
1859  
1860                  final Rect insets = attrs.surfaceInsets;
1861                  final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
1862                          || insets.top != 0 || insets.bottom != 0;
1863                  final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
1864                  final ThreadedRenderer renderer = ThreadedRenderer.create(mContext, translucent,
1865                          attrs.getTitle().toString());
1866                  mAttachInfo.mThreadedRenderer = renderer;
1867                  renderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
1868                  updateColorModeIfNeeded(attrs.getColorMode());
1869                  updateRenderHdrSdrRatio();
1870                  updateForceDarkMode();
1871                  mAttachInfo.mHardwareAccelerated = true;
1872                  mAttachInfo.mHardwareAccelerationRequested = true;
1873                  if (mHardwareRendererObserver != null) {
1874                      renderer.addObserver(mHardwareRendererObserver);
1875                  }
1876              }
1877          }
1878      }
1879  
1880      private int getNightMode() {
1881          return getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
1882      }
1883  
1884      private void updateForceDarkMode() {
1885          if (mAttachInfo.mThreadedRenderer == null) return;
1886  
1887          boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
1888  
1889          if (useAutoDark) {
1890              boolean forceDarkAllowedDefault =
1891                      SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);
1892              TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
1893              useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
1894                      && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);
1895              a.recycle();
1896          }
1897  
1898          if (mAttachInfo.mThreadedRenderer.setForceDark(useAutoDark)) {
1899              // TODO: Don't require regenerating all display lists to apply this setting
1900              invalidateWorld(mView);
1901          }
1902      }
1903  
1904      @UnsupportedAppUsage
1905      public View getView() {
1906          return mView;
1907      }
1908  
1909      final WindowLeaked getLocation() {
1910          return mLocation;
1911      }
1912  
1913      @VisibleForTesting
1914      public void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
1915          synchronized (this) {
1916              final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
1917              final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
1918              final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
1919              final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
1920              final int oldSoftInputMode = mWindowAttributes.softInputMode;
1921              final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
1922  
1923              if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
1924                      & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
1925                      && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
1926                  Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!");
1927              }
1928  
1929              // Keep track of the actual window flags supplied by the client.
1930              mClientWindowLayoutFlags = attrs.flags;
1931  
1932              // Preserve compatible window flag if exists.
1933              final int compatibleWindowFlag = mWindowAttributes.privateFlags
1934                      & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
1935  
1936              // Preserve system UI visibility.
1937              final int systemUiVisibility = mWindowAttributes.systemUiVisibility;
1938              final int subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
1939  
1940              // Preserve appearance and behavior.
1941              final int appearance = mWindowAttributes.insetsFlags.appearance;
1942              final int behavior = mWindowAttributes.insetsFlags.behavior;
1943              final int appearanceAndBehaviorPrivateFlags = mWindowAttributes.privateFlags
1944                      & (PRIVATE_FLAG_APPEARANCE_CONTROLLED | PRIVATE_FLAG_BEHAVIOR_CONTROLLED);
1945  
1946              final int changes = mWindowAttributes.copyFrom(attrs);
1947              if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
1948                  // Recompute system ui visibility.
1949                  mAttachInfo.mRecomputeGlobalAttributes = true;
1950              }
1951              if ((changes & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
1952                  // Request to update light center.
1953                  mAttachInfo.mNeedsUpdateLightCenter = true;
1954              }
1955              if ((changes & WindowManager.LayoutParams.COLOR_MODE_CHANGED) != 0) {
1956                  invalidate();
1957              }
1958              if (mWindowAttributes.packageName == null) {
1959                  mWindowAttributes.packageName = mBasePackageName;
1960              }
1961  
1962              // Restore preserved flags.
1963              mWindowAttributes.systemUiVisibility = systemUiVisibility;
1964              mWindowAttributes.subtreeSystemUiVisibility = subtreeSystemUiVisibility;
1965              mWindowAttributes.insetsFlags.appearance = appearance;
1966              mWindowAttributes.insetsFlags.behavior = behavior;
1967              mWindowAttributes.privateFlags |= compatibleWindowFlag
1968                      | appearanceAndBehaviorPrivateFlags
1969                      | WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
1970  
1971              if (mWindowAttributes.preservePreviousSurfaceInsets) {
1972                  // Restore old surface insets.
1973                  mWindowAttributes.surfaceInsets.set(
1974                          oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
1975                  mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
1976              } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft
1977                      || mWindowAttributes.surfaceInsets.top != oldInsetTop
1978                      || mWindowAttributes.surfaceInsets.right != oldInsetRight
1979                      || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) {
1980                  mNeedsRendererSetup = true;
1981              }
1982  
1983              applyKeepScreenOnFlag(mWindowAttributes);
1984  
1985              if (newView) {
1986                  mSoftInputMode = attrs.softInputMode;
1987                  requestLayout();
1988              }
1989  
1990              // Don't lose the mode we last auto-computed.
1991              if ((attrs.softInputMode & SOFT_INPUT_MASK_ADJUST)
1992                      == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1993                  mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
1994                          & ~SOFT_INPUT_MASK_ADJUST) | (oldSoftInputMode & SOFT_INPUT_MASK_ADJUST);
1995              }
1996  
1997              if (mWindowAttributes.softInputMode != oldSoftInputMode) {
1998                  requestFitSystemWindows();
1999              }
2000  
2001              mWindowAttributesChanged = true;
2002              scheduleTraversals();
2003              setAccessibilityWindowAttributesIfNeeded();
2004          }
2005      }
2006  
2007      void handleAppVisibility(boolean visible) {
2008          if (mAppVisible != visible) {
2009              final boolean previousVisible = getHostVisibility() == View.VISIBLE;
2010              mAppVisible = visible;
2011              final boolean currentVisible = getHostVisibility() == View.VISIBLE;
2012              // Root view only cares about whether it is visible or not.
2013              if (previousVisible != currentVisible) {
2014                  mAppVisibilityChanged = true;
2015                  scheduleTraversals();
2016              }
2017              // Only enable if the window is not already removed (via earlier call to doDie())
2018              if (!mRemoved || !mAppVisible) {
2019                  AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
2020              } else if (LOCAL_LOGV) {
2021                  Log.v(mTag, "handleAppVisibility() enabling visibility when removed");
2022              }
2023          }
2024      }
2025  
2026      void handleGetNewSurface() {
2027          mNewSurfaceNeeded = true;
2028          mFullRedrawNeeded = true;
2029          scheduleTraversals();
2030      }
2031  
2032      /** Handles messages {@link #MSG_RESIZED} and {@link #MSG_RESIZED_REPORT}. */
2033      private void handleResized(int msg, SomeArgs args) {
2034          if (!mAdded) {
2035              return;
2036          }
2037  
2038          final ClientWindowFrames frames = (ClientWindowFrames) args.arg1;
2039          final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2;
2040          CompatibilityInfo.applyOverrideScaleIfNeeded(mergedConfiguration);
2041          final boolean forceNextWindowRelayout = args.argi1 != 0;
2042          final int displayId = args.argi3;
2043          final boolean dragResizing = args.argi5 != 0;
2044  
2045          final Rect frame = frames.frame;
2046          final Rect displayFrame = frames.displayFrame;
2047          final Rect attachedFrame = frames.attachedFrame;
2048          if (mTranslator != null) {
2049              mTranslator.translateRectInScreenToAppWindow(frame);
2050              mTranslator.translateRectInScreenToAppWindow(displayFrame);
2051              mTranslator.translateRectInScreenToAppWindow(attachedFrame);
2052          }
2053          final float compatScale = frames.compatScale;
2054          final boolean frameChanged = !mWinFrame.equals(frame);
2055          final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration);
2056          final boolean attachedFrameChanged = LOCAL_LAYOUT
2057                  && !Objects.equals(mTmpFrames.attachedFrame, attachedFrame);
2058          final boolean displayChanged = mDisplay.getDisplayId() != displayId;
2059          final boolean compatScaleChanged = mTmpFrames.compatScale != compatScale;
2060          final boolean dragResizingChanged = mPendingDragResizing != dragResizing;
2061          if (msg == MSG_RESIZED && !frameChanged && !configChanged && !attachedFrameChanged
2062                  && !displayChanged && !forceNextWindowRelayout
2063                  && !compatScaleChanged && !dragResizingChanged) {
2064              return;
2065          }
2066  
2067          mPendingDragResizing = dragResizing;
2068          mTmpFrames.compatScale = compatScale;
2069          mInvCompatScale = 1f / compatScale;
2070  
2071          if (configChanged) {
2072              // If configuration changed - notify about that and, maybe, about move to display.
2073              performConfigurationChange(mergedConfiguration, false /* force */,
2074                      displayChanged ? displayId : INVALID_DISPLAY /* same display */);
2075          } else if (displayChanged) {
2076              // Moved to display without config change - report last applied one.
2077              onMovedToDisplay(displayId, mLastConfigurationFromResources);
2078          }
2079  
2080          setFrame(frame, false /* withinRelayout */);
2081          mTmpFrames.displayFrame.set(displayFrame);
2082          if (mTmpFrames.attachedFrame != null && attachedFrame != null) {
2083              mTmpFrames.attachedFrame.set(attachedFrame);
2084          }
2085  
2086          if (mDragResizing && mUseMTRenderer) {
2087              boolean fullscreen = frame.equals(mPendingBackDropFrame);
2088              for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
2089                  mWindowCallbacks.get(i).onWindowSizeIsChanging(mPendingBackDropFrame, fullscreen,
2090                          mAttachInfo.mVisibleInsets, mAttachInfo.mStableInsets);
2091              }
2092          }
2093  
2094          mForceNextWindowRelayout |= forceNextWindowRelayout;
2095          mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
2096          mSyncSeqId = args.argi4 > mSyncSeqId ? args.argi4 : mSyncSeqId;
2097  
2098          if (msg == MSG_RESIZED_REPORT) {
2099              reportNextDraw("resized");
2100          }
2101  
2102          if (mView != null && (frameChanged || configChanged)) {
2103              forceLayout(mView);
2104          }
2105          requestLayout();
2106      }
2107  
2108      private final DisplayListener mDisplayListener = new DisplayListener() {
2109          @Override
2110          public void onDisplayChanged(int displayId) {
2111              if (mExtraDisplayListenerLogging) {
2112                  Slog.i(mTag, "Received onDisplayChanged - " + mView);
2113              }
2114              if (mView != null && mDisplay.getDisplayId() == displayId) {
2115                  final int oldDisplayState = mAttachInfo.mDisplayState;
2116                  final int newDisplayState = mDisplay.getState();
2117                  if (mExtraDisplayListenerLogging) {
2118                      Slog.i(mTag, "DisplayState - old: " + oldDisplayState
2119                              + ", new: " + newDisplayState);
2120                  }
2121                  if (oldDisplayState != newDisplayState) {
2122                      mAttachInfo.mDisplayState = newDisplayState;
2123                      pokeDrawLockIfNeeded();
2124                      if (oldDisplayState != Display.STATE_UNKNOWN) {
2125                          final int oldScreenState = toViewScreenState(oldDisplayState);
2126                          final int newScreenState = toViewScreenState(newDisplayState);
2127                          if (oldScreenState != newScreenState) {
2128                              mView.dispatchScreenStateChanged(newScreenState);
2129                          }
2130                          if (oldDisplayState == Display.STATE_OFF) {
2131                              // Draw was suppressed so we need to for it to happen here.
2132                              mFullRedrawNeeded = true;
2133                              scheduleTraversals();
2134                          }
2135                      }
2136                  }
2137              }
2138          }
2139  
2140          @Override
2141          public void onDisplayRemoved(int displayId) {
2142          }
2143  
2144          @Override
2145          public void onDisplayAdded(int displayId) {
2146          }
2147  
2148          private int toViewScreenState(int displayState) {
2149              return displayState == Display.STATE_OFF ?
2150                      View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
2151          }
2152      };
2153  
2154      /**
2155       * Notify about move to a different display.
2156       * @param displayId The id of the display where this view root is moved to.
2157       * @param config Configuration of the resources on new display after move.
2158       *
2159       * @hide
2160       */
onMovedToDisplay(int displayId, Configuration config)2161      public void onMovedToDisplay(int displayId, Configuration config) {
2162          if (mDisplay.getDisplayId() == displayId) {
2163              return;
2164          }
2165  
2166          // Get new instance of display based on current display adjustments. It may be updated later
2167          // if moving between the displays also involved a configuration change.
2168          updateInternalDisplay(displayId, mView.getResources());
2169          mImeFocusController.onMovedToDisplay();
2170          mAttachInfo.mDisplayState = mDisplay.getState();
2171          // Internal state updated, now notify the view hierarchy.
2172          mView.dispatchMovedToDisplay(mDisplay, config);
2173      }
2174  
2175      /**
2176       * Updates {@link #mDisplay} to the display object corresponding to {@param displayId}.
2177       * Uses DEFAULT_DISPLAY if there isn't a display object in the system corresponding
2178       * to {@param displayId}.
2179       */
updateInternalDisplay(int displayId, Resources resources)2180      private void updateInternalDisplay(int displayId, Resources resources) {
2181          final Display preferredDisplay =
2182                  ResourcesManager.getInstance().getAdjustedDisplay(displayId, resources);
2183          if (mHdrSdrRatioChangedListener != null && mDisplay != null) {
2184              mDisplay.unregisterHdrSdrRatioChangedListener(mHdrSdrRatioChangedListener);
2185          }
2186          if (preferredDisplay == null) {
2187              // Fallback to use default display.
2188              Slog.w(TAG, "Cannot get desired display with Id: " + displayId);
2189              mDisplay = ResourcesManager.getInstance()
2190                      .getAdjustedDisplay(DEFAULT_DISPLAY, resources);
2191          } else {
2192              mDisplay = preferredDisplay;
2193          }
2194          if (mHdrSdrRatioChangedListener != null && mDisplay != null) {
2195              mDisplay.registerHdrSdrRatioChangedListener(mExecutor, mHdrSdrRatioChangedListener);
2196          }
2197          mContext.updateDisplay(mDisplay.getDisplayId());
2198      }
2199  
pokeDrawLockIfNeeded()2200      void pokeDrawLockIfNeeded() {
2201          if (!Display.isDozeState(mAttachInfo.mDisplayState)) {
2202              // Only need to acquire wake lock for DOZE state.
2203              return;
2204          }
2205          if (mWindowAttributes.type != WindowManager.LayoutParams.TYPE_BASE_APPLICATION) {
2206              // Non-activity windows should be responsible to hold wake lock by themself, because
2207              // usually they are system windows.
2208              return;
2209          }
2210          if (mAdded && mTraversalScheduled && mAttachInfo.mHasWindowFocus) {
2211              try {
2212                  mWindowSession.pokeDrawLock(mWindow);
2213              } catch (RemoteException ex) {
2214                  // System server died, oh well.
2215              }
2216          }
2217      }
2218  
2219      @Override
requestFitSystemWindows()2220      public void requestFitSystemWindows() {
2221          checkThread();
2222          mApplyInsetsRequested = true;
2223          scheduleTraversals();
2224      }
2225  
notifyInsetsChanged()2226      void notifyInsetsChanged() {
2227          mApplyInsetsRequested = true;
2228          requestLayout();
2229  
2230          // See comment for View.sForceLayoutWhenInsetsChanged
2231          if (View.sForceLayoutWhenInsetsChanged && mView != null
2232                  && (mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST)
2233                          == SOFT_INPUT_ADJUST_RESIZE) {
2234              forceLayout(mView);
2235          }
2236  
2237          // If this changes during traversal, no need to schedule another one as it will dispatch it
2238          // during the current traversal.
2239          if (!mIsInTraversal) {
2240              scheduleTraversals();
2241          }
2242  
2243          if (!mInsetsController.getState().isSourceOrDefaultVisible(ID_IME, Type.ime())) {
2244              notifyLeaveTypingEvent();
2245          }
2246      }
2247  
2248      @Override
requestLayout()2249      public void requestLayout() {
2250          if (!mHandlingLayoutInLayoutRequest) {
2251              checkThread();
2252              mLayoutRequested = true;
2253              scheduleTraversals();
2254          }
2255      }
2256  
2257      @Override
isLayoutRequested()2258      public boolean isLayoutRequested() {
2259          return mLayoutRequested;
2260      }
2261  
2262      @Override
onDescendantInvalidated(@onNull View child, @NonNull View descendant)2263      public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) {
2264          // TODO: Re-enable after camera is fixed or consider targetSdk checking this
2265          // checkThread();
2266          if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
2267              mIsAnimating = true;
2268          }
2269          invalidate();
2270      }
2271  
2272      @UnsupportedAppUsage
invalidate()2273      void invalidate() {
2274          mDirty.set(0, 0, mWidth, mHeight);
2275          if (!mWillDrawSoon) {
2276              scheduleTraversals();
2277          }
2278      }
2279  
invalidateWorld(View view)2280      void invalidateWorld(View view) {
2281          view.invalidate();
2282          if (view instanceof ViewGroup) {
2283              ViewGroup parent = (ViewGroup) view;
2284              for (int i = 0; i < parent.getChildCount(); i++) {
2285                  invalidateWorld(parent.getChildAt(i));
2286              }
2287          }
2288      }
2289  
2290      @Override
invalidateChild(View child, Rect dirty)2291      public void invalidateChild(View child, Rect dirty) {
2292          invalidateChildInParent(null, dirty);
2293      }
2294  
2295      @Override
invalidateChildInParent(int[] location, Rect dirty)2296      public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
2297          checkThread();
2298          if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
2299  
2300          if (dirty == null) {
2301              invalidate();
2302              return null;
2303          } else if (dirty.isEmpty() && !mIsAnimating) {
2304              return null;
2305          }
2306  
2307          if (mCurScrollY != 0 || mTranslator != null) {
2308              mTempRect.set(dirty);
2309              dirty = mTempRect;
2310              if (mCurScrollY != 0) {
2311                  dirty.offset(0, -mCurScrollY);
2312              }
2313              if (mTranslator != null) {
2314                  mTranslator.translateRectInAppWindowToScreen(dirty);
2315              }
2316              if (mAttachInfo.mScalingRequired) {
2317                  dirty.inset(-1, -1);
2318              }
2319          }
2320  
2321          invalidateRectOnScreen(dirty);
2322  
2323          return null;
2324      }
2325  
invalidateRectOnScreen(Rect dirty)2326      private void invalidateRectOnScreen(Rect dirty) {
2327          if (DEBUG_DRAW) Log.v(mTag, "invalidateRectOnScreen: " + dirty);
2328          final Rect localDirty = mDirty;
2329  
2330          // Add the new dirty rect to the current one
2331          localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
2332          // Intersect with the bounds of the window to skip
2333          // updates that lie outside of the visible region
2334          final float appScale = mAttachInfo.mApplicationScale;
2335          final boolean intersected = localDirty.intersect(0, 0,
2336                  (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
2337          if (!intersected) {
2338              localDirty.setEmpty();
2339          }
2340          if (!mWillDrawSoon && (intersected || mIsAnimating)) {
2341              scheduleTraversals();
2342          }
2343      }
2344  
setIsAmbientMode(boolean ambient)2345      public void setIsAmbientMode(boolean ambient) {
2346          mIsAmbientMode = ambient;
2347      }
2348  
setWindowStopped(boolean stopped)2349      void setWindowStopped(boolean stopped) {
2350          checkThread();
2351          if (mStopped != stopped) {
2352              mStopped = stopped;
2353              final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
2354              if (renderer != null) {
2355                  if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
2356                  renderer.setStopped(mStopped);
2357              }
2358              if (!mStopped) {
2359                  // Make sure that relayoutWindow will be called to get valid surface because
2360                  // the previous surface may have been released.
2361                  mAppVisibilityChanged = true;
2362                  scheduleTraversals();
2363              } else {
2364                  if (renderer != null) {
2365                      renderer.destroyHardwareResources(mView);
2366                  }
2367  
2368                  if (mSurface.isValid()) {
2369                      if (mSurfaceHolder != null) {
2370                          notifyHolderSurfaceDestroyed();
2371                      }
2372                      notifySurfaceDestroyed();
2373                  }
2374                  destroySurface();
2375              }
2376          }
2377      }
2378  
2379  
2380      /** Register callbacks to be notified when the ViewRootImpl surface changes. */
2381      public interface SurfaceChangedCallback {
surfaceCreated(Transaction t)2382          void surfaceCreated(Transaction t);
surfaceReplaced(Transaction t)2383          void surfaceReplaced(Transaction t);
surfaceDestroyed()2384          void surfaceDestroyed();
vriDrawStarted(boolean isWmSync)2385          default void vriDrawStarted(boolean isWmSync) {};
2386      }
2387  
2388      private final ArrayList<SurfaceChangedCallback> mSurfaceChangedCallbacks = new ArrayList<>();
addSurfaceChangedCallback(SurfaceChangedCallback c)2389      public void addSurfaceChangedCallback(SurfaceChangedCallback c) {
2390          mSurfaceChangedCallbacks.add(c);
2391      }
2392  
removeSurfaceChangedCallback(SurfaceChangedCallback c)2393      public void removeSurfaceChangedCallback(SurfaceChangedCallback c) {
2394          mSurfaceChangedCallbacks.remove(c);
2395      }
2396  
notifySurfaceCreated(Transaction t)2397      private void notifySurfaceCreated(Transaction t) {
2398          for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2399              mSurfaceChangedCallbacks.get(i).surfaceCreated(t);
2400          }
2401      }
2402  
2403      /**
2404       * Notify listeners when the ViewRootImpl surface has been replaced. This callback will not be
2405       * called if a new surface is created, only if the valid surface has been replaced with another
2406       * valid surface.
2407       */
notifySurfaceReplaced(Transaction t)2408      private void notifySurfaceReplaced(Transaction t) {
2409          for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2410              mSurfaceChangedCallbacks.get(i).surfaceReplaced(t);
2411          }
2412      }
2413  
notifySurfaceDestroyed()2414      private void notifySurfaceDestroyed() {
2415          for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2416              mSurfaceChangedCallbacks.get(i).surfaceDestroyed();
2417          }
2418      }
2419  
notifyDrawStarted(boolean isWmSync)2420      private void notifyDrawStarted(boolean isWmSync) {
2421          for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2422              mSurfaceChangedCallbacks.get(i).vriDrawStarted(isWmSync);
2423          }
2424      }
2425  
2426      /**
2427       * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the
2428       * surface insets. If the layer does not exist, it is created.
2429       *
2430       * <p>Parenting to this layer will ensure that its children are cropped by the view's surface
2431       * insets.
2432       */
updateAndGetBoundsLayer(Transaction t)2433      public SurfaceControl updateAndGetBoundsLayer(Transaction t) {
2434          if (mBoundsLayer == null) {
2435              mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession)
2436                      .setContainerLayer()
2437                      .setName("Bounds for - " + getTitle().toString())
2438                      .setParent(getSurfaceControl())
2439                      .setCallsite("ViewRootImpl.getBoundsLayer")
2440                      .build();
2441              setBoundsLayerCrop(t);
2442              t.show(mBoundsLayer);
2443          }
2444         return mBoundsLayer;
2445      }
2446  
updateBlastSurfaceIfNeeded()2447      void updateBlastSurfaceIfNeeded() {
2448          if (!mSurfaceControl.isValid()) {
2449              return;
2450          }
2451  
2452          if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
2453              mBlastBufferQueue.update(mSurfaceControl,
2454                  mSurfaceSize.x, mSurfaceSize.y,
2455                  mWindowAttributes.format);
2456              return;
2457          }
2458  
2459          // If the SurfaceControl has been updated, destroy and recreate the BBQ to reset the BQ and
2460          // BBQ states.
2461          if (mBlastBufferQueue != null) {
2462              mBlastBufferQueue.destroy();
2463          }
2464          mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
2465                  mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
2466          mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
2467          Surface blastSurface = mBlastBufferQueue.createSurface();
2468          // Only call transferFrom if the surface has changed to prevent inc the generation ID and
2469          // causing EGL resources to be recreated.
2470          mSurface.transferFrom(blastSurface);
2471      }
2472  
setBoundsLayerCrop(Transaction t)2473      private void setBoundsLayerCrop(Transaction t) {
2474          // Adjust of insets and update the bounds layer so child surfaces do not draw into
2475          // the surface inset region.
2476          mTempRect.set(0, 0, mSurfaceSize.x, mSurfaceSize.y);
2477          mTempRect.inset(mWindowAttributes.surfaceInsets.left,
2478                  mWindowAttributes.surfaceInsets.top,
2479                  mWindowAttributes.surfaceInsets.right, mWindowAttributes.surfaceInsets.bottom);
2480          mTempRect.inset(mChildBoundingInsets.left, mChildBoundingInsets.top,
2481              mChildBoundingInsets.right, mChildBoundingInsets.bottom);
2482          t.setWindowCrop(mBoundsLayer, mTempRect);
2483      }
2484  
2485      /**
2486       * Called after window layout to update the bounds surface. If the surface insets have changed
2487       * or the surface has resized, update the bounds surface.
2488       */
updateBoundsLayer(SurfaceControl.Transaction t)2489      private boolean updateBoundsLayer(SurfaceControl.Transaction t) {
2490          if (mBoundsLayer != null) {
2491              setBoundsLayerCrop(t);
2492              return true;
2493          }
2494          return false;
2495      }
2496  
prepareSurfaces()2497      private void prepareSurfaces() {
2498          final SurfaceControl.Transaction t = mTransaction;
2499          final SurfaceControl sc = getSurfaceControl();
2500          if (!sc.isValid()) return;
2501  
2502          if (updateBoundsLayer(t)) {
2503              applyTransactionOnDraw(t);
2504          }
2505      }
2506  
destroySurface()2507      private void destroySurface() {
2508          if (mBoundsLayer != null) {
2509              mBoundsLayer.release();
2510              mBoundsLayer = null;
2511          }
2512          mSurface.release();
2513          mSurfaceControl.release();
2514  
2515          if (mBlastBufferQueue != null) {
2516              mBlastBufferQueue.destroy();
2517              mBlastBufferQueue = null;
2518          }
2519  
2520          if (mAttachInfo.mThreadedRenderer != null) {
2521              mAttachInfo.mThreadedRenderer.setSurfaceControl(null, null);
2522          }
2523      }
2524  
2525      /**
2526       * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
2527       * through to allow quick reversal of the Activity Transition.
2528       *
2529       * @param paused true to pause, false to resume.
2530       */
setPausedForTransition(boolean paused)2531      public void setPausedForTransition(boolean paused) {
2532          mPausedForTransition = paused;
2533      }
2534  
2535      @Override
getParent()2536      public ViewParent getParent() {
2537          return null;
2538      }
2539  
2540      @Override
getChildVisibleRect(View child, Rect r, android.graphics.Point offset)2541      public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
2542          if (child != mView) {
2543              throw new RuntimeException("child is not mine, honest!");
2544          }
2545          // Note: don't apply scroll offset, because we want to know its
2546          // visibility in the virtual canvas being given to the view hierarchy.
2547          return r.intersect(0, 0, mWidth, mHeight);
2548      }
2549  
2550      @Override
getChildLocalHitRegion(@onNull View child, @NonNull Region region, @NonNull Matrix matrix, boolean isHover)2551      public boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region,
2552              @NonNull Matrix matrix, boolean isHover) {
2553          if (child != mView) {
2554              throw new IllegalArgumentException("child " + child + " is not the root view "
2555                      + mView + " managed by this ViewRootImpl");
2556          }
2557  
2558          RectF rectF = new RectF(0, 0, mWidth, mHeight);
2559          matrix.mapRect(rectF);
2560          // Note: don't apply scroll offset, because we want to know its
2561          // visibility in the virtual canvas being given to the view hierarchy.
2562          return region.op(Math.round(rectF.left), Math.round(rectF.top),
2563                  Math.round(rectF.right), Math.round(rectF.bottom), Region.Op.INTERSECT);
2564      }
2565  
2566      @Override
bringChildToFront(View child)2567      public void bringChildToFront(View child) {
2568      }
2569  
getHostVisibility()2570      int getHostVisibility() {
2571          return mView != null && (mAppVisible || mForceDecorViewVisibility)
2572                  ? mView.getVisibility() : View.GONE;
2573      }
2574  
2575      /**
2576       * Add LayoutTransition to the list of transitions to be started in the next traversal.
2577       * This list will be cleared after the transitions on the list are start()'ed. These
2578       * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
2579       * happens during the layout phase of traversal, which we want to complete before any of the
2580       * animations are started (because those animations may side-effect properties that layout
2581       * depends upon, like the bounding rectangles of the affected views). So we add the transition
2582       * to the list and it is started just prior to starting the drawing phase of traversal.
2583       *
2584       * @param transition The LayoutTransition to be started on the next traversal.
2585       *
2586       * @hide
2587       */
requestTransitionStart(LayoutTransition transition)2588      public void requestTransitionStart(LayoutTransition transition) {
2589          if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
2590              if (mPendingTransitions == null) {
2591                   mPendingTransitions = new ArrayList<LayoutTransition>();
2592              }
2593              mPendingTransitions.add(transition);
2594          }
2595      }
2596  
2597      /**
2598       * Notifies the HardwareRenderer that a new frame will be coming soon.
2599       * Currently only {@link ThreadedRenderer} cares about this, and uses
2600       * this knowledge to adjust the scheduling of off-thread animations
2601       */
notifyRendererOfFramePending()2602      void notifyRendererOfFramePending() {
2603          if (mAttachInfo.mThreadedRenderer != null) {
2604              mAttachInfo.mThreadedRenderer.notifyFramePending();
2605          }
2606      }
2607  
2608      /**
2609       * Notifies the HardwareRenderer of an expensive upcoming frame, to
2610       * allow better handling of power and scheduling requirements.
2611       *
2612       * @hide
2613       */
notifyRendererOfExpensiveFrame()2614      public void notifyRendererOfExpensiveFrame() {
2615          if (mAttachInfo.mThreadedRenderer != null) {
2616              mAttachInfo.mThreadedRenderer.notifyExpensiveFrame();
2617          }
2618      }
2619  
2620      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
scheduleTraversals()2621      void scheduleTraversals() {
2622          if (!mTraversalScheduled) {
2623              mTraversalScheduled = true;
2624              mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
2625              mChoreographer.postCallback(
2626                      Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
2627              notifyRendererOfFramePending();
2628              pokeDrawLockIfNeeded();
2629          }
2630      }
2631  
unscheduleTraversals()2632      void unscheduleTraversals() {
2633          if (mTraversalScheduled) {
2634              mTraversalScheduled = false;
2635              mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
2636              mChoreographer.removeCallbacks(
2637                      Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
2638          }
2639      }
2640  
doTraversal()2641      void doTraversal() {
2642          if (mTraversalScheduled) {
2643              mTraversalScheduled = false;
2644              mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
2645  
2646              if (mProfile) {
2647                  Debug.startMethodTracing("ViewAncestor");
2648              }
2649  
2650              performTraversals();
2651  
2652              if (mProfile) {
2653                  Debug.stopMethodTracing();
2654                  mProfile = false;
2655              }
2656          }
2657      }
2658  
applyKeepScreenOnFlag(WindowManager.LayoutParams params)2659      private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
2660          // Update window's global keep screen on flag: if a view has requested
2661          // that the screen be kept on, then it is always set; otherwise, it is
2662          // set to whatever the client last requested for the global state.
2663          if (mAttachInfo.mKeepScreenOn) {
2664              params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
2665          } else {
2666              params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
2667                      | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
2668          }
2669      }
2670  
collectViewAttributes()2671      private boolean collectViewAttributes() {
2672          if (mAttachInfo.mRecomputeGlobalAttributes) {
2673              //Log.i(mTag, "Computing view hierarchy attributes!");
2674              mAttachInfo.mRecomputeGlobalAttributes = false;
2675              boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
2676              mAttachInfo.mKeepScreenOn = false;
2677              mAttachInfo.mSystemUiVisibility = 0;
2678              mAttachInfo.mHasSystemUiListeners = false;
2679              mView.dispatchCollectViewAttributes(mAttachInfo, 0);
2680              mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
2681              WindowManager.LayoutParams params = mWindowAttributes;
2682              mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
2683              mCompatibleVisibilityInfo.globalVisibility =
2684                      (mCompatibleVisibilityInfo.globalVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE)
2685                              | (mAttachInfo.mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
2686              dispatchDispatchSystemUiVisibilityChanged();
2687              if (mAttachInfo.mKeepScreenOn != oldScreenOn
2688                      || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
2689                      || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
2690                  applyKeepScreenOnFlag(params);
2691                  params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
2692                  params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
2693                  mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
2694                  return true;
2695              }
2696          }
2697          return false;
2698      }
2699  
getImpliedSystemUiVisibility(WindowManager.LayoutParams params)2700      private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
2701          int vis = 0;
2702          // Translucent decor window flags imply stable system ui visibility.
2703          if ((params.flags & FLAG_TRANSLUCENT_STATUS) != 0) {
2704              vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
2705          }
2706          if ((params.flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) {
2707              vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
2708          }
2709          return vis;
2710      }
2711  
2712      /**
2713       * Update the compatible system UI visibility for dispatching it to the legacy app.
2714       */
updateCompatSysUiVisibility(@nsetsType int visibleTypes, @InsetsType int requestedVisibleTypes, @InsetsType int controllableTypes)2715      void updateCompatSysUiVisibility(@InsetsType int visibleTypes,
2716              @InsetsType int requestedVisibleTypes, @InsetsType int controllableTypes) {
2717          // If a type is controllable, the visibility is overridden by the requested visibility.
2718          visibleTypes =
2719                  (requestedVisibleTypes & controllableTypes) | (visibleTypes & ~controllableTypes);
2720  
2721          updateCompatSystemUiVisibilityInfo(SYSTEM_UI_FLAG_FULLSCREEN, Type.statusBars(),
2722                  visibleTypes, controllableTypes);
2723          updateCompatSystemUiVisibilityInfo(SYSTEM_UI_FLAG_HIDE_NAVIGATION, Type.navigationBars(),
2724                  visibleTypes, controllableTypes);
2725          dispatchDispatchSystemUiVisibilityChanged();
2726      }
2727  
updateCompatSystemUiVisibilityInfo(int systemUiFlag, @InsetsType int insetsType, @InsetsType int visibleTypes, @InsetsType int controllableTypes)2728      private void updateCompatSystemUiVisibilityInfo(int systemUiFlag, @InsetsType int insetsType,
2729              @InsetsType int visibleTypes, @InsetsType int controllableTypes) {
2730          final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
2731          final boolean willBeVisible = (visibleTypes & insetsType) != 0;
2732          final boolean hasControl = (controllableTypes & insetsType) != 0;
2733          final boolean wasInvisible = (mAttachInfo.mSystemUiVisibility & systemUiFlag) != 0;
2734          if (willBeVisible) {
2735              info.globalVisibility &= ~systemUiFlag;
2736              if (hasControl && wasInvisible) {
2737                  // The local system UI visibility can only be cleared while we have the control.
2738                  info.localChanges |= systemUiFlag;
2739              }
2740          } else {
2741              info.globalVisibility |= systemUiFlag;
2742              info.localChanges &= ~systemUiFlag;
2743          }
2744      }
2745  
2746      /**
2747       * If the system is forcing showing any system bar, the legacy low profile flag should be
2748       * cleared for compatibility.
2749       *
2750       * @param showTypes {@link InsetsType types} shown by the system.
2751       * @param fromIme {@code true} if the invocation is from IME.
2752       */
clearLowProfileModeIfNeeded(@nsetsType int showTypes, boolean fromIme)2753      private void clearLowProfileModeIfNeeded(@InsetsType int showTypes, boolean fromIme) {
2754          final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
2755          if ((showTypes & Type.systemBars()) != 0 && !fromIme
2756                  && (info.globalVisibility & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
2757              info.globalVisibility &= ~SYSTEM_UI_FLAG_LOW_PROFILE;
2758              info.localChanges |= SYSTEM_UI_FLAG_LOW_PROFILE;
2759              dispatchDispatchSystemUiVisibilityChanged();
2760          }
2761      }
2762  
dispatchDispatchSystemUiVisibilityChanged()2763      private void dispatchDispatchSystemUiVisibilityChanged() {
2764          if (mDispatchedSystemUiVisibility != mCompatibleVisibilityInfo.globalVisibility) {
2765              mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY);
2766              mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY));
2767          }
2768      }
2769  
handleDispatchSystemUiVisibilityChanged()2770      private void handleDispatchSystemUiVisibilityChanged() {
2771          if (mView == null) {
2772              return;
2773          }
2774          final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
2775          if (info.localChanges != 0) {
2776              mView.updateLocalSystemUiVisibility(info.localValue, info.localChanges);
2777              info.localChanges = 0;
2778          }
2779  
2780          final int visibility = info.globalVisibility & View.SYSTEM_UI_CLEARABLE_FLAGS;
2781          if (mDispatchedSystemUiVisibility != visibility) {
2782              mDispatchedSystemUiVisibility = visibility;
2783              mView.dispatchSystemUiVisibilityChanged(visibility);
2784          }
2785      }
2786  
2787      @VisibleForTesting
adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams)2788      public static void adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams) {
2789          final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility;
2790          final int flags = inOutParams.flags;
2791          final int type = inOutParams.type;
2792          final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST;
2793  
2794          if ((inOutParams.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) {
2795              inOutParams.insetsFlags.appearance = 0;
2796              if ((sysUiVis & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
2797                  inOutParams.insetsFlags.appearance |= APPEARANCE_LOW_PROFILE_BARS;
2798              }
2799              if ((sysUiVis & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0) {
2800                  inOutParams.insetsFlags.appearance |= APPEARANCE_LIGHT_STATUS_BARS;
2801              }
2802              if ((sysUiVis & SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0) {
2803                  inOutParams.insetsFlags.appearance |= APPEARANCE_LIGHT_NAVIGATION_BARS;
2804              }
2805          }
2806  
2807          if ((inOutParams.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) == 0) {
2808              if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
2809                      || (flags & FLAG_FULLSCREEN) != 0) {
2810                  inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
2811              } else {
2812                  inOutParams.insetsFlags.behavior = BEHAVIOR_DEFAULT;
2813              }
2814          }
2815  
2816          inOutParams.privateFlags &= ~PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
2817  
2818          if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) {
2819              return;
2820          }
2821  
2822          int types = inOutParams.getFitInsetsTypes();
2823          boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility();
2824  
2825          if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0
2826                  || (flags & FLAG_LAYOUT_IN_SCREEN) != 0)
2827                  || (flags & FLAG_TRANSLUCENT_STATUS) != 0) {
2828              types &= ~Type.statusBars();
2829          }
2830          if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
2831                  || (flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) {
2832              types &= ~Type.systemBars();
2833          }
2834          if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
2835              ignoreVis = true;
2836          } else if ((types & Type.systemBars()) == Type.systemBars()) {
2837              if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
2838                  types |= Type.ime();
2839              } else {
2840                  inOutParams.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
2841              }
2842          }
2843          inOutParams.setFitInsetsTypes(types);
2844          inOutParams.setFitInsetsIgnoringVisibility(ignoreVis);
2845  
2846          // The fitting of insets are not really controlled by the clients, so we remove the flag.
2847          inOutParams.privateFlags &= ~PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
2848      }
2849  
controlInsetsForCompatibility(WindowManager.LayoutParams params)2850      private void controlInsetsForCompatibility(WindowManager.LayoutParams params) {
2851          final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility;
2852          final int flags = params.flags;
2853          final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT;
2854          final boolean nonAttachedAppWindow = params.type >= FIRST_APPLICATION_WINDOW
2855                  && params.type <= LAST_APPLICATION_WINDOW;
2856          final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0;
2857          final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0
2858                  || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow);
2859          final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0;
2860          final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
2861  
2862          @InsetsType int typesToHide = 0;
2863          @InsetsType int typesToShow = 0;
2864          if (statusIsHiddenByFlags && !statusWasHiddenByFlags) {
2865              typesToHide |= Type.statusBars();
2866          } else if (!statusIsHiddenByFlags && statusWasHiddenByFlags) {
2867              typesToShow |= Type.statusBars();
2868          }
2869          if (navIsHiddenByFlags && !navWasHiddenByFlags) {
2870              typesToHide |= Type.navigationBars();
2871          } else if (!navIsHiddenByFlags && navWasHiddenByFlags) {
2872              typesToShow |= Type.navigationBars();
2873          }
2874          if (typesToHide != 0) {
2875              getInsetsController().hide(typesToHide);
2876          }
2877          if (typesToShow != 0) {
2878              getInsetsController().show(typesToShow);
2879          }
2880          mTypesHiddenByFlags |= typesToHide;
2881          mTypesHiddenByFlags &= ~typesToShow;
2882      }
2883  
measureHierarchy(final View host, final WindowManager.LayoutParams lp, final Resources res, final int desiredWindowWidth, final int desiredWindowHeight, boolean forRootSizeOnly)2884      private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
2885              final Resources res, final int desiredWindowWidth, final int desiredWindowHeight,
2886              boolean forRootSizeOnly) {
2887          int childWidthMeasureSpec;
2888          int childHeightMeasureSpec;
2889          boolean windowSizeMayChange = false;
2890  
2891          if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
2892                  "Measuring " + host + " in display " + desiredWindowWidth
2893                  + "x" + desiredWindowHeight + "...");
2894  
2895          boolean goodMeasure = false;
2896          if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
2897              // On large screens, we don't want to allow dialogs to just
2898              // stretch to fill the entire width of the screen to display
2899              // one line of text.  First try doing the layout at a smaller
2900              // size to see if it will fit.
2901              final DisplayMetrics packageMetrics = res.getDisplayMetrics();
2902              res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
2903              int baseSize = 0;
2904              if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
2905                  baseSize = (int)mTmpValue.getDimension(packageMetrics);
2906              }
2907              if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
2908                      + ", desiredWindowWidth=" + desiredWindowWidth);
2909              if (baseSize != 0 && desiredWindowWidth > baseSize) {
2910                  childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags);
2911                  childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,
2912                          lp.privateFlags);
2913                  performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
2914                  if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
2915                          + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
2916                          + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
2917                          + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
2918                  if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
2919                      goodMeasure = true;
2920                  } else {
2921                      // Didn't fit in that size... try expanding a bit.
2922                      baseSize = (baseSize+desiredWindowWidth)/2;
2923                      if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
2924                              + baseSize);
2925                      childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags);
2926                      performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
2927                      if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
2928                              + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
2929                      if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
2930                          if (DEBUG_DIALOG) Log.v(mTag, "Good!");
2931                          goodMeasure = true;
2932                      }
2933                  }
2934              }
2935          }
2936  
2937          if (!goodMeasure) {
2938              childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width,
2939                      lp.privateFlags);
2940              childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,
2941                      lp.privateFlags);
2942              if (!forRootSizeOnly || !setMeasuredRootSizeFromSpec(
2943                      childWidthMeasureSpec, childHeightMeasureSpec)) {
2944                  performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
2945              } else {
2946                  // We already know how big the window should be before measuring the views.
2947                  // We can measure the views before laying out them. This is to avoid unnecessary
2948                  // measure.
2949                  mViewMeasureDeferred = true;
2950              }
2951              if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
2952                  windowSizeMayChange = true;
2953              }
2954          }
2955  
2956          if (DBG) {
2957              System.out.println("======================================");
2958              System.out.println("performTraversals -- after measure");
2959              host.debug();
2960          }
2961  
2962          return windowSizeMayChange;
2963      }
2964  
2965      /**
2966       * Sets the measured root size for requesting the window frame.
2967       *
2968       * @param widthMeasureSpec contains the size and the mode of the width.
2969       * @param heightMeasureSpec contains the size and the mode of the height.
2970       * @return {@code true} if we actually set the measured size; {@code false} otherwise.
2971       */
setMeasuredRootSizeFromSpec(int widthMeasureSpec, int heightMeasureSpec)2972      private boolean setMeasuredRootSizeFromSpec(int widthMeasureSpec, int heightMeasureSpec) {
2973          final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
2974          final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
2975          if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
2976              // We don't know the exact size. We need to measure the hierarchy to know that.
2977              return false;
2978          }
2979          mMeasuredWidth = MeasureSpec.getSize(widthMeasureSpec);
2980          mMeasuredHeight = MeasureSpec.getSize(heightMeasureSpec);
2981          return true;
2982      }
2983  
2984      /**
2985       * Modifies the input matrix such that it maps view-local coordinates to
2986       * on-screen coordinates.
2987       *
2988       * @param m input matrix to modify
2989       */
transformMatrixToGlobal(Matrix m)2990      void transformMatrixToGlobal(Matrix m) {
2991          m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
2992      }
2993  
2994      /**
2995       * Modifies the input matrix such that it maps on-screen coordinates to
2996       * view-local coordinates.
2997       *
2998       * @param m input matrix to modify
2999       */
transformMatrixToLocal(Matrix m)3000      void transformMatrixToLocal(Matrix m) {
3001          m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
3002      }
3003  
getWindowInsets(boolean forceConstruct)3004      /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
3005          if (mLastWindowInsets == null || forceConstruct) {
3006              final Configuration config = getConfiguration();
3007              mLastWindowInsets = mInsetsController.calculateInsets(
3008                      config.isScreenRound(), mWindowAttributes.type,
3009                      config.windowConfiguration.getActivityType(), mWindowAttributes.softInputMode,
3010                      mWindowAttributes.flags, (mWindowAttributes.systemUiVisibility
3011                              | mWindowAttributes.subtreeSystemUiVisibility));
3012  
3013              mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect());
3014              mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect());
3015              mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets(
3016                      mWindowAttributes.type, config.windowConfiguration.getActivityType(),
3017                      mWindowAttributes.softInputMode, mWindowAttributes.flags).toRect());
3018          }
3019          return mLastWindowInsets;
3020      }
3021  
dispatchApplyInsets(View host)3022      public void dispatchApplyInsets(View host) {
3023          Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchApplyInsets");
3024          mApplyInsetsRequested = false;
3025          WindowInsets insets = getWindowInsets(true /* forceConstruct */);
3026          if (!shouldDispatchCutout()) {
3027              // Window is either not laid out in cutout or the status bar inset takes care of
3028              // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
3029              insets = insets.consumeDisplayCutout();
3030          }
3031          host.dispatchApplyWindowInsets(insets);
3032          mAttachInfo.delayNotifyContentCaptureInsetsEvent(insets.getInsets(Type.all()));
3033          Trace.traceEnd(Trace.TRACE_TAG_VIEW);
3034      }
3035  
updateCaptionInsets()3036      private boolean updateCaptionInsets() {
3037          if (CAPTION_ON_SHELL) {
3038              return false;
3039          }
3040          if (!(mView instanceof DecorView)) return false;
3041          final int captionInsetsHeight = ((DecorView) mView).getCaptionInsetsHeight();
3042          final Rect captionFrame = new Rect();
3043          if (captionInsetsHeight != 0) {
3044              captionFrame.set(mWinFrame.left, mWinFrame.top, mWinFrame.right,
3045                              mWinFrame.top + captionInsetsHeight);
3046          }
3047          if (mAttachInfo.mCaptionInsets.equals(captionFrame)) return false;
3048          mAttachInfo.mCaptionInsets.set(captionFrame);
3049          return true;
3050      }
3051  
shouldDispatchCutout()3052      private boolean shouldDispatchCutout() {
3053          return mWindowAttributes.layoutInDisplayCutoutMode
3054                          == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
3055                  || mWindowAttributes.layoutInDisplayCutoutMode
3056                          == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3057      }
3058  
3059      @VisibleForTesting
getInsetsController()3060      public InsetsController getInsetsController() {
3061          return mInsetsController;
3062      }
3063  
shouldUseDisplaySize(final WindowManager.LayoutParams lp)3064      private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
3065          return lp.type == TYPE_STATUS_BAR_ADDITIONAL
3066                  || lp.type == TYPE_INPUT_METHOD
3067                  || lp.type == TYPE_VOLUME_OVERLAY;
3068      }
3069  
3070      /**
3071       * @return {@code true} if we should reduce unnecessary measure for the window.
3072       * TODO(b/260382739): Apply this to all windows.
3073       */
shouldOptimizeMeasure(final WindowManager.LayoutParams lp)3074      private static boolean shouldOptimizeMeasure(final WindowManager.LayoutParams lp) {
3075          return (lp.privateFlags & PRIVATE_FLAG_OPTIMIZE_MEASURE) != 0;
3076      }
3077  
getWindowBoundsInsetSystemBars()3078      private Rect getWindowBoundsInsetSystemBars() {
3079          final Rect bounds = new Rect(
3080                  mContext.getResources().getConfiguration().windowConfiguration.getBounds());
3081          bounds.inset(mInsetsController.getState().calculateInsets(
3082                  bounds, Type.systemBars(), false /* ignoreVisibility */));
3083          return bounds;
3084      }
3085  
dipToPx(int dip)3086      int dipToPx(int dip) {
3087          final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
3088          return (int) (displayMetrics.density * dip + 0.5f);
3089      }
3090  
performTraversals()3091      private void performTraversals() {
3092          mLastPerformTraversalsSkipDrawReason = null;
3093  
3094          // cache mView since it is used so much below...
3095          final View host = mView;
3096          if (DBG) {
3097              System.out.println("======================================");
3098              System.out.println("performTraversals");
3099              host.debug();
3100          }
3101  
3102          if (host == null || !mAdded) {
3103              mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added";
3104              return;
3105          }
3106  
3107          if (mNumPausedForSync > 0) {
3108              if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
3109                  Trace.instant(Trace.TRACE_TAG_VIEW,
3110                          TextUtils.formatSimple("performTraversals#mNumPausedForSync=%d",
3111                                  mNumPausedForSync));
3112              }
3113              if (DEBUG_BLAST) {
3114                  Log.d(mTag, "Skipping traversal due to sync " + mNumPausedForSync);
3115              }
3116              mLastPerformTraversalsSkipDrawReason = "paused_for_sync";
3117              return;
3118          }
3119  
3120          mIsInTraversal = true;
3121          mWillDrawSoon = true;
3122          boolean cancelDraw = false;
3123          String cancelReason = null;
3124          boolean isSyncRequest = false;
3125  
3126          boolean windowSizeMayChange = false;
3127          WindowManager.LayoutParams lp = mWindowAttributes;
3128  
3129          int desiredWindowWidth;
3130          int desiredWindowHeight;
3131  
3132          final int viewVisibility = getHostVisibility();
3133          final boolean viewVisibilityChanged = !mFirst
3134                  && (mViewVisibility != viewVisibility || mNewSurfaceNeeded
3135                  // Also check for possible double visibility update, which will make current
3136                  // viewVisibility value equal to mViewVisibility and we may miss it.
3137                  || mAppVisibilityChanged);
3138          mAppVisibilityChanged = false;
3139          final boolean viewUserVisibilityChanged = !mFirst &&
3140                  ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
3141          final boolean shouldOptimizeMeasure = shouldOptimizeMeasure(lp);
3142  
3143          WindowManager.LayoutParams params = null;
3144          CompatibilityInfo compatibilityInfo =
3145                  mDisplay.getDisplayAdjustments().getCompatibilityInfo();
3146          if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
3147              params = lp;
3148              mFullRedrawNeeded = true;
3149              mLayoutRequested = true;
3150              if (mLastInCompatMode) {
3151                  params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
3152                  mLastInCompatMode = false;
3153              } else {
3154                  params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
3155                  mLastInCompatMode = true;
3156              }
3157          }
3158  
3159          Rect frame = mWinFrame;
3160          if (mFirst) {
3161              mFullRedrawNeeded = true;
3162              mLayoutRequested = true;
3163  
3164              final Configuration config = getConfiguration();
3165              if (shouldUseDisplaySize(lp)) {
3166                  // NOTE -- system code, won't try to do compat mode.
3167                  Point size = new Point();
3168                  mDisplay.getRealSize(size);
3169                  desiredWindowWidth = size.x;
3170                  desiredWindowHeight = size.y;
3171              } else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
3172                      || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
3173                  // For wrap content, we have to remeasure later on anyways. Use size consistent with
3174                  // below so we get best use of the measure cache.
3175                  final Rect bounds = getWindowBoundsInsetSystemBars();
3176                  desiredWindowWidth = bounds.width();
3177                  desiredWindowHeight = bounds.height();
3178              } else {
3179                  // After addToDisplay, the frame contains the frameHint from window manager, which
3180                  // for most windows is going to be the same size as the result of relayoutWindow.
3181                  // Using this here allows us to avoid remeasuring after relayoutWindow
3182                  desiredWindowWidth = frame.width();
3183                  desiredWindowHeight = frame.height();
3184              }
3185  
3186              // We used to use the following condition to choose 32 bits drawing caches:
3187              // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
3188              // However, windows are now always 32 bits by default, so choose 32 bits
3189              mAttachInfo.mUse32BitDrawingCache = true;
3190              mAttachInfo.mWindowVisibility = viewVisibility;
3191              mAttachInfo.mRecomputeGlobalAttributes = false;
3192              mLastConfigurationFromResources.setTo(config);
3193              mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
3194              // Set the layout direction if it has not been set before (inherit is the default)
3195              if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
3196                  host.setLayoutDirection(config.getLayoutDirection());
3197              }
3198              host.dispatchAttachedToWindow(mAttachInfo, 0);
3199              mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
3200              dispatchApplyInsets(host);
3201              if (!mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
3202                  // For apps requesting legacy back behavior, we add a compat callback that
3203                  // dispatches {@link KeyEvent#KEYCODE_BACK} to their root views.
3204                  // This way from system point of view, these apps are providing custom
3205                  // {@link OnBackInvokedCallback}s, and will not play system back animations
3206                  // for them.
3207                  registerCompatOnBackInvokedCallback();
3208              }
3209          } else {
3210              desiredWindowWidth = frame.width();
3211              desiredWindowHeight = frame.height();
3212              if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
3213                  if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
3214                  mFullRedrawNeeded = true;
3215                  mLayoutRequested = true;
3216                  windowSizeMayChange = true;
3217              }
3218          }
3219  
3220          if (viewVisibilityChanged) {
3221              mAttachInfo.mWindowVisibility = viewVisibility;
3222              host.dispatchWindowVisibilityChanged(viewVisibility);
3223              mAttachInfo.mTreeObserver.dispatchOnWindowVisibilityChange(viewVisibility);
3224              if (viewUserVisibilityChanged) {
3225                  host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
3226              }
3227              if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
3228                  endDragResizing();
3229                  destroyHardwareResources();
3230              }
3231          }
3232  
3233          // Non-visible windows can't hold accessibility focus.
3234          if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
3235              host.clearAccessibilityFocus();
3236          }
3237  
3238          // Execute enqueued actions on every traversal in case a detached view enqueued an action
3239          getRunQueue().executeActions(mAttachInfo.mHandler);
3240  
3241          if (mFirst) {
3242              // make sure touch mode code executes by setting cached value
3243              // to opposite of the added touch mode.
3244              mAttachInfo.mInTouchMode = !mAddedTouchMode;
3245              ensureTouchModeLocally(mAddedTouchMode);
3246          }
3247  
3248          boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
3249          if (layoutRequested) {
3250              if (!mFirst) {
3251                  if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
3252                          || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
3253                      windowSizeMayChange = true;
3254  
3255                      if (shouldUseDisplaySize(lp)) {
3256                          // NOTE -- system code, won't try to do compat mode.
3257                          Point size = new Point();
3258                          mDisplay.getRealSize(size);
3259                          desiredWindowWidth = size.x;
3260                          desiredWindowHeight = size.y;
3261                      } else {
3262                          final Rect bounds = getWindowBoundsInsetSystemBars();
3263                          desiredWindowWidth = bounds.width();
3264                          desiredWindowHeight = bounds.height();
3265                      }
3266                  }
3267              }
3268  
3269              // Ask host how big it wants to be
3270              windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(),
3271                      desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure);
3272          }
3273  
3274          if (collectViewAttributes()) {
3275              params = lp;
3276          }
3277          if (mAttachInfo.mForceReportNewAttributes) {
3278              mAttachInfo.mForceReportNewAttributes = false;
3279              params = lp;
3280          }
3281  
3282          if (mFirst || mAttachInfo.mViewVisibilityChanged) {
3283              mAttachInfo.mViewVisibilityChanged = false;
3284              int resizeMode = mSoftInputMode & SOFT_INPUT_MASK_ADJUST;
3285              // If we are in auto resize mode, then we need to determine
3286              // what mode to use now.
3287              if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
3288                  final int N = mAttachInfo.mScrollContainers.size();
3289                  for (int i=0; i<N; i++) {
3290                      if (mAttachInfo.mScrollContainers.get(i).isShown()) {
3291                          resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
3292                      }
3293                  }
3294                  if (resizeMode == 0) {
3295                      resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
3296                  }
3297                  if ((lp.softInputMode & SOFT_INPUT_MASK_ADJUST) != resizeMode) {
3298                      lp.softInputMode = (lp.softInputMode & ~SOFT_INPUT_MASK_ADJUST) | resizeMode;
3299                      params = lp;
3300                  }
3301              }
3302          }
3303  
3304          if (mApplyInsetsRequested) {
3305              dispatchApplyInsets(host);
3306              if (mLayoutRequested) {
3307                  // Short-circuit catching a new layout request here, so
3308                  // we don't need to go through two layout passes when things
3309                  // change due to fitting system windows, which can happen a lot.
3310                  windowSizeMayChange |= measureHierarchy(host, lp,
3311                          mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight,
3312                          shouldOptimizeMeasure);
3313              }
3314          }
3315  
3316          if (layoutRequested) {
3317              // Clear this now, so that if anything requests a layout in the
3318              // rest of this function we will catch it and re-run a full
3319              // layout pass.
3320              mLayoutRequested = false;
3321          }
3322  
3323          boolean windowShouldResize = layoutRequested && windowSizeMayChange
3324              && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
3325                  || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
3326                          frame.width() < desiredWindowWidth && frame.width() != mWidth)
3327                  || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
3328                          frame.height() < desiredWindowHeight && frame.height() != mHeight));
3329          windowShouldResize |= mDragResizing && mPendingDragResizing;
3330  
3331          // Determine whether to compute insets.
3332          // If there are no inset listeners remaining then we may still need to compute
3333          // insets in case the old insets were non-empty and must be reset.
3334          final boolean computesInternalInsets =
3335                  mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
3336                  || mAttachInfo.mHasNonEmptyGivenInternalInsets;
3337  
3338          boolean insetsPending = false;
3339          int relayoutResult = 0;
3340          boolean updatedConfiguration = false;
3341  
3342          final int surfaceGenerationId = mSurface.getGenerationId();
3343  
3344          final boolean isViewVisible = viewVisibility == View.VISIBLE;
3345          boolean surfaceSizeChanged = false;
3346          boolean surfaceCreated = false;
3347          boolean surfaceDestroyed = false;
3348          // True if surface generation id changes or relayout result is RELAYOUT_RES_SURFACE_CHANGED.
3349          boolean surfaceReplaced = false;
3350  
3351          final boolean windowAttributesChanged = mWindowAttributesChanged;
3352          if (windowAttributesChanged) {
3353              mWindowAttributesChanged = false;
3354              params = lp;
3355          }
3356  
3357          if (params != null) {
3358              if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0
3359                      && !PixelFormat.formatHasAlpha(params.format)) {
3360                  params.format = PixelFormat.TRANSLUCENT;
3361              }
3362              adjustLayoutParamsForCompatibility(params);
3363              controlInsetsForCompatibility(params);
3364              if (mDispatchedSystemBarAppearance != params.insetsFlags.appearance) {
3365                  mDispatchedSystemBarAppearance = params.insetsFlags.appearance;
3366                  mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance);
3367              }
3368          }
3369  
3370          if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
3371                  || mForceNextWindowRelayout) {
3372              if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
3373                  Trace.traceBegin(Trace.TRACE_TAG_VIEW,
3374                          TextUtils.formatSimple("relayoutWindow#"
3375                                          + "first=%b/resize=%b/vis=%b/params=%b/force=%b",
3376                                  mFirst, windowShouldResize, viewVisibilityChanged, params != null,
3377                                  mForceNextWindowRelayout));
3378              }
3379  
3380              mForceNextWindowRelayout = false;
3381  
3382              // If this window is giving internal insets to the window manager, then we want to first
3383              // make the provided insets unchanged during layout. This avoids it briefly causing
3384              // other windows to resize/move based on the raw frame of the window, waiting until we
3385              // can finish laying out this window and get back to the window manager with the
3386              // ultimately computed insets.
3387              insetsPending = computesInternalInsets;
3388  
3389              if (mSurfaceHolder != null) {
3390                  mSurfaceHolder.mSurfaceLock.lock();
3391                  mDrawingAllowed = true;
3392              }
3393  
3394              boolean hwInitialized = false;
3395              boolean dispatchApplyInsets = false;
3396              boolean hadSurface = mSurface.isValid();
3397  
3398              try {
3399                  if (DEBUG_LAYOUT) {
3400                      Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
3401                              host.getMeasuredHeight() + ", params=" + params);
3402                  }
3403  
3404                  if (mFirst || viewVisibilityChanged) {
3405                      mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
3406                  }
3407                  relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
3408                  cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW)
3409                          == RELAYOUT_RES_CANCEL_AND_REDRAW;
3410                  cancelReason = "relayout";
3411                  final boolean dragResizing = mPendingDragResizing;
3412                  if (mSyncSeqId > mLastSyncSeqId) {
3413                      mLastSyncSeqId = mSyncSeqId;
3414                      if (DEBUG_BLAST) {
3415                          Log.d(mTag, "Relayout called with blastSync");
3416                      }
3417                      reportNextDraw("relayout");
3418                      mSyncBuffer = true;
3419                      isSyncRequest = true;
3420                      if (!cancelDraw) {
3421                          mDrewOnceForSync = false;
3422                      }
3423                  }
3424  
3425                  final boolean surfaceControlChanged =
3426                          (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
3427                                  == RELAYOUT_RES_SURFACE_CHANGED;
3428  
3429                  if (mSurfaceControl.isValid()) {
3430                      updateOpacity(mWindowAttributes, dragResizing,
3431                              surfaceControlChanged /*forceUpdate */);
3432                      // No need to updateDisplayDecoration if it's a new SurfaceControl and
3433                      // mDisplayDecorationCached is false, since that's the default for a new
3434                      // SurfaceControl.
3435                      if (surfaceControlChanged && mDisplayDecorationCached) {
3436                          updateDisplayDecoration();
3437                      }
3438                      if (surfaceControlChanged
3439                              && mWindowAttributes.type
3440                              == WindowManager.LayoutParams.TYPE_STATUS_BAR) {
3441                          mTransaction.setDefaultFrameRateCompatibility(mSurfaceControl,
3442                              Surface.FRAME_RATE_COMPATIBILITY_NO_VOTE).apply();
3443                      }
3444                  }
3445  
3446                  if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
3447                          + " surface=" + mSurface);
3448  
3449                  // If the pending {@link MergedConfiguration} handed back from
3450                  // {@link #relayoutWindow} does not match the one last reported,
3451                  // WindowManagerService has reported back a frame from a configuration not yet
3452                  // handled by the client. In this case, we need to accept the configuration so we
3453                  // do not lay out and draw with the wrong configuration.
3454                  if (mRelayoutRequested
3455                          && !mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)) {
3456                      if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
3457                              + mPendingMergedConfiguration.getMergedConfiguration());
3458                      performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration),
3459                              !mFirst, INVALID_DISPLAY /* same display */);
3460                      updatedConfiguration = true;
3461                  }
3462                  final boolean updateSurfaceNeeded = mUpdateSurfaceNeeded;
3463                  mUpdateSurfaceNeeded = false;
3464  
3465                  surfaceSizeChanged = false;
3466                  if (!mLastSurfaceSize.equals(mSurfaceSize)) {
3467                      surfaceSizeChanged = true;
3468                      mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y);
3469                  }
3470                  final boolean alwaysConsumeSystemBarsChanged =
3471                          mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
3472                  updateColorModeIfNeeded(lp.getColorMode());
3473                  surfaceCreated = !hadSurface && mSurface.isValid();
3474                  surfaceDestroyed = hadSurface && !mSurface.isValid();
3475  
3476                  // When using Blast, the surface generation id may not change when there's a new
3477                  // SurfaceControl. In that case, we also check relayout flag
3478                  // RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
3479                  // SurfaceControl.
3480                  surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()
3481                          || surfaceControlChanged) && mSurface.isValid();
3482                  if (surfaceReplaced) {
3483                      mSurfaceSequenceId++;
3484                  }
3485                  if (alwaysConsumeSystemBarsChanged) {
3486                      mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars;
3487                      dispatchApplyInsets = true;
3488                  }
3489                  if (updateCaptionInsets()) {
3490                      dispatchApplyInsets = true;
3491                  }
3492                  if (dispatchApplyInsets || mLastSystemUiVisibility !=
3493                          mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) {
3494                      mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
3495                      dispatchApplyInsets(host);
3496                      // We applied insets so force contentInsetsChanged to ensure the
3497                      // hierarchy is measured below.
3498                      dispatchApplyInsets = true;
3499                  }
3500  
3501                  if (surfaceCreated) {
3502                      // If we are creating a new surface, then we need to
3503                      // completely redraw it.
3504                      mFullRedrawNeeded = true;
3505                      mPreviousTransparentRegion.setEmpty();
3506  
3507                      // Only initialize up-front if transparent regions are not
3508                      // requested, otherwise defer to see if the entire window
3509                      // will be transparent
3510                      if (mAttachInfo.mThreadedRenderer != null) {
3511                          try {
3512                              hwInitialized = mAttachInfo.mThreadedRenderer.initialize(mSurface);
3513                              if (hwInitialized && (host.mPrivateFlags
3514                                              & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
3515                                  // Don't pre-allocate if transparent regions
3516                                  // are requested as they may not be needed
3517                                  mAttachInfo.mThreadedRenderer.allocateBuffers();
3518                              }
3519                          } catch (OutOfResourcesException e) {
3520                              handleOutOfResourcesException(e);
3521                              mLastPerformTraversalsSkipDrawReason = "oom_initialize_renderer";
3522                              return;
3523                          }
3524                      }
3525                  } else if (surfaceDestroyed) {
3526                      // If the surface has been removed, then reset the scroll
3527                      // positions.
3528                      if (mLastScrolledFocus != null) {
3529                          mLastScrolledFocus.clear();
3530                      }
3531                      mScrollY = mCurScrollY = 0;
3532                      if (mView instanceof RootViewSurfaceTaker) {
3533                          ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
3534                      }
3535                      if (mScroller != null) {
3536                          mScroller.abortAnimation();
3537                      }
3538                      // Our surface is gone
3539                      if (isHardwareEnabled()) {
3540                          mAttachInfo.mThreadedRenderer.destroy();
3541                      }
3542                  } else if ((surfaceReplaced || surfaceSizeChanged || updateSurfaceNeeded)
3543                          && mSurfaceHolder == null
3544                          && mAttachInfo.mThreadedRenderer != null
3545                          && mSurface.isValid()) {
3546                      mFullRedrawNeeded = true;
3547                      try {
3548                          // Need to do updateSurface (which leads to CanvasContext::setSurface and
3549                          // re-create the EGLSurface) if either the Surface changed (as indicated by
3550                          // generation id), or WindowManager changed the surface size. The latter is
3551                          // because on some chips, changing the consumer side's BufferQueue size may
3552                          // not take effect immediately unless we create a new EGLSurface.
3553                          // Note that frame size change doesn't always imply surface size change (eg.
3554                          // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
3555                          // flag from WindowManager.
3556                          mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
3557                      } catch (OutOfResourcesException e) {
3558                          handleOutOfResourcesException(e);
3559                          mLastPerformTraversalsSkipDrawReason = "oom_update_surface";
3560                          return;
3561                      }
3562                  }
3563  
3564                  if (mDragResizing != dragResizing) {
3565                      if (dragResizing) {
3566                          final boolean backdropSizeMatchesFrame =
3567                                  mWinFrame.width() == mPendingBackDropFrame.width()
3568                                          && mWinFrame.height() == mPendingBackDropFrame.height();
3569                          // TODO: Need cutout?
3570                          startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame,
3571                                  mAttachInfo.mContentInsets, mAttachInfo.mStableInsets);
3572                      } else {
3573                          // We shouldn't come here, but if we come we should end the resize.
3574                          endDragResizing();
3575                      }
3576                  }
3577                  if (!mUseMTRenderer) {
3578                      if (dragResizing) {
3579                          mCanvasOffsetX = mWinFrame.left;
3580                          mCanvasOffsetY = mWinFrame.top;
3581                      } else {
3582                          mCanvasOffsetX = mCanvasOffsetY = 0;
3583                      }
3584                  }
3585              } catch (RemoteException e) {
3586              } finally {
3587                  if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
3588                      Trace.traceEnd(Trace.TRACE_TAG_VIEW);
3589                  }
3590              }
3591  
3592              if (DEBUG_ORIENTATION) Log.v(
3593                      TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
3594  
3595              mAttachInfo.mWindowLeft = frame.left;
3596              mAttachInfo.mWindowTop = frame.top;
3597  
3598              // !!FIXME!! This next section handles the case where we did not get the
3599              // window size we asked for. We should avoid this by getting a maximum size from
3600              // the window session beforehand.
3601              if (mWidth != frame.width() || mHeight != frame.height()) {
3602                  mWidth = frame.width();
3603                  mHeight = frame.height();
3604              }
3605  
3606              if (mSurfaceHolder != null) {
3607                  // The app owns the surface; tell it about what is going on.
3608                  if (mSurface.isValid()) {
3609                      // XXX .copyFrom() doesn't work!
3610                      //mSurfaceHolder.mSurface.copyFrom(mSurface);
3611                      mSurfaceHolder.mSurface = mSurface;
3612                  }
3613                  mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
3614                  mSurfaceHolder.mSurfaceLock.unlock();
3615                  if (surfaceCreated) {
3616                      mSurfaceHolder.ungetCallbacks();
3617  
3618                      mIsCreating = true;
3619                      SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
3620                      if (callbacks != null) {
3621                          for (SurfaceHolder.Callback c : callbacks) {
3622                              c.surfaceCreated(mSurfaceHolder);
3623                          }
3624                      }
3625                  }
3626  
3627                  if ((surfaceCreated || surfaceReplaced || surfaceSizeChanged
3628                          || windowAttributesChanged) && mSurface.isValid()) {
3629                      SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
3630                      if (callbacks != null) {
3631                          for (SurfaceHolder.Callback c : callbacks) {
3632                              c.surfaceChanged(mSurfaceHolder, lp.format,
3633                                      mWidth, mHeight);
3634                          }
3635                      }
3636                      mIsCreating = false;
3637                  }
3638  
3639                  if (surfaceDestroyed) {
3640                      notifyHolderSurfaceDestroyed();
3641                      mSurfaceHolder.mSurfaceLock.lock();
3642                      try {
3643                          mSurfaceHolder.mSurface = new Surface();
3644                      } finally {
3645                          mSurfaceHolder.mSurfaceLock.unlock();
3646                      }
3647                  }
3648              }
3649  
3650              final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer;
3651              if (threadedRenderer != null && threadedRenderer.isEnabled()) {
3652                  if (hwInitialized
3653                          || mWidth != threadedRenderer.getWidth()
3654                          || mHeight != threadedRenderer.getHeight()
3655                          || mNeedsRendererSetup) {
3656                      threadedRenderer.setup(mWidth, mHeight, mAttachInfo,
3657                              mWindowAttributes.surfaceInsets);
3658                      mNeedsRendererSetup = false;
3659                  }
3660              }
3661  
3662              // TODO: In the CL "ViewRootImpl: Fix issue with early draw report in
3663              // seamless rotation". We moved processing of RELAYOUT_RES_BLAST_SYNC
3664              // earlier in the function, potentially triggering a call to
3665              // reportNextDraw(). That same CL changed this and the next reference
3666              // to wasReportNextDraw, such that this logic would remain undisturbed
3667              // (it continues to operate as if the code was never moved). This was
3668              // done to achieve a more hermetic fix for S, but it's entirely
3669              // possible that checking the most recent value is actually more
3670              // correct here.
3671              if (!mStopped || mReportNextDraw) {
3672                  if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
3673                          || dispatchApplyInsets || updatedConfiguration) {
3674                      int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
3675                              lp.privateFlags);
3676                      int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
3677                              lp.privateFlags);
3678  
3679                      if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed!  mWidth="
3680                              + mWidth + " measuredWidth=" + host.getMeasuredWidth()
3681                              + " mHeight=" + mHeight
3682                              + " measuredHeight=" + host.getMeasuredHeight()
3683                              + " dispatchApplyInsets=" + dispatchApplyInsets);
3684  
3685                       // Ask host how big it wants to be
3686                      performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3687  
3688                      // Implementation of weights from WindowManager.LayoutParams
3689                      // We just grow the dimensions as needed and re-measure if
3690                      // needs be
3691                      int width = host.getMeasuredWidth();
3692                      int height = host.getMeasuredHeight();
3693                      boolean measureAgain = false;
3694  
3695                      if (lp.horizontalWeight > 0.0f) {
3696                          width += (int) ((mWidth - width) * lp.horizontalWeight);
3697                          childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
3698                                  MeasureSpec.EXACTLY);
3699                          measureAgain = true;
3700                      }
3701                      if (lp.verticalWeight > 0.0f) {
3702                          height += (int) ((mHeight - height) * lp.verticalWeight);
3703                          childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
3704                                  MeasureSpec.EXACTLY);
3705                          measureAgain = true;
3706                      }
3707  
3708                      if (measureAgain) {
3709                          if (DEBUG_LAYOUT) Log.v(mTag,
3710                                  "And hey let's measure once more: width=" + width
3711                                  + " height=" + height);
3712                          performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3713                      }
3714  
3715                      layoutRequested = true;
3716                  }
3717              }
3718          } else {
3719              // Not the first pass and no window/insets/visibility change but the window
3720              // may have moved and we need check that and if so to update the left and right
3721              // in the attach info. We translate only the window frame since on window move
3722              // the window manager tells us only for the new frame but the insets are the
3723              // same and we do not want to translate them more than once.
3724              maybeHandleWindowMove(frame);
3725          }
3726  
3727          if (mViewMeasureDeferred) {
3728              // It's time to measure the views since we are going to layout them.
3729              performMeasure(
3730                      MeasureSpec.makeMeasureSpec(frame.width(), MeasureSpec.EXACTLY),
3731                      MeasureSpec.makeMeasureSpec(frame.height(), MeasureSpec.EXACTLY));
3732          }
3733  
3734          if (!mRelayoutRequested && mCheckIfCanDraw) {
3735              // We had a sync previously, but we didn't call IWindowSession#relayout in this
3736              // traversal. So we don't know if the sync is complete that we can continue to draw.
3737              // Here invokes cancelDraw to obtain the information.
3738              try {
3739                  cancelDraw = mWindowSession.cancelDraw(mWindow);
3740                  cancelReason = "wm_sync";
3741                  if (DEBUG_BLAST) {
3742                      Log.d(mTag, "cancelDraw returned " + cancelDraw);
3743                  }
3744              } catch (RemoteException e) {
3745              }
3746          }
3747  
3748          if (surfaceSizeChanged || surfaceReplaced || surfaceCreated ||
3749              windowAttributesChanged || mChildBoundingInsetsChanged) {
3750              // If the surface has been replaced, there's a chance the bounds layer is not parented
3751              // to the new layer. When updating bounds layer, also reparent to the main VRI
3752              // SurfaceControl to ensure it's correctly placed in the hierarchy.
3753              //
3754              // This needs to be done on the client side since WMS won't reparent the children to the
3755              // new surface if it thinks the app is closing. WMS gets the signal that the app is
3756              // stopping, but on the client side it doesn't get stopped since it's restarted quick
3757              // enough. WMS doesn't want to keep around old children since they will leak when the
3758              // client creates new children.
3759              prepareSurfaces();
3760              mChildBoundingInsetsChanged = false;
3761          }
3762  
3763          final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
3764          boolean triggerGlobalLayoutListener = didLayout
3765                  || mAttachInfo.mRecomputeGlobalAttributes;
3766          if (didLayout) {
3767              performLayout(lp, mWidth, mHeight);
3768  
3769              // By this point all views have been sized and positioned
3770              // We can compute the transparent area
3771  
3772              if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
3773                  // start out transparent
3774                  // TODO: AVOID THAT CALL BY CACHING THE RESULT?
3775                  host.getLocationInWindow(mTmpLocation);
3776                  mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
3777                          mTmpLocation[0] + host.mRight - host.mLeft,
3778                          mTmpLocation[1] + host.mBottom - host.mTop);
3779  
3780                  host.gatherTransparentRegion(mTransparentRegion);
3781                  if (mTranslator != null) {
3782                      mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
3783                  }
3784  
3785                  if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
3786                      mPreviousTransparentRegion.set(mTransparentRegion);
3787                      mFullRedrawNeeded = true;
3788                      // TODO: Ideally we would do this in prepareSurfaces,
3789                      // but prepareSurfaces is currently working under
3790                      // the assumption that we paused the render thread
3791                      // via the WM relayout code path. We probably eventually
3792                      // want to synchronize transparent region hint changes
3793                      // with draws.
3794                      SurfaceControl sc = getSurfaceControl();
3795                      if (sc.isValid()) {
3796                          mTransaction.setTransparentRegionHint(sc, mTransparentRegion).apply();
3797                      }
3798                  }
3799              }
3800  
3801              if (DBG) {
3802                  System.out.println("======================================");
3803                  System.out.println("performTraversals -- after setFrame");
3804                  host.debug();
3805              }
3806          }
3807  
3808          boolean didUseTransaction = false;
3809          // These callbacks will trigger SurfaceView SurfaceHolder.Callbacks and must be invoked
3810          // after the measure pass. If its invoked before the measure pass and the app modifies
3811          // the view hierarchy in the callbacks, we could leave the views in a broken state.
3812          if (surfaceCreated) {
3813              notifySurfaceCreated(mTransaction);
3814              didUseTransaction = true;
3815          } else if (surfaceReplaced) {
3816              notifySurfaceReplaced(mTransaction);
3817              didUseTransaction = true;
3818          } else if (surfaceDestroyed)  {
3819              notifySurfaceDestroyed();
3820          }
3821  
3822          if (didUseTransaction) {
3823              applyTransactionOnDraw(mTransaction);
3824          }
3825  
3826          if (triggerGlobalLayoutListener) {
3827              mAttachInfo.mRecomputeGlobalAttributes = false;
3828              mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
3829          }
3830  
3831          Rect contentInsets = null;
3832          Rect visibleInsets = null;
3833          Region touchableRegion = null;
3834          int touchableInsetMode = TOUCHABLE_INSETS_REGION;
3835          boolean computedInternalInsets = false;
3836          if (computesInternalInsets) {
3837              final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
3838  
3839              // Clear the original insets.
3840              insets.reset();
3841  
3842              // Compute new insets in place.
3843              mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
3844              mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
3845  
3846              // Tell the window manager.
3847              if (insetsPending || !mLastGivenInsets.equals(insets)) {
3848                  mLastGivenInsets.set(insets);
3849  
3850                  // Translate insets to screen coordinates if needed.
3851                  if (mTranslator != null) {
3852                      contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
3853                      visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
3854                      touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
3855                  } else {
3856                      contentInsets = insets.contentInsets;
3857                      visibleInsets = insets.visibleInsets;
3858                      touchableRegion = insets.touchableRegion;
3859                  }
3860                  computedInternalInsets = true;
3861              }
3862              touchableInsetMode = insets.mTouchableInsets;
3863          }
3864          boolean needsSetInsets = computedInternalInsets;
3865          needsSetInsets |= !Objects.equals(mPreviousTouchableRegion, mTouchableRegion) &&
3866              (mTouchableRegion != null);
3867          if (needsSetInsets) {
3868              if (mTouchableRegion != null) {
3869                  if (mPreviousTouchableRegion == null) {
3870                      mPreviousTouchableRegion = new Region();
3871                  }
3872                  mPreviousTouchableRegion.set(mTouchableRegion);
3873                  if (touchableInsetMode != TOUCHABLE_INSETS_REGION) {
3874                      Log.e(mTag, "Setting touchableInsetMode to non TOUCHABLE_INSETS_REGION" +
3875                            " from OnComputeInternalInsets, while also using setTouchableRegion" +
3876                            " causes setTouchableRegion to be ignored");
3877                  }
3878              } else {
3879                  mPreviousTouchableRegion = null;
3880              }
3881              if (contentInsets == null) contentInsets = new Rect(0,0,0,0);
3882              if (visibleInsets == null) visibleInsets = new Rect(0,0,0,0);
3883              if (touchableRegion == null) {
3884                  touchableRegion = mTouchableRegion;
3885              } else if (touchableRegion != null && mTouchableRegion != null) {
3886                  touchableRegion.op(touchableRegion, mTouchableRegion, Region.Op.UNION);
3887              }
3888              try {
3889                  mWindowSession.setInsets(mWindow, touchableInsetMode,
3890                                           contentInsets, visibleInsets, touchableRegion);
3891              } catch (RemoteException e) {
3892                  throw e.rethrowFromSystemServer();
3893              }
3894          } else if (mTouchableRegion == null && mPreviousTouchableRegion != null) {
3895              mPreviousTouchableRegion = null;
3896              try {
3897                  mWindowSession.clearTouchableRegion(mWindow);
3898              } catch (RemoteException e) {
3899                  throw e.rethrowFromSystemServer();
3900              }
3901          }
3902  
3903          if (mFirst) {
3904              if (sAlwaysAssignFocus || !isInTouchMode()) {
3905                  // handle first focus request
3906                  if (DEBUG_INPUT_RESIZE) {
3907                      Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus());
3908                  }
3909                  if (mView != null) {
3910                      if (!mView.hasFocus()) {
3911                          mView.restoreDefaultFocus();
3912                          if (DEBUG_INPUT_RESIZE) {
3913                              Log.v(mTag, "First: requested focused view=" + mView.findFocus());
3914                          }
3915                      } else {
3916                          if (DEBUG_INPUT_RESIZE) {
3917                              Log.v(mTag, "First: existing focused view=" + mView.findFocus());
3918                          }
3919                      }
3920                  }
3921              } else {
3922                  // Some views (like ScrollView) won't hand focus to descendants that aren't within
3923                  // their viewport. Before layout, there's a good change these views are size 0
3924                  // which means no children can get focus. After layout, this view now has size, but
3925                  // is not guaranteed to hand-off focus to a focusable child (specifically, the edge-
3926                  // case where the child has a size prior to layout and thus won't trigger
3927                  // focusableViewAvailable).
3928                  View focused = mView.findFocus();
3929                  if (focused instanceof ViewGroup
3930                          && ((ViewGroup) focused).getDescendantFocusability()
3931                                  == ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3932                      focused.restoreDefaultFocus();
3933                  }
3934              }
3935          }
3936  
3937          final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
3938          if (changedVisibility) {
3939              maybeFireAccessibilityWindowStateChangedEvent();
3940          }
3941  
3942          mFirst = false;
3943          mWillDrawSoon = false;
3944          mNewSurfaceNeeded = false;
3945          mViewVisibility = viewVisibility;
3946  
3947          final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
3948          mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
3949  
3950          if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
3951              reportNextDraw("first_relayout");
3952          }
3953  
3954          mCheckIfCanDraw = isSyncRequest || cancelDraw;
3955  
3956          boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
3957          boolean cancelAndRedraw = cancelDueToPreDrawListener
3958                   || (cancelDraw && mDrewOnceForSync);
3959          if (cancelAndRedraw) {
3960              Log.d(mTag, "Cancelling draw."
3961                      + " cancelDueToPreDrawListener=" + cancelDueToPreDrawListener
3962                      + " cancelDueToSync=" + (cancelDraw && mDrewOnceForSync));
3963          }
3964          if (!cancelAndRedraw) {
3965              // A sync was already requested before the WMS requested sync. This means we need to
3966              // sync the buffer, regardless if WMS wants to sync the buffer.
3967              if (mActiveSurfaceSyncGroup != null) {
3968                  mSyncBuffer = true;
3969              }
3970  
3971              createSyncIfNeeded();
3972              notifyDrawStarted(isInWMSRequestedSync());
3973              mDrewOnceForSync = true;
3974  
3975              // If the active SSG is also requesting to sync a buffer, the following needs to happen
3976              // 1. Ensure we keep track of the number of active syncs to know when to disable RT
3977              //    RT animations that conflict with syncing a buffer.
3978              // 2. Add a safeguard SSG to prevent multiple SSG that sync buffers from being submitted
3979              //    out of order.
3980              if (mActiveSurfaceSyncGroup != null && mSyncBuffer) {
3981                  updateSyncInProgressCount(mActiveSurfaceSyncGroup);
3982                  safeguardOverlappingSyncs(mActiveSurfaceSyncGroup);
3983              }
3984          }
3985  
3986          if (!isViewVisible) {
3987              mLastPerformTraversalsSkipDrawReason = "view_not_visible";
3988              if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
3989                  for (int i = 0; i < mPendingTransitions.size(); ++i) {
3990                      mPendingTransitions.get(i).endChangingAnimations();
3991                  }
3992                  mPendingTransitions.clear();
3993              }
3994  
3995              if (mActiveSurfaceSyncGroup != null) {
3996                  mActiveSurfaceSyncGroup.markSyncReady();
3997              }
3998          } else if (cancelAndRedraw) {
3999              mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
4000                  ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
4001                  : "cancel_" + cancelReason;
4002              // Try again
4003              scheduleTraversals();
4004          } else {
4005              if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
4006                  for (int i = 0; i < mPendingTransitions.size(); ++i) {
4007                      mPendingTransitions.get(i).startChangingAnimations();
4008                  }
4009                  mPendingTransitions.clear();
4010              }
4011              if (!performDraw(mActiveSurfaceSyncGroup) && mActiveSurfaceSyncGroup != null) {
4012                  mActiveSurfaceSyncGroup.markSyncReady();
4013              }
4014          }
4015  
4016          if (mAttachInfo.mContentCaptureEvents != null) {
4017              notifyContentCaptureEvents();
4018          }
4019  
4020          mIsInTraversal = false;
4021          mRelayoutRequested = false;
4022  
4023          if (!cancelAndRedraw) {
4024              mReportNextDraw = false;
4025              mLastReportNextDrawReason = null;
4026              mActiveSurfaceSyncGroup = null;
4027              mSyncBuffer = false;
4028              if (isInWMSRequestedSync()) {
4029                  mWmsRequestSyncGroup.markSyncReady();
4030                  mWmsRequestSyncGroup = null;
4031                  mWmsRequestSyncGroupState = WMS_SYNC_NONE;
4032              }
4033          }
4034      }
4035  
createSyncIfNeeded()4036      private void createSyncIfNeeded() {
4037          // WMS requested sync already started or there's nothing needing to sync
4038          if (isInWMSRequestedSync() || !mReportNextDraw) {
4039              return;
4040          }
4041  
4042          final int seqId = mSyncSeqId;
4043          mWmsRequestSyncGroupState = WMS_SYNC_PENDING;
4044          mWmsRequestSyncGroup = new SurfaceSyncGroup("wmsSync-" + mTag, t -> {
4045              mWmsRequestSyncGroupState = WMS_SYNC_MERGED;
4046              // See b/286355097. If the current process is not system, then invoking finishDraw on
4047              // any thread is fine since once it calls into system process, finishDrawing will run
4048              // on a different thread. However, when the current process is system, the finishDraw in
4049              // system server will be run on the current thread, which could result in a deadlock.
4050              if (mWindowSession instanceof Binder) {
4051                  reportDrawFinished(t, seqId);
4052              } else {
4053                  mHandler.postAtFrontOfQueue(() -> reportDrawFinished(t, seqId));
4054              }
4055          });
4056          if (DEBUG_BLAST) {
4057              Log.d(mTag, "Setup new sync=" + mWmsRequestSyncGroup.getName());
4058          }
4059  
4060          mWmsRequestSyncGroup.add(this, null /* runnable */);
4061      }
4062  
notifyContentCaptureEvents()4063      private void notifyContentCaptureEvents() {
4064          Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
4065          try {
4066              MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
4067                      .getMainContentCaptureSession();
4068              for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) {
4069                  int sessionId = mAttachInfo.mContentCaptureEvents.keyAt(i);
4070                  mainSession.notifyViewTreeEvent(sessionId, /* started= */ true);
4071                  ArrayList<Object> events = mAttachInfo.mContentCaptureEvents
4072                          .valueAt(i);
4073                  for_each_event: for (int j = 0; j < events.size(); j++) {
4074                      Object event = events.get(j);
4075                      if (event instanceof AutofillId) {
4076                          mainSession.notifyViewDisappeared(sessionId, (AutofillId) event);
4077                      } else if (event instanceof View) {
4078                          View view = (View) event;
4079                          ContentCaptureSession session = view.getContentCaptureSession();
4080                          if (session == null) {
4081                              Log.w(mTag, "no content capture session on view: " + view);
4082                              continue for_each_event;
4083                          }
4084                          int actualId = session.getId();
4085                          if (actualId != sessionId) {
4086                              Log.w(mTag, "content capture session mismatch for view (" + view
4087                                      + "): was " + sessionId + " before, it's " + actualId + " now");
4088                              continue for_each_event;
4089                          }
4090                          ViewStructure structure = session.newViewStructure(view);
4091                          view.onProvideContentCaptureStructure(structure, /* flags= */ 0);
4092                          session.notifyViewAppeared(structure);
4093                      } else if (event instanceof Insets) {
4094                          mainSession.notifyViewInsetsChanged(sessionId, (Insets) event);
4095                      } else {
4096                          Log.w(mTag, "invalid content capture event: " + event);
4097                      }
4098                  }
4099                  mainSession.notifyViewTreeEvent(sessionId, /* started= */ false);
4100              }
4101              mAttachInfo.mContentCaptureEvents = null;
4102          } finally {
4103              Trace.traceEnd(Trace.TRACE_TAG_VIEW);
4104          }
4105      }
4106  
notifyHolderSurfaceDestroyed()4107      private void notifyHolderSurfaceDestroyed() {
4108          mSurfaceHolder.ungetCallbacks();
4109          SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
4110          if (callbacks != null) {
4111              for (SurfaceHolder.Callback c : callbacks) {
4112                  c.surfaceDestroyed(mSurfaceHolder);
4113              }
4114          }
4115      }
4116  
maybeHandleWindowMove(Rect frame)4117      private void maybeHandleWindowMove(Rect frame) {
4118          // TODO: Well, we are checking whether the frame has changed similarly
4119          // to how this is done for the insets. This is however incorrect since
4120          // the insets and the frame are translated. For example, the old frame
4121          // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
4122          // reported frame is (2, 2 - 2, 2) which implies no change but this is not
4123          // true since we are comparing a not translated value to a translated one.
4124          // This scenario is rare but we may want to fix that.
4125  
4126          final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left
4127                  || mAttachInfo.mWindowTop != frame.top;
4128          if (windowMoved) {
4129              mAttachInfo.mWindowLeft = frame.left;
4130              mAttachInfo.mWindowTop = frame.top;
4131          }
4132          if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) {
4133              // Update the light position for the new offsets.
4134              if (mAttachInfo.mThreadedRenderer != null) {
4135                  mAttachInfo.mThreadedRenderer.setLightCenter(mAttachInfo);
4136              }
4137              mAttachInfo.mNeedsUpdateLightCenter = false;
4138          }
4139      }
4140  
handleWindowFocusChanged()4141      private void handleWindowFocusChanged() {
4142          final boolean hasWindowFocus;
4143          synchronized (this) {
4144              if (!mWindowFocusChanged) {
4145                  return;
4146              }
4147              mWindowFocusChanged = false;
4148              hasWindowFocus = mUpcomingWindowFocus;
4149          }
4150          // TODO (b/131181940): Make sure this doesn't leak Activity with mActivityConfigCallback
4151          // config changes.
4152          if (hasWindowFocus) {
4153              mInsetsController.onWindowFocusGained(
4154                      getFocusedViewOrNull() != null /* hasViewFocused */);
4155          } else {
4156              mInsetsController.onWindowFocusLost();
4157          }
4158  
4159          if (mAdded) {
4160              dispatchFocusEvent(hasWindowFocus, false /* fakeFocus */);
4161              // Note: must be done after the focus change callbacks,
4162              // so all of the view state is set up correctly.
4163              mImeFocusController.onPostWindowFocus(
4164                      getFocusedViewOrNull(), hasWindowFocus, mWindowAttributes);
4165  
4166              if (hasWindowFocus) {
4167                  // Clear the forward bit.  We can just do this directly, since
4168                  // the window manager doesn't care about it.
4169                  mWindowAttributes.softInputMode &=
4170                          ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
4171                  ((WindowManager.LayoutParams) mView.getLayoutParams())
4172                          .softInputMode &=
4173                          ~WindowManager.LayoutParams
4174                                  .SOFT_INPUT_IS_FORWARD_NAVIGATION;
4175  
4176                  maybeFireAccessibilityWindowStateChangedEvent();
4177  
4178                  // Refocusing a window that has a focused view should fire a
4179                  // focus event for the view since the global focused view changed.
4180                  fireAccessibilityFocusEventIfHasFocusedNode();
4181              } else {
4182                  if (mPointerCapture) {
4183                      handlePointerCaptureChanged(false);
4184                  }
4185              }
4186          }
4187          mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
4188  
4189          // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus
4190          // is lost, so we don't need to to force a flush - there might be other events such as
4191          // text changes, but these should be flushed independently.
4192          if (hasWindowFocus) {
4193              handleContentCaptureFlush();
4194          }
4195      }
4196  
4197      /**
4198       * Send a fake focus event for unfocused apps in split screen as some game engines wait to
4199       * get focus before drawing the content of the app. This will be used so that apps do not get
4200       * blacked out when they are resumed and do not have focus yet.
4201       *
4202       * {@hide}
4203       */
4204      // TODO(b/263094829): Investigate dispatching this for onPause as well
dispatchCompatFakeFocus()4205      public void dispatchCompatFakeFocus() {
4206          boolean aboutToHaveFocus = false;
4207          synchronized (this) {
4208              aboutToHaveFocus = mWindowFocusChanged && mUpcomingWindowFocus;
4209          }
4210          final boolean alreadyHaveFocus = mAttachInfo.mHasWindowFocus;
4211          if (aboutToHaveFocus || alreadyHaveFocus) {
4212              // Do not need to toggle focus if app doesn't need it, or has focus.
4213              return;
4214          }
4215          EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
4216                  "Giving fake focus to " + mBasePackageName, "reason=unity bug workaround");
4217          dispatchFocusEvent(true /* hasWindowFocus */, true /* fakeFocus */);
4218          EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
4219                  "Removing fake focus from " + mBasePackageName, "reason=timeout callback");
4220          dispatchFocusEvent(false /* hasWindowFocus */, true /* fakeFocus */);
4221      }
4222  
dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus)4223      private void dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus) {
4224          profileRendering(hasWindowFocus);
4225          if (hasWindowFocus && mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
4226              mFullRedrawNeeded = true;
4227              try {
4228                  final Rect surfaceInsets = mWindowAttributes.surfaceInsets;
4229                  mAttachInfo.mThreadedRenderer.initializeIfNeeded(
4230                          mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
4231              } catch (OutOfResourcesException e) {
4232                  Log.e(mTag, "OutOfResourcesException locking surface", e);
4233                  try {
4234                      if (!mWindowSession.outOfMemory(mWindow)) {
4235                          Slog.w(mTag, "No processes killed for memory;"
4236                                  + " killing self");
4237                          Process.killProcess(Process.myPid());
4238                      }
4239                  } catch (RemoteException ex) {
4240                  }
4241                  // Retry in a bit.
4242                  mHandler.sendMessageDelayed(mHandler.obtainMessage(
4243                          MSG_WINDOW_FOCUS_CHANGED), 500);
4244                  return;
4245              }
4246          }
4247  
4248          mAttachInfo.mHasWindowFocus = hasWindowFocus;
4249  
4250          if (!fakeFocus) {
4251              mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes);
4252          }
4253  
4254          if (mView != null) {
4255              mAttachInfo.mKeyDispatchState.reset();
4256              mView.dispatchWindowFocusChanged(hasWindowFocus);
4257              mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
4258              if (mAttachInfo.mTooltipHost != null) {
4259                  mAttachInfo.mTooltipHost.hideTooltip();
4260              }
4261          }
4262      }
4263  
handleWindowTouchModeChanged()4264      private void handleWindowTouchModeChanged() {
4265          final boolean inTouchMode;
4266          synchronized (this) {
4267              inTouchMode = mUpcomingInTouchMode;
4268          }
4269          ensureTouchModeLocally(inTouchMode);
4270      }
4271  
maybeFireAccessibilityWindowStateChangedEvent()4272      private void maybeFireAccessibilityWindowStateChangedEvent() {
4273          // Toasts are presented as notifications - don't present them as windows as well.
4274          boolean isToast = mWindowAttributes != null && (mWindowAttributes.type == TYPE_TOAST);
4275          if (!isToast && mView != null) {
4276              mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
4277          }
4278      }
4279  
fireAccessibilityFocusEventIfHasFocusedNode()4280      private void fireAccessibilityFocusEventIfHasFocusedNode() {
4281          if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
4282              return;
4283          }
4284          final View focusedView = mView.findFocus();
4285          if (focusedView == null) {
4286              return;
4287          }
4288          final AccessibilityNodeProvider provider = focusedView.getAccessibilityNodeProvider();
4289          if (provider == null) {
4290              focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
4291          } else {
4292              final AccessibilityNodeInfo focusedNode = findFocusedVirtualNode(provider);
4293              if (focusedNode != null) {
4294                  final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
4295                          focusedNode.getSourceNodeId());
4296                  // This is a best effort since clearing and setting the focus via the
4297                  // provider APIs could have side effects. We don't have a provider API
4298                  // similar to that on View to ask a given event to be fired.
4299                  final AccessibilityEvent event = AccessibilityEvent.obtain(
4300                          AccessibilityEvent.TYPE_VIEW_FOCUSED);
4301                  event.setSource(focusedView, virtualId);
4302                  event.setPackageName(focusedNode.getPackageName());
4303                  event.setChecked(focusedNode.isChecked());
4304                  event.setContentDescription(focusedNode.getContentDescription());
4305                  event.setPassword(focusedNode.isPassword());
4306                  event.getText().add(focusedNode.getText());
4307                  event.setEnabled(focusedNode.isEnabled());
4308                  focusedView.getParent().requestSendAccessibilityEvent(focusedView, event);
4309                  focusedNode.recycle();
4310              }
4311          }
4312      }
4313  
findFocusedVirtualNode(AccessibilityNodeProvider provider)4314      private AccessibilityNodeInfo findFocusedVirtualNode(AccessibilityNodeProvider provider) {
4315          AccessibilityNodeInfo focusedNode = provider.findFocus(
4316                  AccessibilityNodeInfo.FOCUS_INPUT);
4317          if (focusedNode != null) {
4318              return focusedNode;
4319          }
4320  
4321          if (!mContext.isAutofillCompatibilityEnabled()) {
4322              return null;
4323          }
4324  
4325          // Unfortunately some provider implementations don't properly
4326          // implement AccessibilityNodeProvider#findFocus
4327          AccessibilityNodeInfo current = provider.createAccessibilityNodeInfo(
4328                  AccessibilityNodeProvider.HOST_VIEW_ID);
4329          if (current.isFocused()) {
4330              return current;
4331          }
4332  
4333          final Queue<AccessibilityNodeInfo> fringe = new ArrayDeque<>();
4334          fringe.offer(current);
4335  
4336          while (!fringe.isEmpty()) {
4337              current = fringe.poll();
4338              final LongArray childNodeIds = current.getChildNodeIds();
4339              if (childNodeIds== null || childNodeIds.size() <= 0) {
4340                  continue;
4341              }
4342              final int childCount = childNodeIds.size();
4343              for (int i = 0; i < childCount; i++) {
4344                  final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
4345                          childNodeIds.get(i));
4346                  final AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(virtualId);
4347                  if (child != null) {
4348                      if (child.isFocused()) {
4349                          return child;
4350                      }
4351                      fringe.offer(child);
4352                  }
4353              }
4354              current.recycle();
4355          }
4356  
4357          return null;
4358      }
4359  
handleOutOfResourcesException(Surface.OutOfResourcesException e)4360      private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
4361          Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
4362          try {
4363              if (!mWindowSession.outOfMemory(mWindow) &&
4364                      Process.myUid() != Process.SYSTEM_UID) {
4365                  Slog.w(mTag, "No processes killed for memory; killing self");
4366                  Process.killProcess(Process.myPid());
4367              }
4368          } catch (RemoteException ex) {
4369          }
4370          mLayoutRequested = true;    // ask wm for a new surface next time.
4371      }
4372  
performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec)4373      private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
4374          if (mView == null) {
4375              return;
4376          }
4377          Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
4378          try {
4379              mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4380          } finally {
4381              Trace.traceEnd(Trace.TRACE_TAG_VIEW);
4382          }
4383          mMeasuredWidth = mView.getMeasuredWidth();
4384          mMeasuredHeight = mView.getMeasuredHeight();
4385          mViewMeasureDeferred = false;
4386      }
4387  
4388      /**
4389       * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
4390       * is currently undergoing a layout pass.
4391       *
4392       * @return whether the view hierarchy is currently undergoing a layout pass
4393       */
isInLayout()4394      boolean isInLayout() {
4395          return mInLayout;
4396      }
4397  
4398      /**
4399       * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
4400       * undergoing a layout pass. requestLayout() should not generally be called during layout,
4401       * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
4402       * all children in that container hierarchy are measured and laid out at the end of the layout
4403       * pass for that container). If requestLayout() is called anyway, we handle it correctly
4404       * by registering all requesters during a frame as it proceeds. At the end of the frame,
4405       * we check all of those views to see if any still have pending layout requests, which
4406       * indicates that they were not correctly handled by their container hierarchy. If that is
4407       * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
4408       * to blank containers, and force a second request/measure/layout pass in this frame. If
4409       * more requestLayout() calls are received during that second layout pass, we post those
4410       * requests to the next frame to avoid possible infinite loops.
4411       *
4412       * <p>The return value from this method indicates whether the request should proceed
4413       * (if it is a request during the first layout pass) or should be skipped and posted to the
4414       * next frame (if it is a request during the second layout pass).</p>
4415       *
4416       * @param view the view that requested the layout.
4417       *
4418       * @return true if request should proceed, false otherwise.
4419       */
requestLayoutDuringLayout(final View view)4420      boolean requestLayoutDuringLayout(final View view) {
4421          if (view.mParent == null || view.mAttachInfo == null) {
4422              // Would not normally trigger another layout, so just let it pass through as usual
4423              return true;
4424          }
4425          if (!mLayoutRequesters.contains(view)) {
4426              mLayoutRequesters.add(view);
4427          }
4428          if (!mHandlingLayoutInLayoutRequest) {
4429              // Let the request proceed normally; it will be processed in a second layout pass
4430              // if necessary
4431              return true;
4432          } else {
4433              // Don't let the request proceed during the second layout pass.
4434              // It will post to the next frame instead.
4435              return false;
4436          }
4437      }
4438  
performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight)4439      private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
4440              int desiredWindowHeight) {
4441          mScrollMayChange = true;
4442          mInLayout = true;
4443  
4444          final View host = mView;
4445          if (host == null) {
4446              return;
4447          }
4448          if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
4449              Log.v(mTag, "Laying out " + host + " to (" +
4450                      host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
4451          }
4452  
4453          Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
4454          try {
4455              host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
4456  
4457              mInLayout = false;
4458              int numViewsRequestingLayout = mLayoutRequesters.size();
4459              if (numViewsRequestingLayout > 0) {
4460                  // requestLayout() was called during layout.
4461                  // If no layout-request flags are set on the requesting views, there is no problem.
4462                  // If some requests are still pending, then we need to clear those flags and do
4463                  // a full request/measure/layout pass to handle this situation.
4464                  ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
4465                          false);
4466                  if (validLayoutRequesters != null) {
4467                      // Set this flag to indicate that any further requests are happening during
4468                      // the second pass, which may result in posting those requests to the next
4469                      // frame instead
4470                      mHandlingLayoutInLayoutRequest = true;
4471  
4472                      // Process fresh layout requests, then measure and layout
4473                      int numValidRequests = validLayoutRequesters.size();
4474                      for (int i = 0; i < numValidRequests; ++i) {
4475                          final View view = validLayoutRequesters.get(i);
4476                          Log.w("View", "requestLayout() improperly called by " + view +
4477                                  " during layout: running second layout pass");
4478                          view.requestLayout();
4479                      }
4480                      measureHierarchy(host, lp, mView.getContext().getResources(),
4481                              desiredWindowWidth, desiredWindowHeight, false /* forRootSizeOnly */);
4482                      mInLayout = true;
4483                      host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
4484  
4485                      mHandlingLayoutInLayoutRequest = false;
4486  
4487                      // Check the valid requests again, this time without checking/clearing the
4488                      // layout flags, since requests happening during the second pass get noop'd
4489                      validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
4490                      if (validLayoutRequesters != null) {
4491                          final ArrayList<View> finalRequesters = validLayoutRequesters;
4492                          // Post second-pass requests to the next frame
4493                          getRunQueue().post(new Runnable() {
4494                              @Override
4495                              public void run() {
4496                                  int numValidRequests = finalRequesters.size();
4497                                  for (int i = 0; i < numValidRequests; ++i) {
4498                                      final View view = finalRequesters.get(i);
4499                                      Log.w("View", "requestLayout() improperly called by " + view +
4500                                              " during second layout pass: posting in next frame");
4501                                      view.requestLayout();
4502                                  }
4503                              }
4504                          });
4505                      }
4506                  }
4507  
4508              }
4509          } finally {
4510              Trace.traceEnd(Trace.TRACE_TAG_VIEW);
4511          }
4512          mInLayout = false;
4513      }
4514  
4515      /**
4516       * This method is called during layout when there have been calls to requestLayout() during
4517       * layout. It walks through the list of views that requested layout to determine which ones
4518       * still need it, based on visibility in the hierarchy and whether they have already been
4519       * handled (as is usually the case with ListView children).
4520       *
4521       * @param layoutRequesters The list of views that requested layout during layout
4522       * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
4523       * If so, the FORCE_LAYOUT flag was not set on requesters.
4524       * @return A list of the actual views that still need to be laid out.
4525       */
getValidLayoutRequesters(ArrayList<View> layoutRequesters, boolean secondLayoutRequests)4526      private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
4527              boolean secondLayoutRequests) {
4528  
4529          int numViewsRequestingLayout = layoutRequesters.size();
4530          ArrayList<View> validLayoutRequesters = null;
4531          for (int i = 0; i < numViewsRequestingLayout; ++i) {
4532              View view = layoutRequesters.get(i);
4533              if (view != null && view.mAttachInfo != null && view.mParent != null &&
4534                      (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
4535                              View.PFLAG_FORCE_LAYOUT)) {
4536                  boolean gone = false;
4537                  View parent = view;
4538                  // Only trigger new requests for views in a non-GONE hierarchy
4539                  while (parent != null) {
4540                      if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
4541                          gone = true;
4542                          break;
4543                      }
4544                      if (parent.mParent instanceof View) {
4545                          parent = (View) parent.mParent;
4546                      } else {
4547                          parent = null;
4548                      }
4549                  }
4550                  if (!gone) {
4551                      if (validLayoutRequesters == null) {
4552                          validLayoutRequesters = new ArrayList<View>();
4553                      }
4554                      validLayoutRequesters.add(view);
4555                  }
4556              }
4557          }
4558          if (!secondLayoutRequests) {
4559              // If we're checking the layout flags, then we need to clean them up also
4560              for (int i = 0; i < numViewsRequestingLayout; ++i) {
4561                  View view = layoutRequesters.get(i);
4562                  while (view != null &&
4563                          (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
4564                      view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
4565                      if (view.mParent instanceof View) {
4566                          view = (View) view.mParent;
4567                      } else {
4568                          view = null;
4569                      }
4570                  }
4571              }
4572          }
4573          layoutRequesters.clear();
4574          return validLayoutRequesters;
4575      }
4576  
4577      @Override
requestTransparentRegion(View child)4578      public void requestTransparentRegion(View child) {
4579          // the test below should not fail unless someone is messing with us
4580          checkThread();
4581          if (mView != child) {
4582              return;
4583          }
4584  
4585          if ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
4586              mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
4587              // Need to make sure we re-evaluate the window attributes next
4588              // time around, to ensure the window has the correct format.
4589              mWindowAttributesChanged = true;
4590          }
4591  
4592          // Always request layout to apply the latest transparent region.
4593          requestLayout();
4594      }
4595  
4596      /**
4597       * Figures out the measure spec for the root view in a window based on it's
4598       * layout params.
4599       *
4600       * @param windowSize The available width or height of the window.
4601       * @param measurement The layout width or height requested in the layout params.
4602       * @param privateFlags The private flags in the layout params of the window.
4603       * @return The measure spec to use to measure the root view.
4604       */
getRootMeasureSpec(int windowSize, int measurement, int privateFlags)4605      private static int getRootMeasureSpec(int windowSize, int measurement, int privateFlags) {
4606          int measureSpec;
4607          final int rootDimension = (privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0
4608                  ? MATCH_PARENT : measurement;
4609          switch (rootDimension) {
4610              case ViewGroup.LayoutParams.MATCH_PARENT:
4611                  // Window can't resize. Force root view to be windowSize.
4612                  measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
4613                  break;
4614              case ViewGroup.LayoutParams.WRAP_CONTENT:
4615                  // Window can resize. Set max size for root view.
4616                  measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
4617                  break;
4618              default:
4619                  // Window wants to be an exact size. Force root view to be that size.
4620                  measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
4621                  break;
4622          }
4623          return measureSpec;
4624      }
4625  
4626      int mHardwareXOffset;
4627      int mHardwareYOffset;
4628  
4629      @Override
onPreDraw(RecordingCanvas canvas)4630      public void onPreDraw(RecordingCanvas canvas) {
4631          // If mCurScrollY is not 0 then this influences the hardwareYOffset. The end result is we
4632          // can apply offsets that are not handled by anything else, resulting in underdraw as
4633          // the View is shifted (thus shifting the window background) exposing unpainted
4634          // content. To handle this with minimal glitches we just clear to BLACK if the window
4635          // is opaque. If it's not opaque then HWUI already internally does a glClear to
4636          // transparent, so there's no risk of underdraw on non-opaque surfaces.
4637          if (mCurScrollY != 0 && mHardwareYOffset != 0 && mAttachInfo.mThreadedRenderer.isOpaque()) {
4638              canvas.drawColor(Color.BLACK);
4639          }
4640          canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
4641      }
4642  
4643      @Override
onPostDraw(RecordingCanvas canvas)4644      public void onPostDraw(RecordingCanvas canvas) {
4645          drawAccessibilityFocusedDrawableIfNeeded(canvas);
4646          if (mUseMTRenderer) {
4647              for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
4648                  mWindowCallbacks.get(i).onPostDraw(canvas);
4649              }
4650          }
4651      }
4652  
4653      /**
4654       * @hide
4655       */
outputDisplayList(View view)4656      void outputDisplayList(View view) {
4657          view.mRenderNode.output();
4658      }
4659  
4660      /**
4661       * @see #PROPERTY_PROFILE_RENDERING
4662       */
profileRendering(boolean enabled)4663      private void profileRendering(boolean enabled) {
4664          if (mProfileRendering) {
4665              mRenderProfilingEnabled = enabled;
4666  
4667              if (mRenderProfiler != null) {
4668                  mChoreographer.removeFrameCallback(mRenderProfiler);
4669              }
4670              if (mRenderProfilingEnabled) {
4671                  if (mRenderProfiler == null) {
4672                      mRenderProfiler = new Choreographer.FrameCallback() {
4673                          @Override
4674                          public void doFrame(long frameTimeNanos) {
4675                              mDirty.set(0, 0, mWidth, mHeight);
4676                              scheduleTraversals();
4677                              if (mRenderProfilingEnabled) {
4678                                  mChoreographer.postFrameCallback(mRenderProfiler);
4679                              }
4680                          }
4681                      };
4682                  }
4683                  mChoreographer.postFrameCallback(mRenderProfiler);
4684              } else {
4685                  mRenderProfiler = null;
4686              }
4687          }
4688      }
4689  
4690      /**
4691       * Called from draw() when DEBUG_FPS is enabled
4692       */
trackFPS()4693      private void trackFPS() {
4694          // Tracks frames per second drawn. First value in a series of draws may be bogus
4695          // because it down not account for the intervening idle time
4696          long nowTime = System.currentTimeMillis();
4697          if (mFpsStartTime < 0) {
4698              mFpsStartTime = mFpsPrevTime = nowTime;
4699              mFpsNumFrames = 0;
4700          } else {
4701              ++mFpsNumFrames;
4702              String thisHash = Integer.toHexString(System.identityHashCode(this));
4703              long frameTime = nowTime - mFpsPrevTime;
4704              long totalTime = nowTime - mFpsStartTime;
4705              Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
4706              mFpsPrevTime = nowTime;
4707              if (totalTime > 1000) {
4708                  float fps = (float) mFpsNumFrames * 1000 / totalTime;
4709                  Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
4710                  mFpsStartTime = nowTime;
4711                  mFpsNumFrames = 0;
4712              }
4713          }
4714      }
4715  
reportDrawFinished(@ullable Transaction t, int seqId)4716      private void reportDrawFinished(@Nullable Transaction t, int seqId) {
4717          if (DEBUG_BLAST) {
4718              Log.d(mTag, "reportDrawFinished");
4719          }
4720  
4721          if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
4722              Trace.instant(Trace.TRACE_TAG_VIEW, "reportDrawFinished " + mTag + " seqId=" + seqId);
4723          }
4724          try {
4725              mWindowSession.finishDrawing(mWindow, t, seqId);
4726          } catch (RemoteException e) {
4727              Log.e(mTag, "Unable to report draw finished", e);
4728              if (t != null) {
4729                  t.apply();
4730              }
4731          } finally {
4732              if (t != null) {
4733                  t.clear();
4734              }
4735          }
4736      }
4737  
4738      /**
4739       * @hide
4740       */
isHardwareEnabled()4741      public boolean isHardwareEnabled() {
4742          return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled();
4743      }
4744  
4745      /**
4746       * This VRI is currently in the middle of a sync request that was initiated by WMS.
4747       */
isInWMSRequestedSync()4748      public boolean isInWMSRequestedSync() {
4749          return mWmsRequestSyncGroup != null;
4750      }
4751  
addFrameCommitCallbackIfNeeded()4752      private void addFrameCommitCallbackIfNeeded() {
4753          if (!isHardwareEnabled()) {
4754              return;
4755          }
4756  
4757          ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
4758                  .captureFrameCommitCallbacks();
4759          final boolean needFrameCommitCallback =
4760                  (commitCallbacks != null && commitCallbacks.size() > 0);
4761          if (!needFrameCommitCallback) {
4762              return;
4763          }
4764  
4765          if (DEBUG_DRAW) {
4766              Log.d(mTag, "Creating frameCommitCallback"
4767                      + " commitCallbacks size=" + commitCallbacks.size());
4768          }
4769          mAttachInfo.mThreadedRenderer.setFrameCommitCallback(didProduceBuffer -> {
4770              if (DEBUG_DRAW) {
4771                  Log.d(mTag, "Received frameCommitCallback didProduceBuffer=" + didProduceBuffer);
4772              }
4773  
4774              mHandler.postAtFrontOfQueue(() -> {
4775                  for (int i = 0; i < commitCallbacks.size(); i++) {
4776                      commitCallbacks.get(i).run();
4777                  }
4778              });
4779          });
4780      }
4781  
4782      /**
4783       * These callbacks check if the draw failed for any reason and apply
4784       * those transactions directly so they don't get stuck forever.
4785       */
registerCallbackForPendingTransactions()4786      private void registerCallbackForPendingTransactions() {
4787          Transaction t = new Transaction();
4788          t.merge(mPendingTransaction);
4789  
4790          registerRtFrameCallback(new FrameDrawingCallback() {
4791              @Override
4792              public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
4793                  mergeWithNextTransaction(t, frame);
4794                  if ((syncResult
4795                          & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
4796                      mBlastBufferQueue.applyPendingTransactions(frame);
4797                      return null;
4798                  }
4799  
4800                  return didProduceBuffer -> {
4801                      if (!didProduceBuffer) {
4802                          mBlastBufferQueue.applyPendingTransactions(frame);
4803                      }
4804                  };
4805  
4806              }
4807  
4808              @Override
4809              public void onFrameDraw(long frame) {
4810              }
4811          });
4812      }
4813  
performDraw(@ullable SurfaceSyncGroup surfaceSyncGroup)4814      private boolean performDraw(@Nullable SurfaceSyncGroup surfaceSyncGroup) {
4815          mLastPerformDrawSkippedReason = null;
4816          if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
4817              mLastPerformDrawSkippedReason = "screen_off";
4818              return false;
4819          } else if (mView == null) {
4820              mLastPerformDrawSkippedReason = "no_root_view";
4821              return false;
4822          }
4823  
4824          final boolean fullRedrawNeeded = mFullRedrawNeeded || surfaceSyncGroup != null;
4825          mFullRedrawNeeded = false;
4826  
4827          mIsDrawing = true;
4828          Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
4829  
4830          addFrameCommitCallbackIfNeeded();
4831  
4832          boolean usingAsyncReport;
4833  
4834          try {
4835              usingAsyncReport = draw(fullRedrawNeeded, surfaceSyncGroup, mSyncBuffer);
4836              if (mAttachInfo.mThreadedRenderer != null && !usingAsyncReport) {
4837                  mAttachInfo.mThreadedRenderer.setFrameCallback(null);
4838              }
4839          } finally {
4840              mIsDrawing = false;
4841              Trace.traceEnd(Trace.TRACE_TAG_VIEW);
4842          }
4843  
4844          // For whatever reason we didn't create a HardwareRenderer, end any
4845          // hardware animations that are now dangling
4846          if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
4847              final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
4848              for (int i = 0; i < count; i++) {
4849                  mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
4850              }
4851              mAttachInfo.mPendingAnimatingRenderNodes.clear();
4852          }
4853  
4854          if (mReportNextDraw) {
4855  
4856              // if we're using multi-thread renderer, wait for the window frame draws
4857              if (mWindowDrawCountDown != null) {
4858                  try {
4859                      mWindowDrawCountDown.await();
4860                  } catch (InterruptedException e) {
4861                      Log.e(mTag, "Window redraw count down interrupted!");
4862                  }
4863                  mWindowDrawCountDown = null;
4864              }
4865  
4866              if (mAttachInfo.mThreadedRenderer != null) {
4867                  mAttachInfo.mThreadedRenderer.setStopped(mStopped);
4868              }
4869  
4870              if (LOCAL_LOGV) {
4871                  Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
4872              }
4873  
4874              if (mSurfaceHolder != null && mSurface.isValid()) {
4875                  usingAsyncReport = true;
4876                  SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> {
4877                      if (surfaceSyncGroup != null) {
4878                          surfaceSyncGroup.markSyncReady();
4879                      }
4880                  });
4881  
4882                  SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
4883  
4884                  sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
4885              } else if (!usingAsyncReport) {
4886                  if (mAttachInfo.mThreadedRenderer != null) {
4887                      mAttachInfo.mThreadedRenderer.fence();
4888                  }
4889              }
4890          }
4891  
4892          if (surfaceSyncGroup != null && !usingAsyncReport) {
4893              surfaceSyncGroup.markSyncReady();
4894          }
4895          if (mPerformContentCapture) {
4896              performContentCaptureInitialReport();
4897          }
4898          return true;
4899      }
4900  
4901      /**
4902       * Checks (and caches) if content capture is enabled for this context.
4903       */
isContentCaptureEnabled()4904      private boolean isContentCaptureEnabled() {
4905          switch (mContentCaptureEnabled) {
4906              case CONTENT_CAPTURE_ENABLED_TRUE:
4907                  return true;
4908              case CONTENT_CAPTURE_ENABLED_FALSE:
4909                  return false;
4910              case CONTENT_CAPTURE_ENABLED_NOT_CHECKED:
4911                  final boolean reallyEnabled = isContentCaptureReallyEnabled();
4912                  mContentCaptureEnabled = reallyEnabled ? CONTENT_CAPTURE_ENABLED_TRUE
4913                          : CONTENT_CAPTURE_ENABLED_FALSE;
4914                  return reallyEnabled;
4915              default:
4916                  Log.w(TAG, "isContentCaptureEnabled(): invalid state " + mContentCaptureEnabled);
4917                  return false;
4918          }
4919  
4920      }
4921  
4922      /**
4923       * Checks (without caching) if content capture is enabled for this context.
4924       */
isContentCaptureReallyEnabled()4925      private boolean isContentCaptureReallyEnabled() {
4926          // First check if context supports it, so it saves a service lookup when it doesn't
4927          if (mContext.getContentCaptureOptions() == null) return false;
4928  
4929          final ContentCaptureManager ccm = mAttachInfo.getContentCaptureManager(mContext);
4930          // Then check if it's enabled in the contex itself.
4931          if (ccm == null || !ccm.isContentCaptureEnabled()) return false;
4932  
4933          return true;
4934      }
4935  
performContentCaptureInitialReport()4936      private void performContentCaptureInitialReport() {
4937          mPerformContentCapture = false; // One-time offer!
4938          final View rootView = mView;
4939          if (DEBUG_CONTENT_CAPTURE) {
4940              Log.v(mTag, "performContentCaptureInitialReport() on " + rootView);
4941          }
4942          if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
4943              Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for "
4944                      + getClass().getSimpleName());
4945          }
4946          try {
4947              if (!isContentCaptureEnabled()) return;
4948  
4949              // Initial dispatch of window bounds to content capture
4950              if (mAttachInfo.mContentCaptureManager != null) {
4951                  MainContentCaptureSession session =
4952                          mAttachInfo.mContentCaptureManager.getMainContentCaptureSession();
4953                  session.notifyWindowBoundsChanged(session.getId(),
4954                          getConfiguration().windowConfiguration.getBounds());
4955              }
4956  
4957              // Content capture is a go!
4958              rootView.dispatchInitialProvideContentCaptureStructure();
4959          } finally {
4960              Trace.traceEnd(Trace.TRACE_TAG_VIEW);
4961          }
4962      }
4963  
handleContentCaptureFlush()4964      private void handleContentCaptureFlush() {
4965          if (DEBUG_CONTENT_CAPTURE) {
4966              Log.v(mTag, "handleContentCaptureFlush()");
4967          }
4968          if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
4969              Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for "
4970                      + getClass().getSimpleName());
4971          }
4972          try {
4973              if (!isContentCaptureEnabled()) return;
4974  
4975              final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager;
4976              if (ccm == null) {
4977                  Log.w(TAG, "No ContentCapture on AttachInfo");
4978                  return;
4979              }
4980              ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED);
4981          } finally {
4982              Trace.traceEnd(Trace.TRACE_TAG_VIEW);
4983          }
4984      }
4985  
draw(boolean fullRedrawNeeded, @Nullable SurfaceSyncGroup activeSyncGroup, boolean syncBuffer)4986      private boolean draw(boolean fullRedrawNeeded,
4987              @Nullable SurfaceSyncGroup activeSyncGroup, boolean syncBuffer) {
4988          Surface surface = mSurface;
4989          if (!surface.isValid()) {
4990              return false;
4991          }
4992  
4993          if (DEBUG_FPS) {
4994              trackFPS();
4995          }
4996  
4997          if (!sFirstDrawComplete) {
4998              synchronized (sFirstDrawHandlers) {
4999                  sFirstDrawComplete = true;
5000                  final int count = sFirstDrawHandlers.size();
5001                  for (int i = 0; i< count; i++) {
5002                      mHandler.post(sFirstDrawHandlers.get(i));
5003                  }
5004              }
5005          }
5006  
5007          scrollToRectOrFocus(null, false);
5008  
5009          if (mAttachInfo.mViewScrollChanged) {
5010              mAttachInfo.mViewScrollChanged = false;
5011              mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
5012          }
5013  
5014          boolean animating = mScroller != null && mScroller.computeScrollOffset();
5015          final int curScrollY;
5016          if (animating) {
5017              curScrollY = mScroller.getCurrY();
5018          } else {
5019              curScrollY = mScrollY;
5020          }
5021          if (mCurScrollY != curScrollY) {
5022              mCurScrollY = curScrollY;
5023              fullRedrawNeeded = true;
5024              if (mView instanceof RootViewSurfaceTaker) {
5025                  ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
5026              }
5027          }
5028  
5029          final float appScale = mAttachInfo.mApplicationScale;
5030          final boolean scalingRequired = mAttachInfo.mScalingRequired;
5031  
5032          final Rect dirty = mDirty;
5033          if (mSurfaceHolder != null) {
5034              // The app owns the surface, we won't draw.
5035              dirty.setEmpty();
5036              if (animating && mScroller != null) {
5037                  mScroller.abortAnimation();
5038              }
5039              return false;
5040          }
5041  
5042          if (fullRedrawNeeded) {
5043              dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
5044          }
5045  
5046          if (DEBUG_ORIENTATION || DEBUG_DRAW) {
5047              Log.v(mTag, "Draw " + mView + "/"
5048                      + mWindowAttributes.getTitle()
5049                      + ": dirty={" + dirty.left + "," + dirty.top
5050                      + "," + dirty.right + "," + dirty.bottom + "} surface="
5051                      + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
5052                      appScale + ", width=" + mWidth + ", height=" + mHeight);
5053          }
5054  
5055          mAttachInfo.mTreeObserver.dispatchOnDraw();
5056  
5057          int xOffset = -mCanvasOffsetX;
5058          int yOffset = -mCanvasOffsetY + curScrollY;
5059          final WindowManager.LayoutParams params = mWindowAttributes;
5060          final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
5061          if (surfaceInsets != null) {
5062              xOffset -= surfaceInsets.left;
5063              yOffset -= surfaceInsets.top;
5064  
5065              // Offset dirty rect for surface insets.
5066              dirty.offset(surfaceInsets.left, surfaceInsets.top);
5067          }
5068  
5069          boolean accessibilityFocusDirty = false;
5070          final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
5071          if (drawable != null) {
5072              final Rect bounds = mAttachInfo.mTmpInvalRect;
5073              final boolean hasFocus = getAccessibilityFocusedRect(bounds);
5074              if (!hasFocus) {
5075                  bounds.setEmpty();
5076              }
5077              if (!bounds.equals(drawable.getBounds())) {
5078                  accessibilityFocusDirty = true;
5079              }
5080          }
5081  
5082          mAttachInfo.mDrawingTime =
5083                  mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
5084  
5085          boolean useAsyncReport = false;
5086          if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
5087              if (isHardwareEnabled()) {
5088                  // If accessibility focus moved, always invalidate the root.
5089                  boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
5090                  mInvalidateRootRequested = false;
5091  
5092                  // Draw with hardware renderer.
5093                  mIsAnimating = false;
5094  
5095                  if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
5096                      mHardwareYOffset = yOffset;
5097                      mHardwareXOffset = xOffset;
5098                      invalidateRoot = true;
5099                  }
5100  
5101                  if (invalidateRoot) {
5102                      mAttachInfo.mThreadedRenderer.invalidateRoot();
5103                  }
5104  
5105                  dirty.setEmpty();
5106  
5107                  // Stage the content drawn size now. It will be transferred to the renderer
5108                  // shortly before the draw commands get send to the renderer.
5109                  final boolean updated = updateContentDrawBounds();
5110  
5111                  if (mReportNextDraw) {
5112                      // report next draw overrides setStopped()
5113                      // This value is re-sync'd to the value of mStopped
5114                      // in the handling of mReportNextDraw post-draw.
5115                      mAttachInfo.mThreadedRenderer.setStopped(false);
5116                  }
5117  
5118                  if (updated) {
5119                      requestDrawWindow();
5120                  }
5121  
5122                  useAsyncReport = true;
5123  
5124                  if (mUpdateHdrSdrRatioInfo) {
5125                      mUpdateHdrSdrRatioInfo = false;
5126                      applyTransactionOnDraw(mTransaction.setExtendedRangeBrightness(
5127                              getSurfaceControl(), mRenderHdrSdrRatio, mDesiredHdrSdrRatio));
5128                      mAttachInfo.mThreadedRenderer.setTargetHdrSdrRatio(mRenderHdrSdrRatio);
5129                  }
5130  
5131                  if (activeSyncGroup != null) {
5132                      registerCallbacksForSync(syncBuffer, activeSyncGroup);
5133                      if (syncBuffer) {
5134                          mAttachInfo.mThreadedRenderer.forceDrawNextFrame();
5135                      }
5136                  } else if (mHasPendingTransactions) {
5137                      // Register a calback if there's no sync involved but there were calls to
5138                      // applyTransactionOnDraw. If there is a sync involved, the sync callback will
5139                      // handle merging the pending transaction.
5140                      registerCallbackForPendingTransactions();
5141                  }
5142                  mHasPendingTransactions = false;
5143  
5144                  mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
5145              } else {
5146                  // If we get here with a disabled & requested hardware renderer, something went
5147                  // wrong (an invalidate posted right before we destroyed the hardware surface
5148                  // for instance) so we should just bail out. Locking the surface with software
5149                  // rendering at this point would lock it forever and prevent hardware renderer
5150                  // from doing its job when it comes back.
5151                  // Before we request a new frame we must however attempt to reinitiliaze the
5152                  // hardware renderer if it's in requested state. This would happen after an
5153                  // eglTerminate() for instance.
5154                  if (mAttachInfo.mThreadedRenderer != null &&
5155                          !mAttachInfo.mThreadedRenderer.isEnabled() &&
5156                          mAttachInfo.mThreadedRenderer.isRequested() &&
5157                          mSurface.isValid()) {
5158  
5159                      try {
5160                          mAttachInfo.mThreadedRenderer.initializeIfNeeded(
5161                                  mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
5162                      } catch (OutOfResourcesException e) {
5163                          handleOutOfResourcesException(e);
5164                          return false;
5165                      }
5166  
5167                      mFullRedrawNeeded = true;
5168                      scheduleTraversals();
5169                      return false;
5170                  }
5171  
5172                  if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
5173                          scalingRequired, dirty, surfaceInsets)) {
5174                      return false;
5175                  }
5176              }
5177          }
5178  
5179          if (animating) {
5180              mFullRedrawNeeded = true;
5181              scheduleTraversals();
5182          }
5183          return useAsyncReport;
5184      }
5185  
5186      /**
5187       * @return true if drawing was successful, false if an error occurred
5188       */
drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets)5189      private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
5190              boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
5191  
5192          // Draw with software renderer.
5193          final Canvas canvas;
5194  
5195          try {
5196              canvas = mSurface.lockCanvas(dirty);
5197              canvas.setDensity(mDensity);
5198          } catch (Surface.OutOfResourcesException e) {
5199              handleOutOfResourcesException(e);
5200              return false;
5201          } catch (IllegalArgumentException e) {
5202              Log.e(mTag, "Could not lock surface", e);
5203              // Don't assume this is due to out of memory, it could be
5204              // something else, and if it is something else then we could
5205              // kill stuff (or ourself) for no reason.
5206              mLayoutRequested = true;    // ask wm for a new surface next time.
5207              return false;
5208          }
5209  
5210          try {
5211              if (DEBUG_ORIENTATION || DEBUG_DRAW) {
5212                  Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
5213                          + canvas.getWidth() + ", h=" + canvas.getHeight() + ", dirty: " + dirty
5214                          + ", xOff=" + xoff + ", yOff=" + yoff);
5215                  //canvas.drawARGB(255, 255, 0, 0);
5216              }
5217  
5218              // If this bitmap's format includes an alpha channel, we
5219              // need to clear it before drawing so that the child will
5220              // properly re-composite its drawing on a transparent
5221              // background. This automatically respects the clip/dirty region
5222              // or
5223              // If we are applying an offset, we need to clear the area
5224              // where the offset doesn't appear to avoid having garbage
5225              // left in the blank areas.
5226              if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
5227                  canvas.drawColor(0, PorterDuff.Mode.CLEAR);
5228              }
5229  
5230              dirty.setEmpty();
5231              mIsAnimating = false;
5232              mView.mPrivateFlags |= View.PFLAG_DRAWN;
5233  
5234              if (DEBUG_DRAW) {
5235                  Context cxt = mView.getContext();
5236                  Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
5237                          ", metrics=" + cxt.getResources().getDisplayMetrics() +
5238                          ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
5239              }
5240              canvas.translate(-xoff, -yoff);
5241              if (mTranslator != null) {
5242                  mTranslator.translateCanvas(canvas);
5243              }
5244              canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
5245  
5246              mView.draw(canvas);
5247  
5248              drawAccessibilityFocusedDrawableIfNeeded(canvas);
5249          } finally {
5250              try {
5251                  surface.unlockCanvasAndPost(canvas);
5252              } catch (IllegalArgumentException e) {
5253                  Log.e(mTag, "Could not unlock surface", e);
5254                  mLayoutRequested = true;    // ask wm for a new surface next time.
5255                  //noinspection ReturnInsideFinallyBlock
5256                  return false;
5257              }
5258  
5259              if (LOCAL_LOGV) {
5260                  Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
5261              }
5262          }
5263          return true;
5264      }
5265  
5266      /**
5267       * We want to draw a highlight around the current accessibility focused.
5268       * Since adding a style for all possible view is not a viable option we
5269       * have this specialized drawing method.
5270       *
5271       * Note: We are doing this here to be able to draw the highlight for
5272       *       virtual views in addition to real ones.
5273       *
5274       * @param canvas The canvas on which to draw.
5275       */
drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas)5276      private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
5277          final Rect bounds = mAttachInfo.mTmpInvalRect;
5278          if (getAccessibilityFocusedRect(bounds)) {
5279              final Drawable drawable = getAccessibilityFocusedDrawable();
5280              if (drawable != null) {
5281                  drawable.setBounds(bounds);
5282                  drawable.draw(canvas);
5283              }
5284          } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
5285              mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
5286          }
5287      }
5288  
getAccessibilityFocusedRect(Rect bounds)5289      private boolean getAccessibilityFocusedRect(Rect bounds) {
5290          final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
5291          if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
5292              return false;
5293          }
5294  
5295          final View host = mAccessibilityFocusedHost;
5296          if (host == null || host.mAttachInfo == null) {
5297              return false;
5298          }
5299  
5300          final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
5301          if (provider == null) {
5302              host.getBoundsOnScreen(bounds, true);
5303          } else if (mAccessibilityFocusedVirtualView != null) {
5304              mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
5305          } else {
5306              return false;
5307          }
5308  
5309          // Transform the rect into window-relative coordinates.
5310          final AttachInfo attachInfo = mAttachInfo;
5311          bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
5312          bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
5313          if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
5314                  attachInfo.mViewRootImpl.mHeight)) {
5315              // If no intersection, set bounds to empty.
5316              bounds.setEmpty();
5317          }
5318          return !bounds.isEmpty();
5319      }
5320  
getAccessibilityFocusedDrawable()5321      private Drawable getAccessibilityFocusedDrawable() {
5322          // Lazily load the accessibility focus drawable.
5323          if (mAttachInfo.mAccessibilityFocusDrawable == null) {
5324              final TypedValue value = new TypedValue();
5325              final boolean resolved = mView.mContext.getTheme().resolveAttribute(
5326                      R.attr.accessibilityFocusedDrawable, value, true);
5327              if (resolved) {
5328                  mAttachInfo.mAccessibilityFocusDrawable =
5329                          mView.mContext.getDrawable(value.resourceId);
5330              }
5331          }
5332          // Sets the focus appearance data into the accessibility focus drawable.
5333          if (mAttachInfo.mAccessibilityFocusDrawable instanceof GradientDrawable) {
5334              final GradientDrawable drawable =
5335                      (GradientDrawable) mAttachInfo.mAccessibilityFocusDrawable;
5336              drawable.setStroke(mAccessibilityManager.getAccessibilityFocusStrokeWidth(),
5337                      mAccessibilityManager.getAccessibilityFocusColor());
5338          }
5339  
5340          return mAttachInfo.mAccessibilityFocusDrawable;
5341      }
5342  
updateSystemGestureExclusionRectsForView(View view)5343      void updateSystemGestureExclusionRectsForView(View view) {
5344          mGestureExclusionTracker.updateRectsForView(view);
5345          mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
5346      }
5347  
systemGestureExclusionChanged()5348      void systemGestureExclusionChanged() {
5349          final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects();
5350          if (rectsForWindowManager != null && mView != null) {
5351              try {
5352                  mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager);
5353              } catch (RemoteException e) {
5354                  throw e.rethrowFromSystemServer();
5355              }
5356              mAttachInfo.mTreeObserver
5357                      .dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager);
5358          }
5359      }
5360  
5361      /**
5362       * Set the root-level system gesture exclusion rects. These are added to those provided by
5363       * the root's view hierarchy.
5364       */
setRootSystemGestureExclusionRects(@onNull List<Rect> rects)5365      public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) {
5366          mGestureExclusionTracker.setRootRects(rects);
5367          mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
5368      }
5369  
5370      /**
5371       * Returns the root-level system gesture exclusion rects. These do not include those provided by
5372       * the root's view hierarchy.
5373       */
5374      @NonNull
getRootSystemGestureExclusionRects()5375      public List<Rect> getRootSystemGestureExclusionRects() {
5376          return mGestureExclusionTracker.getRootRects();
5377      }
5378  
5379      /**
5380       * Called from View when the position listener is triggered
5381       */
updateKeepClearRectsForView(View view)5382      void updateKeepClearRectsForView(View view) {
5383          mKeepClearRectsTracker.updateRectsForView(view);
5384          mUnrestrictedKeepClearRectsTracker.updateRectsForView(view);
5385          mHandler.sendEmptyMessage(MSG_KEEP_CLEAR_RECTS_CHANGED);
5386      }
5387  
updateKeepClearForAccessibilityFocusRect()5388      private void updateKeepClearForAccessibilityFocusRect() {
5389          if (mViewConfiguration.isPreferKeepClearForFocusEnabled()) {
5390              if (mKeepClearAccessibilityFocusRect == null) {
5391                  mKeepClearAccessibilityFocusRect = new Rect();
5392              }
5393              boolean hasAccessibilityFocus =
5394                      getAccessibilityFocusedRect(mKeepClearAccessibilityFocusRect);
5395              if (!hasAccessibilityFocus) {
5396                  mKeepClearAccessibilityFocusRect.setEmpty();
5397              }
5398              mHandler.obtainMessage(MSG_KEEP_CLEAR_RECTS_CHANGED, 1, 0).sendToTarget();
5399          }
5400      }
5401  
keepClearRectsChanged(boolean accessibilityFocusRectChanged)5402      void keepClearRectsChanged(boolean accessibilityFocusRectChanged) {
5403          boolean restrictedKeepClearRectsChanged = mKeepClearRectsTracker.computeChanges();
5404          boolean unrestrictedKeepClearRectsChanged =
5405                  mUnrestrictedKeepClearRectsTracker.computeChanges();
5406  
5407          if ((restrictedKeepClearRectsChanged || unrestrictedKeepClearRectsChanged
5408                  || accessibilityFocusRectChanged) && mView != null) {
5409              mHasPendingKeepClearAreaChange = true;
5410              // Only report keep clear areas immediately if they have not been reported recently
5411              if (!mHandler.hasMessages(MSG_REPORT_KEEP_CLEAR_RECTS)) {
5412                  mHandler.sendEmptyMessageDelayed(MSG_REPORT_KEEP_CLEAR_RECTS,
5413                          KEEP_CLEAR_AREA_REPORT_RATE_MILLIS);
5414                  reportKeepClearAreasChanged();
5415              }
5416          }
5417      }
5418  
reportKeepClearAreasChanged()5419      void reportKeepClearAreasChanged() {
5420          if (!mHasPendingKeepClearAreaChange || mView == null) {
5421              return;
5422          }
5423          mHasPendingKeepClearAreaChange = false;
5424  
5425          List<Rect> restrictedKeepClearRects = mKeepClearRectsTracker.getLastComputedRects();
5426          final List<Rect> unrestrictedKeepClearRects =
5427                  mUnrestrictedKeepClearRectsTracker.getLastComputedRects();
5428  
5429          if (mKeepClearAccessibilityFocusRect != null
5430                  && !mKeepClearAccessibilityFocusRect.isEmpty()) {
5431              restrictedKeepClearRects = new ArrayList<>(restrictedKeepClearRects);
5432              restrictedKeepClearRects.add(mKeepClearAccessibilityFocusRect);
5433          }
5434  
5435          try {
5436              mWindowSession.reportKeepClearAreasChanged(mWindow, restrictedKeepClearRects,
5437                      unrestrictedKeepClearRects);
5438          } catch (RemoteException e) {
5439              throw e.rethrowFromSystemServer();
5440          }
5441      }
5442  
5443      /**
5444       * Requests that the root render node is invalidated next time we perform a draw, such that
5445       * {@link WindowCallbacks#onPostDraw} gets called.
5446       */
requestInvalidateRootRenderNode()5447      public void requestInvalidateRootRenderNode() {
5448          mInvalidateRootRequested = true;
5449      }
5450  
scrollToRectOrFocus(Rect rectangle, boolean immediate)5451      boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
5452          final Rect ci = mAttachInfo.mContentInsets;
5453          final Rect vi = mAttachInfo.mVisibleInsets;
5454          int scrollY = 0;
5455          boolean handled = false;
5456  
5457          if (vi.left > ci.left || vi.top > ci.top
5458                  || vi.right > ci.right || vi.bottom > ci.bottom) {
5459              // We'll assume that we aren't going to change the scroll
5460              // offset, since we want to avoid that unless it is actually
5461              // going to make the focus visible...  otherwise we scroll
5462              // all over the place.
5463              scrollY = mScrollY;
5464              // We can be called for two different situations: during a draw,
5465              // to update the scroll position if the focus has changed (in which
5466              // case 'rectangle' is null), or in response to a
5467              // requestChildRectangleOnScreen() call (in which case 'rectangle'
5468              // is non-null and we just want to scroll to whatever that
5469              // rectangle is).
5470              final View focus = mView.findFocus();
5471              if (focus == null) {
5472                  return false;
5473              }
5474              View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
5475              if (focus != lastScrolledFocus) {
5476                  // If the focus has changed, then ignore any requests to scroll
5477                  // to a rectangle; first we want to make sure the entire focus
5478                  // view is visible.
5479                  rectangle = null;
5480              }
5481              if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
5482                      + " rectangle=" + rectangle + " ci=" + ci
5483                      + " vi=" + vi);
5484              if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
5485                  // Optimization: if the focus hasn't changed since last
5486                  // time, and no layout has happened, then just leave things
5487                  // as they are.
5488                  if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
5489                          + mScrollY + " vi=" + vi.toShortString());
5490              } else {
5491                  // We need to determine if the currently focused view is
5492                  // within the visible part of the window and, if not, apply
5493                  // a pan so it can be seen.
5494                  mLastScrolledFocus = new WeakReference<View>(focus);
5495                  mScrollMayChange = false;
5496                  if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
5497                  // Try to find the rectangle from the focus view.
5498                  if (focus.getGlobalVisibleRect(mVisRect, null)) {
5499                      if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
5500                              + mView.getWidth() + " h=" + mView.getHeight()
5501                              + " ci=" + ci.toShortString()
5502                              + " vi=" + vi.toShortString());
5503                      if (rectangle == null) {
5504                          focus.getFocusedRect(mTempRect);
5505                          if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
5506                                  + ": focusRect=" + mTempRect.toShortString());
5507                          if (mView instanceof ViewGroup) {
5508                              ((ViewGroup) mView).offsetDescendantRectToMyCoords(
5509                                      focus, mTempRect);
5510                          }
5511                          if (DEBUG_INPUT_RESIZE) Log.v(mTag,
5512                                  "Focus in window: focusRect="
5513                                  + mTempRect.toShortString()
5514                                  + " visRect=" + mVisRect.toShortString());
5515                      } else {
5516                          mTempRect.set(rectangle);
5517                          if (DEBUG_INPUT_RESIZE) Log.v(mTag,
5518                                  "Request scroll to rect: "
5519                                  + mTempRect.toShortString()
5520                                  + " visRect=" + mVisRect.toShortString());
5521                      }
5522                      if (mTempRect.intersect(mVisRect)) {
5523                          if (DEBUG_INPUT_RESIZE) Log.v(mTag,
5524                                  "Focus window visible rect: "
5525                                  + mTempRect.toShortString());
5526                          if (mTempRect.height() >
5527                                  (mView.getHeight()-vi.top-vi.bottom)) {
5528                              // If the focus simply is not going to fit, then
5529                              // best is probably just to leave things as-is.
5530                              if (DEBUG_INPUT_RESIZE) Log.v(mTag,
5531                                      "Too tall; leaving scrollY=" + scrollY);
5532                          }
5533                          // Next, check whether top or bottom is covered based on the non-scrolled
5534                          // position, and calculate new scrollY (or set it to 0).
5535                          // We can't keep using mScrollY here. For example mScrollY is non-zero
5536                          // due to IME, then IME goes away. The current value of mScrollY leaves top
5537                          // and bottom both visible, but we still need to scroll it back to 0.
5538                          else if (mTempRect.top < vi.top) {
5539                              scrollY = mTempRect.top - vi.top;
5540                              if (DEBUG_INPUT_RESIZE) Log.v(mTag,
5541                                      "Top covered; scrollY=" + scrollY);
5542                          } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) {
5543                              scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom);
5544                              if (DEBUG_INPUT_RESIZE) Log.v(mTag,
5545                                      "Bottom covered; scrollY=" + scrollY);
5546                          } else {
5547                              scrollY = 0;
5548                          }
5549                          handled = true;
5550                      }
5551                  }
5552              }
5553          }
5554  
5555          if (scrollY != mScrollY) {
5556              if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
5557                      + mScrollY + " , new=" + scrollY);
5558              if (!immediate) {
5559                  if (mScroller == null) {
5560                      mScroller = new Scroller(mView.getContext());
5561                  }
5562                  mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
5563              } else if (mScroller != null) {
5564                  mScroller.abortAnimation();
5565              }
5566              mScrollY = scrollY;
5567          }
5568  
5569          return handled;
5570      }
5571  
5572      /**
5573       * @hide
5574       */
5575      @UnsupportedAppUsage
getAccessibilityFocusedHost()5576      public View getAccessibilityFocusedHost() {
5577          return mAccessibilityFocusedHost;
5578      }
5579  
5580      /**
5581       * Get accessibility-focused virtual view. The bounds and sourceNodeId of the returned node is
5582       * up-to-date while other fields may be stale.
5583       *
5584       * @hide
5585       */
5586      @UnsupportedAppUsage
getAccessibilityFocusedVirtualView()5587      public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
5588          return mAccessibilityFocusedVirtualView;
5589      }
5590  
setAccessibilityFocus(View view, AccessibilityNodeInfo node)5591      void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
5592          // If we have a virtual view with accessibility focus we need
5593          // to clear the focus and invalidate the virtual view bounds.
5594          if (mAccessibilityFocusedVirtualView != null) {
5595  
5596              AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
5597              View focusHost = mAccessibilityFocusedHost;
5598  
5599              // Wipe the state of the current accessibility focus since
5600              // the call into the provider to clear accessibility focus
5601              // will fire an accessibility event which will end up calling
5602              // this method and we want to have clean state when this
5603              // invocation happens.
5604              mAccessibilityFocusedHost = null;
5605              mAccessibilityFocusedVirtualView = null;
5606  
5607              // Clear accessibility focus on the host after clearing state since
5608              // this method may be reentrant.
5609              focusHost.clearAccessibilityFocusNoCallbacks(
5610                      AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
5611  
5612              AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
5613              if (provider != null) {
5614                  // Invalidate the area of the cleared accessibility focus.
5615                  focusNode.getBoundsInParent(mTempRect);
5616                  focusHost.invalidate(mTempRect);
5617                  // Clear accessibility focus in the virtual node.
5618                  final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
5619                          focusNode.getSourceNodeId());
5620                  provider.performAction(virtualNodeId,
5621                          AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
5622              }
5623              focusNode.recycle();
5624          }
5625          if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view))  {
5626              // Clear accessibility focus in the view.
5627              mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(
5628                      AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
5629          }
5630  
5631          // Set the new focus host and node.
5632          mAccessibilityFocusedHost = view;
5633          mAccessibilityFocusedVirtualView = node;
5634          updateKeepClearForAccessibilityFocusRect();
5635  
5636          if (mAttachInfo.mThreadedRenderer != null) {
5637              mAttachInfo.mThreadedRenderer.invalidateRoot();
5638          }
5639      }
5640  
hasPointerCapture()5641      boolean hasPointerCapture() {
5642          return mPointerCapture;
5643      }
5644  
requestPointerCapture(boolean enabled)5645      void requestPointerCapture(boolean enabled) {
5646          final IBinder inputToken = getInputToken();
5647          if (inputToken == null) {
5648              Log.e(mTag, "No input channel to request Pointer Capture.");
5649              return;
5650          }
5651          InputManagerGlobal
5652                  .getInstance()
5653                  .requestPointerCapture(inputToken, enabled);
5654      }
5655  
handlePointerCaptureChanged(boolean hasCapture)5656      private void handlePointerCaptureChanged(boolean hasCapture) {
5657          if (mPointerCapture == hasCapture) {
5658              return;
5659          }
5660          mPointerCapture = hasCapture;
5661          if (mView != null) {
5662              mView.dispatchPointerCaptureChanged(hasCapture);
5663          }
5664      }
5665  
updateRenderHdrSdrRatio()5666      private void updateRenderHdrSdrRatio() {
5667          mRenderHdrSdrRatio = Math.min(mDesiredHdrSdrRatio, mDisplay.getHdrSdrRatio());
5668          mUpdateHdrSdrRatioInfo = true;
5669      }
5670  
updateColorModeIfNeeded(@ctivityInfo.ColorMode int colorMode)5671      private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode) {
5672          if (mAttachInfo.mThreadedRenderer == null) {
5673              return;
5674          }
5675          if ((colorMode == ActivityInfo.COLOR_MODE_HDR || colorMode == ActivityInfo.COLOR_MODE_HDR10)
5676                  && !mDisplay.isHdrSdrRatioAvailable()) {
5677              colorMode = ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
5678          }
5679          // TODO: Centralize this sanitization? Why do we let setting bad modes?
5680          // Alternatively, can we just let HWUI figure it out? Do we need to care here?
5681          if (colorMode != ActivityInfo.COLOR_MODE_A8
5682                  && !getConfiguration().isScreenWideColorGamut()) {
5683              colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
5684          }
5685          float desiredRatio = mAttachInfo.mThreadedRenderer.setColorMode(colorMode);
5686          if (desiredRatio != mDesiredHdrSdrRatio) {
5687              mDesiredHdrSdrRatio = desiredRatio;
5688              updateRenderHdrSdrRatio();
5689              invalidate();
5690  
5691              if (mDesiredHdrSdrRatio < 1.01f) {
5692                  mDisplay.unregisterHdrSdrRatioChangedListener(mHdrSdrRatioChangedListener);
5693                  mHdrSdrRatioChangedListener = null;
5694              } else {
5695                  mHdrSdrRatioChangedListener = display -> {
5696                      updateRenderHdrSdrRatio();
5697                      invalidate();
5698                  };
5699                  mDisplay.registerHdrSdrRatioChangedListener(mExecutor, mHdrSdrRatioChangedListener);
5700              }
5701          }
5702      }
5703  
5704      @Override
requestChildFocus(View child, View focused)5705      public void requestChildFocus(View child, View focused) {
5706          if (DEBUG_INPUT_RESIZE) {
5707              Log.v(mTag, "Request child focus: focus now " + focused);
5708          }
5709          checkThread();
5710          scheduleTraversals();
5711      }
5712  
5713      @Override
clearChildFocus(View child)5714      public void clearChildFocus(View child) {
5715          if (DEBUG_INPUT_RESIZE) {
5716              Log.v(mTag, "Clearing child focus");
5717          }
5718          checkThread();
5719          scheduleTraversals();
5720      }
5721  
5722      @Override
getParentForAccessibility()5723      public ViewParent getParentForAccessibility() {
5724          return null;
5725      }
5726  
5727      @Override
focusableViewAvailable(View v)5728      public void focusableViewAvailable(View v) {
5729          checkThread();
5730          if (mView != null) {
5731              if (!mView.hasFocus()) {
5732                  if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) {
5733                      v.requestFocus();
5734                  }
5735              } else {
5736                  // the one case where will transfer focus away from the current one
5737                  // is if the current view is a view group that prefers to give focus
5738                  // to its children first AND the view is a descendant of it.
5739                  View focused = mView.findFocus();
5740                  if (focused instanceof ViewGroup) {
5741                      ViewGroup group = (ViewGroup) focused;
5742                      if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
5743                              && isViewDescendantOf(v, focused)) {
5744                          v.requestFocus();
5745                      }
5746                  }
5747              }
5748          }
5749      }
5750  
5751      @Override
recomputeViewAttributes(View child)5752      public void recomputeViewAttributes(View child) {
5753          checkThread();
5754          if (mView == child) {
5755              mAttachInfo.mRecomputeGlobalAttributes = true;
5756              if (!mWillDrawSoon) {
5757                  scheduleTraversals();
5758              }
5759          }
5760      }
5761  
dispatchDetachedFromWindow()5762      void dispatchDetachedFromWindow() {
5763          // Make sure we free-up insets resources if view never received onWindowFocusLost()
5764          // because of a die-signal
5765          mInsetsController.onWindowFocusLost();
5766          mFirstInputStage.onDetachedFromWindow();
5767          if (mView != null && mView.mAttachInfo != null) {
5768              mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
5769              mView.dispatchDetachedFromWindow();
5770          }
5771  
5772          mAccessibilityInteractionConnectionManager.ensureNoConnection();
5773          mAccessibilityInteractionConnectionManager.ensureNoDirectConnection();
5774          removeSendWindowContentChangedCallback();
5775  
5776          destroyHardwareRenderer();
5777  
5778          setAccessibilityFocus(null, null);
5779  
5780          mInsetsController.cancelExistingAnimations();
5781  
5782          mView.assignParent(null);
5783          mView = null;
5784          mAttachInfo.mRootView = null;
5785  
5786          destroySurface();
5787  
5788          if (mInputQueueCallback != null && mInputQueue != null) {
5789              mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
5790              mInputQueue.dispose();
5791              mInputQueueCallback = null;
5792              mInputQueue = null;
5793          }
5794          try {
5795              mWindowSession.remove(mWindow);
5796          } catch (RemoteException e) {
5797          }
5798          // Dispose receiver would dispose client InputChannel, too. That could send out a socket
5799          // broken event, so we need to unregister the server InputChannel when removing window to
5800          // prevent server side receive the event and prompt error.
5801          if (mInputEventReceiver != null) {
5802              mInputEventReceiver.dispose();
5803              mInputEventReceiver = null;
5804          }
5805  
5806          unregisterListeners();
5807          unscheduleTraversals();
5808      }
5809  
5810      /**
5811       * Notifies all callbacks that configuration and/or display has changed and updates internal
5812       * state.
5813       * @param mergedConfiguration New global and override config in {@link MergedConfiguration}
5814       *                            container.
5815       * @param force Flag indicating if we should force apply the config.
5816       * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not
5817       *                     changed.
5818       */
performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force, int newDisplayId)5819      private void performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force,
5820              int newDisplayId) {
5821          if (mergedConfiguration == null) {
5822              throw new IllegalArgumentException("No merged config provided.");
5823          }
5824  
5825          final int lastRotation = mLastReportedMergedConfiguration.getMergedConfiguration()
5826                  .windowConfiguration.getRotation();
5827          final int newRotation = mergedConfiguration.getMergedConfiguration()
5828                  .windowConfiguration.getRotation();
5829          if (lastRotation != newRotation) {
5830              // Trigger ThreadedRenderer#updateSurface() if the surface control doesn't change.
5831              // Because even if the actual surface size is not changed, e.g. flip 180 degrees,
5832              // the buffers may still have content in previous rotation. And the next draw may
5833              // not update all regions, that causes some afterimages to flicker.
5834              mUpdateSurfaceNeeded = true;
5835              if (!mIsInTraversal) {
5836                  mForceNextWindowRelayout = true;
5837              }
5838          }
5839  
5840          Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
5841          final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration();
5842          if (DEBUG_CONFIGURATION) Log.v(mTag,
5843                  "Applying new config to window " + mWindowAttributes.getTitle()
5844                          + ", globalConfig: " + globalConfig
5845                          + ", overrideConfig: " + overrideConfig);
5846  
5847          final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
5848          if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
5849              globalConfig = new Configuration(globalConfig);
5850              ci.applyToConfiguration(mNoncompatDensity, globalConfig);
5851          }
5852  
5853          synchronized (sConfigCallbacks) {
5854              for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
5855                  sConfigCallbacks.get(i).onConfigurationChanged(globalConfig);
5856              }
5857          }
5858  
5859          mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
5860  
5861          mForceNextConfigUpdate = force;
5862          if (mActivityConfigCallback != null) {
5863              // An activity callback is set - notify it about override configuration update.
5864              // This basically initiates a round trip to ActivityThread and back, which will ensure
5865              // that corresponding activity and resources are updated before updating inner state of
5866              // ViewRootImpl. Eventually it will call #updateConfiguration().
5867              mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId);
5868          } else {
5869              // There is no activity callback - update the configuration right away.
5870              updateConfiguration(newDisplayId);
5871          }
5872          mForceNextConfigUpdate = false;
5873      }
5874  
5875      /**
5876       * Update display and views if last applied merged configuration changed.
5877       * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise.
5878       */
updateConfiguration(int newDisplayId)5879      public void updateConfiguration(int newDisplayId) {
5880          if (mView == null) {
5881              return;
5882          }
5883  
5884          // At this point the resources have been updated to
5885          // have the most recent config, whatever that is.  Use
5886          // the one in them which may be newer.
5887          final Resources localResources = mView.getResources();
5888          final Configuration config = localResources.getConfiguration();
5889  
5890          // Handle move to display.
5891          if (newDisplayId != INVALID_DISPLAY) {
5892              onMovedToDisplay(newDisplayId, config);
5893          }
5894  
5895          // Handle configuration change.
5896          if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
5897              // Update the display with new DisplayAdjustments.
5898              updateInternalDisplay(mDisplay.getDisplayId(), localResources);
5899  
5900              updateLastConfigurationFromResources(config);
5901              mView.dispatchConfigurationChanged(config);
5902  
5903              // We could have gotten this {@link Configuration} update after we called
5904              // {@link #performTraversals} with an older {@link Configuration}. As a result, our
5905              // window frame may be stale. We must ensure the next pass of {@link #performTraversals}
5906              // catches this.
5907              mForceNextWindowRelayout = true;
5908              requestLayout();
5909          }
5910  
5911          updateForceDarkMode();
5912      }
5913  
updateLastConfigurationFromResources(Configuration resConfig)5914      private void updateLastConfigurationFromResources(Configuration resConfig) {
5915          final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
5916          final int currentLayoutDirection = resConfig.getLayoutDirection();
5917          mLastConfigurationFromResources.setTo(resConfig);
5918          // Update layout direction in case the language or screen layout is changed.
5919          if (lastLayoutDirection != currentLayoutDirection && mView != null
5920                  && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
5921              mView.setLayoutDirection(currentLayoutDirection);
5922          }
5923      }
5924  
5925      /**
5926       * Return true if child is an ancestor of parent, (or equal to the parent).
5927       */
isViewDescendantOf(View child, View parent)5928      public static boolean isViewDescendantOf(View child, View parent) {
5929          if (child == parent) {
5930              return true;
5931          }
5932  
5933          final ViewParent theParent = child.getParent();
5934          return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
5935      }
5936  
forceLayout(View view)5937      private static void forceLayout(View view) {
5938          view.forceLayout();
5939          if (view instanceof ViewGroup) {
5940              ViewGroup group = (ViewGroup) view;
5941              final int count = group.getChildCount();
5942              for (int i = 0; i < count; i++) {
5943                  forceLayout(group.getChildAt(i));
5944              }
5945          }
5946      }
5947  
5948      private static final int MSG_INVALIDATE = 1;
5949      private static final int MSG_INVALIDATE_RECT = 2;
5950      private static final int MSG_DIE = 3;
5951      private static final int MSG_RESIZED = 4;
5952      private static final int MSG_RESIZED_REPORT = 5;
5953      private static final int MSG_WINDOW_FOCUS_CHANGED = 6;
5954      private static final int MSG_DISPATCH_INPUT_EVENT = 7;
5955      private static final int MSG_DISPATCH_APP_VISIBILITY = 8;
5956      private static final int MSG_DISPATCH_GET_NEW_SURFACE = 9;
5957      private static final int MSG_DISPATCH_KEY_FROM_IME = 11;
5958      private static final int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12;
5959      private static final int MSG_CHECK_FOCUS = 13;
5960      private static final int MSG_CLOSE_SYSTEM_DIALOGS = 14;
5961      private static final int MSG_DISPATCH_DRAG_EVENT = 15;
5962      private static final int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
5963      private static final int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
5964      private static final int MSG_UPDATE_CONFIGURATION = 18;
5965      private static final int MSG_PROCESS_INPUT_EVENTS = 19;
5966      private static final int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
5967      private static final int MSG_INVALIDATE_WORLD = 22;
5968      private static final int MSG_WINDOW_MOVED = 23;
5969      private static final int MSG_SYNTHESIZE_INPUT_EVENT = 24;
5970      private static final int MSG_DISPATCH_WINDOW_SHOWN = 25;
5971      private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
5972      private static final int MSG_UPDATE_POINTER_ICON = 27;
5973      private static final int MSG_POINTER_CAPTURE_CHANGED = 28;
5974      private static final int MSG_INSETS_CONTROL_CHANGED = 29;
5975      private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 30;
5976      private static final int MSG_SHOW_INSETS = 31;
5977      private static final int MSG_HIDE_INSETS = 32;
5978      private static final int MSG_REQUEST_SCROLL_CAPTURE = 33;
5979      private static final int MSG_WINDOW_TOUCH_MODE_CHANGED = 34;
5980      private static final int MSG_KEEP_CLEAR_RECTS_CHANGED = 35;
5981      private static final int MSG_REPORT_KEEP_CLEAR_RECTS = 36;
5982      private static final int MSG_PAUSED_FOR_SYNC_TIMEOUT = 37;
5983  
5984      final class ViewRootHandler extends Handler {
5985          @Override
getMessageName(Message message)5986          public String getMessageName(Message message) {
5987              switch (message.what) {
5988                  case MSG_INVALIDATE:
5989                      return "MSG_INVALIDATE";
5990                  case MSG_INVALIDATE_RECT:
5991                      return "MSG_INVALIDATE_RECT";
5992                  case MSG_DIE:
5993                      return "MSG_DIE";
5994                  case MSG_RESIZED:
5995                      return "MSG_RESIZED";
5996                  case MSG_RESIZED_REPORT:
5997                      return "MSG_RESIZED_REPORT";
5998                  case MSG_WINDOW_FOCUS_CHANGED:
5999                      return "MSG_WINDOW_FOCUS_CHANGED";
6000                  case MSG_DISPATCH_INPUT_EVENT:
6001                      return "MSG_DISPATCH_INPUT_EVENT";
6002                  case MSG_DISPATCH_APP_VISIBILITY:
6003                      return "MSG_DISPATCH_APP_VISIBILITY";
6004                  case MSG_DISPATCH_GET_NEW_SURFACE:
6005                      return "MSG_DISPATCH_GET_NEW_SURFACE";
6006                  case MSG_DISPATCH_KEY_FROM_IME:
6007                      return "MSG_DISPATCH_KEY_FROM_IME";
6008                  case MSG_DISPATCH_KEY_FROM_AUTOFILL:
6009                      return "MSG_DISPATCH_KEY_FROM_AUTOFILL";
6010                  case MSG_CHECK_FOCUS:
6011                      return "MSG_CHECK_FOCUS";
6012                  case MSG_CLOSE_SYSTEM_DIALOGS:
6013                      return "MSG_CLOSE_SYSTEM_DIALOGS";
6014                  case MSG_DISPATCH_DRAG_EVENT:
6015                      return "MSG_DISPATCH_DRAG_EVENT";
6016                  case MSG_DISPATCH_DRAG_LOCATION_EVENT:
6017                      return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
6018                  case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
6019                      return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
6020                  case MSG_UPDATE_CONFIGURATION:
6021                      return "MSG_UPDATE_CONFIGURATION";
6022                  case MSG_PROCESS_INPUT_EVENTS:
6023                      return "MSG_PROCESS_INPUT_EVENTS";
6024                  case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
6025                      return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
6026                  case MSG_WINDOW_MOVED:
6027                      return "MSG_WINDOW_MOVED";
6028                  case MSG_SYNTHESIZE_INPUT_EVENT:
6029                      return "MSG_SYNTHESIZE_INPUT_EVENT";
6030                  case MSG_DISPATCH_WINDOW_SHOWN:
6031                      return "MSG_DISPATCH_WINDOW_SHOWN";
6032                  case MSG_UPDATE_POINTER_ICON:
6033                      return "MSG_UPDATE_POINTER_ICON";
6034                  case MSG_POINTER_CAPTURE_CHANGED:
6035                      return "MSG_POINTER_CAPTURE_CHANGED";
6036                  case MSG_INSETS_CONTROL_CHANGED:
6037                      return "MSG_INSETS_CONTROL_CHANGED";
6038                  case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED:
6039                      return "MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED";
6040                  case MSG_SHOW_INSETS:
6041                      return "MSG_SHOW_INSETS";
6042                  case MSG_HIDE_INSETS:
6043                      return "MSG_HIDE_INSETS";
6044                  case MSG_WINDOW_TOUCH_MODE_CHANGED:
6045                      return "MSG_WINDOW_TOUCH_MODE_CHANGED";
6046                  case MSG_KEEP_CLEAR_RECTS_CHANGED:
6047                      return "MSG_KEEP_CLEAR_RECTS_CHANGED";
6048              }
6049              return super.getMessageName(message);
6050          }
6051  
6052          @Override
sendMessageAtTime(Message msg, long uptimeMillis)6053          public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
6054              if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
6055                  // Debugging for b/27963013
6056                  throw new NullPointerException(
6057                          "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
6058              }
6059              return super.sendMessageAtTime(msg, uptimeMillis);
6060          }
6061  
6062          @Override
handleMessage(Message msg)6063          public void handleMessage(Message msg) {
6064              if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
6065                  Trace.traceBegin(Trace.TRACE_TAG_VIEW, getMessageName(msg));
6066              }
6067              try {
6068                  handleMessageImpl(msg);
6069              } finally {
6070                  Trace.traceEnd(Trace.TRACE_TAG_VIEW);
6071              }
6072          }
6073  
handleMessageImpl(Message msg)6074          private void handleMessageImpl(Message msg) {
6075              switch (msg.what) {
6076                  case MSG_INVALIDATE:
6077                      ((View) msg.obj).invalidate();
6078                      break;
6079                  case MSG_INVALIDATE_RECT:
6080                      final View.AttachInfo.InvalidateInfo info =
6081                              (View.AttachInfo.InvalidateInfo) msg.obj;
6082                      info.target.invalidate(info.left, info.top, info.right, info.bottom);
6083                      info.recycle();
6084                      break;
6085                  case MSG_PROCESS_INPUT_EVENTS:
6086                      mProcessInputEventsScheduled = false;
6087                      doProcessInputEvents();
6088                      break;
6089                  case MSG_DISPATCH_APP_VISIBILITY:
6090                      handleAppVisibility(msg.arg1 != 0);
6091                      break;
6092                  case MSG_DISPATCH_GET_NEW_SURFACE:
6093                      handleGetNewSurface();
6094                      break;
6095                  case MSG_RESIZED:
6096                  case MSG_RESIZED_REPORT: {
6097                      final SomeArgs args = (SomeArgs) msg.obj;
6098                      mInsetsController.onStateChanged((InsetsState) args.arg3);
6099                      handleResized(msg.what, args);
6100                      args.recycle();
6101                      break;
6102                  }
6103                  case MSG_INSETS_CONTROL_CHANGED: {
6104                      SomeArgs args = (SomeArgs) msg.obj;
6105  
6106                      // Deliver state change before control change, such that:
6107                      // a) When gaining control, controller can compare with server state to evaluate
6108                      // whether it needs to run animation.
6109                      // b) When loosing control, controller can restore server state by taking last
6110                      // dispatched state as truth.
6111                      mInsetsController.onStateChanged((InsetsState) args.arg1);
6112                      InsetsSourceControl[] controls = (InsetsSourceControl[]) args.arg2;
6113                      if (mAdded) {
6114                          mInsetsController.onControlsChanged(controls);
6115                      } else if (controls != null) {
6116                          for (InsetsSourceControl control : controls) {
6117                              if (control != null) {
6118                                  control.release(SurfaceControl::release);
6119                              }
6120                          }
6121                      }
6122                      args.recycle();
6123                      break;
6124                  }
6125                  case MSG_SHOW_INSETS: {
6126                      final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj;
6127                      ImeTracker.forLogging().onProgress(statsToken,
6128                              ImeTracker.PHASE_CLIENT_HANDLE_SHOW_INSETS);
6129                      if (mView == null) {
6130                          Log.e(TAG,
6131                                  String.format("Calling showInsets(%d,%b) on window that no longer"
6132                                          + " has views.", msg.arg1, msg.arg2 == 1));
6133                      }
6134                      clearLowProfileModeIfNeeded(msg.arg1, msg.arg2 == 1);
6135                      mInsetsController.show(msg.arg1, msg.arg2 == 1, statsToken);
6136                      break;
6137                  }
6138                  case MSG_HIDE_INSETS: {
6139                      final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj;
6140                      ImeTracker.forLogging().onProgress(statsToken,
6141                              ImeTracker.PHASE_CLIENT_HANDLE_HIDE_INSETS);
6142                      mInsetsController.hide(msg.arg1, msg.arg2 == 1, statsToken);
6143                      break;
6144                  }
6145                  case MSG_WINDOW_MOVED:
6146                      if (mAdded) {
6147                          final int w = mWinFrame.width();
6148                          final int h = mWinFrame.height();
6149                          final int l = msg.arg1;
6150                          final int t = msg.arg2;
6151                          mTmpFrames.frame.left = l;
6152                          mTmpFrames.frame.right = l + w;
6153                          mTmpFrames.frame.top = t;
6154                          mTmpFrames.frame.bottom = t + h;
6155                          setFrame(mTmpFrames.frame, false /* withinRelayout */);
6156                          maybeHandleWindowMove(mWinFrame);
6157                      }
6158                      break;
6159                  case MSG_WINDOW_FOCUS_CHANGED: {
6160                      handleWindowFocusChanged();
6161                  } break;
6162                  case MSG_WINDOW_TOUCH_MODE_CHANGED: {
6163                      handleWindowTouchModeChanged();
6164                  } break;
6165                  case MSG_DIE: {
6166                      doDie();
6167                  } break;
6168                  case MSG_DISPATCH_INPUT_EVENT: {
6169                      SomeArgs args = (SomeArgs) msg.obj;
6170                      InputEvent event = (InputEvent) args.arg1;
6171                      InputEventReceiver receiver = (InputEventReceiver) args.arg2;
6172                      enqueueInputEvent(event, receiver, 0, true);
6173                      args.recycle();
6174                  } break;
6175                  case MSG_SYNTHESIZE_INPUT_EVENT: {
6176                      InputEvent event = (InputEvent) msg.obj;
6177                      enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
6178                  } break;
6179                  case MSG_DISPATCH_KEY_FROM_IME: {
6180                      if (LOCAL_LOGV) {
6181                          Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView);
6182                      }
6183                      KeyEvent event = (KeyEvent) msg.obj;
6184                      if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) {
6185                          // The IME is trying to say this event is from the
6186                          // system!  Bad bad bad!
6187                          //noinspection UnusedAssignment
6188                          event = KeyEvent.changeFlags(event,
6189                                  event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
6190                      }
6191                      enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
6192                  } break;
6193                  case MSG_DISPATCH_KEY_FROM_AUTOFILL: {
6194                      if (LOCAL_LOGV) {
6195                          Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView);
6196                      }
6197                      KeyEvent event = (KeyEvent) msg.obj;
6198                      enqueueInputEvent(event, null, 0, true);
6199                  } break;
6200                  case MSG_CHECK_FOCUS: {
6201                      getImeFocusController().onScheduledCheckFocus();
6202                  } break;
6203                  case MSG_CLOSE_SYSTEM_DIALOGS: {
6204                      if (mView != null) {
6205                          mView.onCloseSystemDialogs((String) msg.obj);
6206                      }
6207                  } break;
6208                  case MSG_DISPATCH_DRAG_EVENT: {
6209                  } // fall through
6210                  case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
6211                      DragEvent event = (DragEvent) msg.obj;
6212                      // only present when this app called startDrag()
6213                      event.mLocalState = mLocalDragState;
6214                      handleDragEvent(event);
6215                  } break;
6216                  case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
6217                      handleDispatchSystemUiVisibilityChanged();
6218                  } break;
6219                  case MSG_UPDATE_CONFIGURATION: {
6220                      Configuration config = (Configuration) msg.obj;
6221                      if (config.isOtherSeqNewer(
6222                              mLastReportedMergedConfiguration.getMergedConfiguration())) {
6223                          // If we already have a newer merged config applied - use its global part.
6224                          config = mLastReportedMergedConfiguration.getGlobalConfiguration();
6225                      }
6226  
6227                      // Use the newer global config and last reported override config.
6228                      mPendingMergedConfiguration.setConfiguration(config,
6229                              mLastReportedMergedConfiguration.getOverrideConfiguration());
6230  
6231                      performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration),
6232                              false /* force */, INVALID_DISPLAY /* same display */);
6233                  } break;
6234                  case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
6235                      setAccessibilityFocus(null, null);
6236                  } break;
6237                  case MSG_INVALIDATE_WORLD: {
6238                      if (mView != null) {
6239                          invalidateWorld(mView);
6240                      }
6241                  } break;
6242                  case MSG_DISPATCH_WINDOW_SHOWN: {
6243                      handleDispatchWindowShown();
6244                  } break;
6245                  case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
6246                      final IResultReceiver receiver = (IResultReceiver) msg.obj;
6247                      final int deviceId = msg.arg1;
6248                      handleRequestKeyboardShortcuts(receiver, deviceId);
6249                  } break;
6250                  case MSG_UPDATE_POINTER_ICON: {
6251                      MotionEvent event = (MotionEvent) msg.obj;
6252                      resetPointerIcon(event);
6253                  } break;
6254                  case MSG_POINTER_CAPTURE_CHANGED: {
6255                      final boolean hasCapture = msg.arg1 != 0;
6256                      handlePointerCaptureChanged(hasCapture);
6257                  } break;
6258                  case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: {
6259                      systemGestureExclusionChanged();
6260                  }   break;
6261                  case MSG_KEEP_CLEAR_RECTS_CHANGED: {
6262                      keepClearRectsChanged(/* accessibilityFocusRectChanged= */ msg.arg1 == 1);
6263                  }   break;
6264                  case MSG_REPORT_KEEP_CLEAR_RECTS: {
6265                      reportKeepClearAreasChanged();
6266                  }   break;
6267                  case MSG_REQUEST_SCROLL_CAPTURE:
6268                      handleScrollCaptureRequest((IScrollCaptureResponseListener) msg.obj);
6269                      break;
6270                  case MSG_PAUSED_FOR_SYNC_TIMEOUT:
6271                      Log.e(mTag, "Timedout waiting to unpause for sync");
6272                      mNumPausedForSync = 0;
6273                      scheduleTraversals();
6274                      break;
6275              }
6276          }
6277      }
6278  
6279      final ViewRootHandler mHandler = new ViewRootHandler();
6280      private final Executor mExecutor = (Runnable r) -> {
6281          mHandler.post(r);
6282      };
6283  
6284      /**
6285       * Something in the current window tells us we need to change the touch mode.  For
6286       * example, we are not in touch mode, and the user touches the screen.
6287       *
6288       * If the touch mode has changed, tell the window manager, and handle it locally.
6289       *
6290       * @param inTouchMode Whether we want to be in touch mode.
6291       * @return True if the touch mode changed and focus changed was changed as a result
6292       */
6293      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
ensureTouchMode(boolean inTouchMode)6294      boolean ensureTouchMode(boolean inTouchMode) {
6295          if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
6296                  + "touch mode is " + mAttachInfo.mInTouchMode);
6297          if (mAttachInfo.mInTouchMode == inTouchMode) return false;
6298  
6299          // tell the window manager
6300          try {
6301              IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService();
6302              windowManager.setInTouchMode(inTouchMode, getDisplayId());
6303          } catch (RemoteException e) {
6304              throw new RuntimeException(e);
6305          }
6306  
6307          // handle the change
6308          return ensureTouchModeLocally(inTouchMode);
6309      }
6310  
6311      /**
6312       * Ensure that the touch mode for this window is set, and if it is changing,
6313       * take the appropriate action.
6314       * @param inTouchMode Whether we want to be in touch mode.
6315       * @return True if the touch mode changed and focus changed was changed as a result
6316       */
ensureTouchModeLocally(boolean inTouchMode)6317      private boolean ensureTouchModeLocally(boolean inTouchMode) {
6318          if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
6319                  + "touch mode is " + mAttachInfo.mInTouchMode);
6320  
6321          if (mAttachInfo.mInTouchMode == inTouchMode) return false;
6322  
6323          mAttachInfo.mInTouchMode = inTouchMode;
6324          mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
6325  
6326          return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
6327      }
6328  
enterTouchMode()6329      private boolean enterTouchMode() {
6330          if (mView != null && mView.hasFocus()) {
6331              // note: not relying on mFocusedView here because this could
6332              // be when the window is first being added, and mFocused isn't
6333              // set yet.
6334              final View focused = mView.findFocus();
6335              if (focused != null && !focused.isFocusableInTouchMode()) {
6336                  final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
6337                  if (ancestorToTakeFocus != null) {
6338                      // there is an ancestor that wants focus after its
6339                      // descendants that is focusable in touch mode.. give it
6340                      // focus
6341                      return ancestorToTakeFocus.requestFocus();
6342                  } else {
6343                      // There's nothing to focus. Clear and propagate through the
6344                      // hierarchy, but don't attempt to place new focus.
6345                      focused.clearFocusInternal(null, true, false);
6346                      return true;
6347                  }
6348              }
6349          }
6350          return false;
6351      }
6352  
6353      /**
6354       * Find an ancestor of focused that wants focus after its descendants and is
6355       * focusable in touch mode.
6356       * @param focused The currently focused view.
6357       * @return An appropriate view, or null if no such view exists.
6358       */
findAncestorToTakeFocusInTouchMode(View focused)6359      private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
6360          ViewParent parent = focused.getParent();
6361          while (parent instanceof ViewGroup) {
6362              final ViewGroup vgParent = (ViewGroup) parent;
6363              if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
6364                      && vgParent.isFocusableInTouchMode()) {
6365                  return vgParent;
6366              }
6367              if (vgParent.isRootNamespace()) {
6368                  return null;
6369              } else {
6370                  parent = vgParent.getParent();
6371              }
6372          }
6373          return null;
6374      }
6375  
leaveTouchMode()6376      private boolean leaveTouchMode() {
6377          if (mView != null) {
6378              if (mView.hasFocus()) {
6379                  View focusedView = mView.findFocus();
6380                  if (!(focusedView instanceof ViewGroup)) {
6381                      // some view has focus, let it keep it
6382                      return false;
6383                  } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
6384                          ViewGroup.FOCUS_AFTER_DESCENDANTS) {
6385                      // some view group has focus, and doesn't prefer its children
6386                      // over itself for focus, so let them keep it.
6387                      return false;
6388                  }
6389              }
6390  
6391              // find the best view to give focus to in this brave new non-touch-mode
6392              // world
6393              return mView.restoreDefaultFocus();
6394          }
6395          return false;
6396      }
6397  
6398      /**
6399       * Base class for implementing a stage in the chain of responsibility
6400       * for processing input events.
6401       * <p>
6402       * Events are delivered to the stage by the {@link #deliver} method.  The stage
6403       * then has the choice of finishing the event or forwarding it to the next stage.
6404       * </p>
6405       */
6406      abstract class InputStage {
6407          private final InputStage mNext;
6408  
6409          protected static final int FORWARD = 0;
6410          protected static final int FINISH_HANDLED = 1;
6411          protected static final int FINISH_NOT_HANDLED = 2;
6412  
6413          private String mTracePrefix;
6414  
6415          /**
6416           * Creates an input stage.
6417           * @param next The next stage to which events should be forwarded.
6418           */
InputStage(InputStage next)6419          public InputStage(InputStage next) {
6420              mNext = next;
6421          }
6422  
6423          /**
6424           * Delivers an event to be processed.
6425           */
deliver(QueuedInputEvent q)6426          public final void deliver(QueuedInputEvent q) {
6427              if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
6428                  forward(q);
6429              } else if (shouldDropInputEvent(q)) {
6430                  finish(q, false);
6431              } else {
6432                  traceEvent(q, Trace.TRACE_TAG_VIEW);
6433                  final int result;
6434                  try {
6435                      result = onProcess(q);
6436                  } finally {
6437                      Trace.traceEnd(Trace.TRACE_TAG_VIEW);
6438                  }
6439                  apply(q, result);
6440              }
6441          }
6442  
6443          /**
6444           * Marks the input event as finished then forwards it to the next stage.
6445           */
finish(QueuedInputEvent q, boolean handled)6446          protected void finish(QueuedInputEvent q, boolean handled) {
6447              q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
6448              if (handled) {
6449                  q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
6450              }
6451              forward(q);
6452          }
6453  
6454          /**
6455           * Forwards the event to the next stage.
6456           */
forward(QueuedInputEvent q)6457          protected void forward(QueuedInputEvent q) {
6458              onDeliverToNext(q);
6459          }
6460  
6461          /**
6462           * Applies a result code from {@link #onProcess} to the specified event.
6463           */
apply(QueuedInputEvent q, int result)6464          protected void apply(QueuedInputEvent q, int result) {
6465              if (result == FORWARD) {
6466                  forward(q);
6467              } else if (result == FINISH_HANDLED) {
6468                  finish(q, true);
6469              } else if (result == FINISH_NOT_HANDLED) {
6470                  finish(q, false);
6471              } else {
6472                  throw new IllegalArgumentException("Invalid result: " + result);
6473              }
6474          }
6475  
6476          /**
6477           * Called when an event is ready to be processed.
6478           * @return A result code indicating how the event was handled.
6479           */
onProcess(QueuedInputEvent q)6480          protected int onProcess(QueuedInputEvent q) {
6481              return FORWARD;
6482          }
6483  
6484          /**
6485           * Called when an event is being delivered to the next stage.
6486           */
onDeliverToNext(QueuedInputEvent q)6487          protected void onDeliverToNext(QueuedInputEvent q) {
6488              if (DEBUG_INPUT_STAGES) {
6489                  Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
6490              }
6491              if (mNext != null) {
6492                  mNext.deliver(q);
6493              } else {
6494                  finishInputEvent(q);
6495              }
6496          }
6497  
onWindowFocusChanged(boolean hasWindowFocus)6498          protected void onWindowFocusChanged(boolean hasWindowFocus) {
6499              if (mNext != null) {
6500                  mNext.onWindowFocusChanged(hasWindowFocus);
6501              }
6502          }
6503  
onDetachedFromWindow()6504          protected void onDetachedFromWindow() {
6505              if (mNext != null) {
6506                  mNext.onDetachedFromWindow();
6507              }
6508          }
6509  
shouldDropInputEvent(QueuedInputEvent q)6510          protected boolean shouldDropInputEvent(QueuedInputEvent q) {
6511              if (mView == null || !mAdded) {
6512                  Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
6513                  return true;
6514              }
6515  
6516              // Find a reason for dropping or canceling the event.
6517              final String reason;
6518              if (!mAttachInfo.mHasWindowFocus
6519                      && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
6520                      && !isAutofillUiShowing()) {
6521                  // This is a non-pointer event and the window doesn't currently have input focus
6522                  // This could be an event that came back from the previous stage
6523                  // but the window has lost focus or stopped in the meantime.
6524                  reason = "no window focus";
6525              } else if (mStopped) {
6526                  reason = "window is stopped";
6527              } else if (mIsAmbientMode
6528                      && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) {
6529                  reason = "non-button event in ambient mode";
6530              } else if (mPausedForTransition && !isBack(q.mEvent)) {
6531                  reason = "paused for transition";
6532              } else {
6533                  // Most common path: no reason to drop or cancel the event
6534                  return false;
6535              }
6536  
6537              if (isTerminalInputEvent(q.mEvent)) {
6538                  // Don't drop terminal input events, however mark them as canceled.
6539                  q.mEvent.cancel();
6540                  Slog.w(mTag, "Cancelling event (" + reason + "):" + q.mEvent);
6541                  return false;
6542              }
6543  
6544              // Drop non-terminal input events.
6545              Slog.w(mTag, "Dropping event (" + reason + "):" + q.mEvent);
6546              return true;
6547          }
6548  
dump(String prefix, PrintWriter writer)6549          void dump(String prefix, PrintWriter writer) {
6550              if (mNext != null) {
6551                  mNext.dump(prefix, writer);
6552              }
6553          }
6554  
isBack(InputEvent event)6555          boolean isBack(InputEvent event) {
6556              if (event instanceof KeyEvent) {
6557                  return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
6558              } else {
6559                  return false;
6560              }
6561          }
6562  
traceEvent(QueuedInputEvent q, long traceTag)6563          private void traceEvent(QueuedInputEvent q, long traceTag) {
6564              if (!Trace.isTagEnabled(traceTag)) {
6565                  return;
6566              }
6567  
6568              if (mTracePrefix == null) {
6569                  mTracePrefix = getClass().getSimpleName();
6570              }
6571              Trace.traceBegin(traceTag, mTracePrefix + " id=0x"
6572                      + Integer.toHexString(q.mEvent.getId()));
6573          }
6574      }
6575  
6576      /**
6577       * Base class for implementing an input pipeline stage that supports
6578       * asynchronous and out-of-order processing of input events.
6579       * <p>
6580       * In addition to what a normal input stage can do, an asynchronous
6581       * input stage may also defer an input event that has been delivered to it
6582       * and finish or forward it later.
6583       * </p>
6584       */
6585      abstract class AsyncInputStage extends InputStage {
6586          private final String mTraceCounter;
6587  
6588          private QueuedInputEvent mQueueHead;
6589          private QueuedInputEvent mQueueTail;
6590          private int mQueueLength;
6591  
6592          protected static final int DEFER = 3;
6593  
6594          /**
6595           * Creates an asynchronous input stage.
6596           * @param next The next stage to which events should be forwarded.
6597           * @param traceCounter The name of a counter to record the size of
6598           * the queue of pending events.
6599           */
AsyncInputStage(InputStage next, String traceCounter)6600          public AsyncInputStage(InputStage next, String traceCounter) {
6601              super(next);
6602              mTraceCounter = traceCounter;
6603          }
6604  
6605          /**
6606           * Marks the event as deferred, which is to say that it will be handled
6607           * asynchronously.  The caller is responsible for calling {@link #forward}
6608           * or {@link #finish} later when it is done handling the event.
6609           */
defer(QueuedInputEvent q)6610          protected void defer(QueuedInputEvent q) {
6611              q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
6612              enqueue(q);
6613          }
6614  
6615          @Override
forward(QueuedInputEvent q)6616          protected void forward(QueuedInputEvent q) {
6617              // Clear the deferred flag.
6618              q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
6619  
6620              // Fast path if the queue is empty.
6621              QueuedInputEvent curr = mQueueHead;
6622              if (curr == null) {
6623                  super.forward(q);
6624                  return;
6625              }
6626  
6627              // Determine whether the event must be serialized behind any others
6628              // before it can be delivered to the next stage.  This is done because
6629              // deferred events might be handled out of order by the stage.
6630              final int deviceId = q.mEvent.getDeviceId();
6631              QueuedInputEvent prev = null;
6632              boolean blocked = false;
6633              while (curr != null && curr != q) {
6634                  if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
6635                      blocked = true;
6636                  }
6637                  prev = curr;
6638                  curr = curr.mNext;
6639              }
6640  
6641              // If the event is blocked, then leave it in the queue to be delivered later.
6642              // Note that the event might not yet be in the queue if it was not previously
6643              // deferred so we will enqueue it if needed.
6644              if (blocked) {
6645                  if (curr == null) {
6646                      enqueue(q);
6647                  }
6648                  return;
6649              }
6650  
6651              // The event is not blocked.  Deliver it immediately.
6652              if (curr != null) {
6653                  curr = curr.mNext;
6654                  dequeue(q, prev);
6655              }
6656              super.forward(q);
6657  
6658              // Dequeuing this event may have unblocked successors.  Deliver them.
6659              while (curr != null) {
6660                  if (deviceId == curr.mEvent.getDeviceId()) {
6661                      if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
6662                          break;
6663                      }
6664                      QueuedInputEvent next = curr.mNext;
6665                      dequeue(curr, prev);
6666                      super.forward(curr);
6667                      curr = next;
6668                  } else {
6669                      prev = curr;
6670                      curr = curr.mNext;
6671                  }
6672              }
6673          }
6674  
6675          @Override
apply(QueuedInputEvent q, int result)6676          protected void apply(QueuedInputEvent q, int result) {
6677              if (result == DEFER) {
6678                  defer(q);
6679              } else {
6680                  super.apply(q, result);
6681              }
6682          }
6683  
enqueue(QueuedInputEvent q)6684          private void enqueue(QueuedInputEvent q) {
6685              if (mQueueTail == null) {
6686                  mQueueHead = q;
6687                  mQueueTail = q;
6688              } else {
6689                  mQueueTail.mNext = q;
6690                  mQueueTail = q;
6691              }
6692  
6693              mQueueLength += 1;
6694              Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
6695          }
6696  
dequeue(QueuedInputEvent q, QueuedInputEvent prev)6697          private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
6698              if (prev == null) {
6699                  mQueueHead = q.mNext;
6700              } else {
6701                  prev.mNext = q.mNext;
6702              }
6703              if (mQueueTail == q) {
6704                  mQueueTail = prev;
6705              }
6706              q.mNext = null;
6707  
6708              mQueueLength -= 1;
6709              Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
6710          }
6711  
6712          @Override
dump(String prefix, PrintWriter writer)6713          void dump(String prefix, PrintWriter writer) {
6714              writer.print(prefix);
6715              writer.print(getClass().getName());
6716              writer.print(": mQueueLength=");
6717              writer.println(mQueueLength);
6718  
6719              super.dump(prefix, writer);
6720          }
6721      }
6722  
6723      /**
6724       * Delivers pre-ime input events to a native activity.
6725       * Does not support pointer events.
6726       */
6727      final class NativePreImeInputStage extends AsyncInputStage
6728              implements InputQueue.FinishedInputEventCallback {
6729  
NativePreImeInputStage(InputStage next, String traceCounter)6730          public NativePreImeInputStage(InputStage next, String traceCounter) {
6731              super(next, traceCounter);
6732          }
6733  
6734          @Override
onProcess(QueuedInputEvent q)6735          protected int onProcess(QueuedInputEvent q) {
6736              if (q.mEvent instanceof KeyEvent) {
6737                  final KeyEvent keyEvent = (KeyEvent) q.mEvent;
6738  
6739                  // If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the
6740                  // view tree or IME, and invoke the appropriate {@link OnBackInvokedCallback}.
6741                  if (isBack(keyEvent)
6742                          && mContext != null
6743                          && mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
6744                      return doOnBackKeyEvent(keyEvent);
6745                  }
6746  
6747                  if (mInputQueue != null) {
6748                      mInputQueue.sendInputEvent(q.mEvent, q, true, this);
6749                      return DEFER;
6750                  }
6751              }
6752              return FORWARD;
6753          }
6754  
doOnBackKeyEvent(KeyEvent keyEvent)6755          private int doOnBackKeyEvent(KeyEvent keyEvent) {
6756              OnBackInvokedCallback topCallback = getOnBackInvokedDispatcher().getTopCallback();
6757              if (topCallback instanceof OnBackAnimationCallback) {
6758                  final OnBackAnimationCallback animationCallback =
6759                          (OnBackAnimationCallback) topCallback;
6760                  switch (keyEvent.getAction()) {
6761                      case KeyEvent.ACTION_DOWN:
6762                          // ACTION_DOWN is emitted twice: once when the user presses the button,
6763                          // and again a few milliseconds later.
6764                          // Based on the result of `keyEvent.getRepeatCount()` we have:
6765                          // - 0 means the button was pressed.
6766                          // - 1 means the button continues to be pressed (long press).
6767                          if (keyEvent.getRepeatCount() == 0) {
6768                              animationCallback.onBackStarted(
6769                                      new BackEvent(0, 0, 0f, BackEvent.EDGE_LEFT));
6770                          }
6771                          break;
6772                      case KeyEvent.ACTION_UP:
6773                          if (keyEvent.isCanceled()) {
6774                              animationCallback.onBackCancelled();
6775                          } else {
6776                              topCallback.onBackInvoked();
6777                              return FINISH_HANDLED;
6778                          }
6779                          break;
6780                  }
6781              } else if (topCallback != null) {
6782                  if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
6783                      if (!keyEvent.isCanceled()) {
6784                          topCallback.onBackInvoked();
6785                          return FINISH_HANDLED;
6786                      } else {
6787                          Log.d(mTag, "Skip onBackInvoked(), reason: keyEvent.isCanceled=true");
6788                      }
6789                  }
6790              }
6791  
6792              return FINISH_NOT_HANDLED;
6793          }
6794  
6795          @Override
onFinishedInputEvent(Object token, boolean handled)6796          public void onFinishedInputEvent(Object token, boolean handled) {
6797              QueuedInputEvent q = (QueuedInputEvent)token;
6798              if (handled) {
6799                  finish(q, true);
6800                  return;
6801              }
6802              forward(q);
6803          }
6804      }
6805  
6806      /**
6807       * Delivers pre-ime input events to the view hierarchy.
6808       * Does not support pointer events.
6809       */
6810      final class ViewPreImeInputStage extends InputStage {
ViewPreImeInputStage(InputStage next)6811          public ViewPreImeInputStage(InputStage next) {
6812              super(next);
6813          }
6814  
6815          @Override
onProcess(QueuedInputEvent q)6816          protected int onProcess(QueuedInputEvent q) {
6817              if (q.mEvent instanceof KeyEvent) {
6818                  return processKeyEvent(q);
6819              }
6820              return FORWARD;
6821          }
6822  
processKeyEvent(QueuedInputEvent q)6823          private int processKeyEvent(QueuedInputEvent q) {
6824              final KeyEvent event = (KeyEvent)q.mEvent;
6825              if (mView.dispatchKeyEventPreIme(event)) {
6826                  return FINISH_HANDLED;
6827              }
6828              return FORWARD;
6829          }
6830      }
6831  
6832      /**
6833       * Delivers input events to the ime.
6834       * Does not support pointer events.
6835       */
6836      final class ImeInputStage extends AsyncInputStage
6837              implements InputMethodManager.FinishedInputEventCallback {
ImeInputStage(InputStage next, String traceCounter)6838          public ImeInputStage(InputStage next, String traceCounter) {
6839              super(next, traceCounter);
6840          }
6841  
6842          @Override
onProcess(QueuedInputEvent q)6843          protected int onProcess(QueuedInputEvent q) {
6844              final int result = mImeFocusController.onProcessImeInputStage(
6845                      q, q.mEvent, mWindowAttributes, this);
6846              switch (result) {
6847                  case InputMethodManager.DISPATCH_IN_PROGRESS:
6848                      // callback will be invoked later
6849                      return DEFER;
6850                  case InputMethodManager.DISPATCH_NOT_HANDLED:
6851                      // The IME could not handle it, so skip along to the next InputStage
6852                      return FORWARD;
6853                  case InputMethodManager.DISPATCH_HANDLED:
6854                      return FINISH_HANDLED;
6855                  default:
6856                      throw new IllegalStateException("Unexpected result=" + result);
6857              }
6858          }
6859  
6860          @Override
onFinishedInputEvent(Object token, boolean handled)6861          public void onFinishedInputEvent(Object token, boolean handled) {
6862              QueuedInputEvent q = (QueuedInputEvent)token;
6863              if (handled) {
6864                  finish(q, true);
6865                  return;
6866              }
6867              forward(q);
6868          }
6869      }
6870  
6871      /**
6872       * Performs early processing of post-ime input events.
6873       */
6874      final class EarlyPostImeInputStage extends InputStage {
EarlyPostImeInputStage(InputStage next)6875          public EarlyPostImeInputStage(InputStage next) {
6876              super(next);
6877          }
6878  
6879          @Override
onProcess(QueuedInputEvent q)6880          protected int onProcess(QueuedInputEvent q) {
6881              if (q.mEvent instanceof KeyEvent) {
6882                  return processKeyEvent(q);
6883              } else if (q.mEvent instanceof MotionEvent) {
6884                  return processMotionEvent(q);
6885              }
6886              return FORWARD;
6887          }
6888  
processKeyEvent(QueuedInputEvent q)6889          private int processKeyEvent(QueuedInputEvent q) {
6890              final KeyEvent event = (KeyEvent)q.mEvent;
6891  
6892              if (mAttachInfo.mTooltipHost != null) {
6893                  mAttachInfo.mTooltipHost.handleTooltipKey(event);
6894              }
6895  
6896              // If the key's purpose is to exit touch mode then we consume it
6897              // and consider it handled.
6898              if (checkForLeavingTouchModeAndConsume(event)) {
6899                  return FINISH_HANDLED;
6900              }
6901  
6902              // Make sure the fallback event policy sees all keys that will be
6903              // delivered to the view hierarchy.
6904              mFallbackEventHandler.preDispatchKeyEvent(event);
6905  
6906              // Reset last tracked MotionEvent click toolType.
6907              if (event.getAction() == KeyEvent.ACTION_DOWN) {
6908                  mLastClickToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
6909              }
6910  
6911              return FORWARD;
6912          }
6913  
processMotionEvent(QueuedInputEvent q)6914          private int processMotionEvent(QueuedInputEvent q) {
6915              final MotionEvent event = (MotionEvent) q.mEvent;
6916  
6917              if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
6918                  return processPointerEvent(q);
6919              }
6920  
6921              // If the motion event is from an absolute position device, exit touch mode
6922              final int action = event.getActionMasked();
6923              if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
6924                  if (event.isFromSource(InputDevice.SOURCE_CLASS_POSITION)) {
6925                      ensureTouchMode(false);
6926                  }
6927              }
6928              return FORWARD;
6929          }
6930  
processPointerEvent(QueuedInputEvent q)6931          private int processPointerEvent(QueuedInputEvent q) {
6932              final MotionEvent event = (MotionEvent)q.mEvent;
6933  
6934              // Translate the pointer event for compatibility, if needed.
6935              if (mTranslator != null) {
6936                  mTranslator.translateEventInScreenToAppWindow(event);
6937              }
6938  
6939              // Enter touch mode on down or scroll from any type of a device.
6940              final int action = event.getAction();
6941              if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
6942                  ensureTouchMode(true);
6943              }
6944  
6945              if (action == MotionEvent.ACTION_DOWN) {
6946                  // Upon motion event within app window, close autofill ui.
6947                  AutofillManager afm = getAutofillManager();
6948                  if (afm != null) {
6949                      afm.requestHideFillUi();
6950                  }
6951              }
6952  
6953              if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
6954                  mAttachInfo.mTooltipHost.hideTooltip();
6955              }
6956  
6957              // Offset the scroll position.
6958              if (mCurScrollY != 0) {
6959                  event.offsetLocation(0, mCurScrollY);
6960              }
6961  
6962              if (event.isTouchEvent()) {
6963                  // Remember the touch position for possible drag-initiation.
6964                  mLastTouchPoint.x = event.getRawX();
6965                  mLastTouchPoint.y = event.getRawY();
6966                  mLastTouchSource = event.getSource();
6967  
6968                  // Register last ACTION_UP. This will be propagated to IME.
6969                  if (event.getActionMasked() == MotionEvent.ACTION_UP) {
6970                      mLastClickToolType = event.getToolType(event.getActionIndex());
6971                  }
6972              }
6973              return FORWARD;
6974          }
6975      }
6976  
6977      /**
6978       * Delivers post-ime input events to a native activity.
6979       */
6980      final class NativePostImeInputStage extends AsyncInputStage
6981              implements InputQueue.FinishedInputEventCallback {
NativePostImeInputStage(InputStage next, String traceCounter)6982          public NativePostImeInputStage(InputStage next, String traceCounter) {
6983              super(next, traceCounter);
6984          }
6985  
6986          @Override
onProcess(QueuedInputEvent q)6987          protected int onProcess(QueuedInputEvent q) {
6988              if (mInputQueue != null) {
6989                  mInputQueue.sendInputEvent(q.mEvent, q, false, this);
6990                  return DEFER;
6991              }
6992              return FORWARD;
6993          }
6994  
6995          @Override
onFinishedInputEvent(Object token, boolean handled)6996          public void onFinishedInputEvent(Object token, boolean handled) {
6997              QueuedInputEvent q = (QueuedInputEvent)token;
6998              if (handled) {
6999                  finish(q, true);
7000                  return;
7001              }
7002              forward(q);
7003          }
7004      }
7005  
7006      /**
7007       * Restores the refresh rate after leaving typing, the leaving typing cases like
7008       * the IME insets is invisible or the user interacts the screen outside keyboard.
7009       */
7010      @UiThread
notifyLeaveTypingEvent()7011      private void notifyLeaveTypingEvent() {
7012          if (mRefreshRateController != null && mActiveTypingHintNotifier.get() != null) {
7013              mRefreshRateController.updateRefreshRatePreference(RESTORE);
7014          }
7015      }
7016  
7017      /**
7018       * Delivers post-ime input events to the view hierarchy.
7019       */
7020      final class ViewPostImeInputStage extends InputStage {
ViewPostImeInputStage(InputStage next)7021          public ViewPostImeInputStage(InputStage next) {
7022              super(next);
7023          }
7024  
7025          @Override
onProcess(QueuedInputEvent q)7026          protected int onProcess(QueuedInputEvent q) {
7027              if (q.mEvent instanceof KeyEvent) {
7028                  return processKeyEvent(q);
7029              } else {
7030                  final int source = q.mEvent.getSource();
7031                  if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
7032                      return processPointerEvent(q);
7033                  } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
7034                      return processTrackballEvent(q);
7035                  } else {
7036                      return processGenericMotionEvent(q);
7037                  }
7038              }
7039          }
7040  
7041          @Override
onDeliverToNext(QueuedInputEvent q)7042          protected void onDeliverToNext(QueuedInputEvent q) {
7043              if (mUnbufferedInputDispatch
7044                      && q.mEvent instanceof MotionEvent
7045                      && ((MotionEvent)q.mEvent).isTouchEvent()
7046                      && isTerminalInputEvent(q.mEvent)) {
7047                  mUnbufferedInputDispatch = false;
7048                  scheduleConsumeBatchedInput();
7049              }
7050              super.onDeliverToNext(q);
7051          }
7052  
performFocusNavigation(KeyEvent event)7053          private boolean performFocusNavigation(KeyEvent event) {
7054              int direction = 0;
7055              switch (event.getKeyCode()) {
7056                  case KeyEvent.KEYCODE_DPAD_LEFT:
7057                      if (event.hasNoModifiers()) {
7058                          direction = View.FOCUS_LEFT;
7059                      }
7060                      break;
7061                  case KeyEvent.KEYCODE_DPAD_RIGHT:
7062                      if (event.hasNoModifiers()) {
7063                          direction = View.FOCUS_RIGHT;
7064                      }
7065                      break;
7066                  case KeyEvent.KEYCODE_DPAD_UP:
7067                      if (event.hasNoModifiers()) {
7068                          direction = View.FOCUS_UP;
7069                      }
7070                      break;
7071                  case KeyEvent.KEYCODE_DPAD_DOWN:
7072                      if (event.hasNoModifiers()) {
7073                          direction = View.FOCUS_DOWN;
7074                      }
7075                      break;
7076                  case KeyEvent.KEYCODE_TAB:
7077                      if (event.hasNoModifiers()) {
7078                          direction = View.FOCUS_FORWARD;
7079                      } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
7080                          direction = View.FOCUS_BACKWARD;
7081                      }
7082                      break;
7083              }
7084              if (direction != 0) {
7085                  View focused = mView.findFocus();
7086                  if (focused != null) {
7087                      View v = focused.focusSearch(direction);
7088                      if (v != null && v != focused) {
7089                          // do the math the get the interesting rect
7090                          // of previous focused into the coord system of
7091                          // newly focused view
7092                          focused.getFocusedRect(mTempRect);
7093                          if (mView instanceof ViewGroup) {
7094                              ((ViewGroup) mView).offsetDescendantRectToMyCoords(
7095                                      focused, mTempRect);
7096                              ((ViewGroup) mView).offsetRectIntoDescendantCoords(
7097                                      v, mTempRect);
7098                          }
7099                          if (v.requestFocus(direction, mTempRect)) {
7100                              boolean isFastScrolling = event.getRepeatCount() > 0;
7101                              playSoundEffect(
7102                                      SoundEffectConstants.getConstantForFocusDirection(direction,
7103                                              isFastScrolling));
7104                              return true;
7105                          }
7106                      }
7107  
7108                      // Give the focused view a last chance to handle the dpad key.
7109                      if (mView.dispatchUnhandledMove(focused, direction)) {
7110                          return true;
7111                      }
7112                  } else {
7113                      if (mView.restoreDefaultFocus()) {
7114                          return true;
7115                      }
7116                  }
7117              }
7118              return false;
7119          }
7120  
performKeyboardGroupNavigation(int direction)7121          private boolean performKeyboardGroupNavigation(int direction) {
7122              final View focused = mView.findFocus();
7123              if (focused == null && mView.restoreDefaultFocus()) {
7124                  return true;
7125              }
7126              View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction)
7127                      : focused.keyboardNavigationClusterSearch(null, direction);
7128  
7129              // Since requestFocus only takes "real" focus directions (and therefore also
7130              // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN.
7131              int realDirection = direction;
7132              if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
7133                  realDirection = View.FOCUS_DOWN;
7134              }
7135  
7136              if (cluster != null && cluster.isRootNamespace()) {
7137                  // the default cluster. Try to find a non-clustered view to focus.
7138                  if (cluster.restoreFocusNotInCluster()) {
7139                      playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
7140                      return true;
7141                  }
7142                  // otherwise skip to next actual cluster
7143                  cluster = keyboardNavigationClusterSearch(null, direction);
7144              }
7145  
7146              if (cluster != null && cluster.restoreFocusInCluster(realDirection)) {
7147                  playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
7148                  return true;
7149              }
7150  
7151              return false;
7152          }
7153  
processKeyEvent(QueuedInputEvent q)7154          private int processKeyEvent(QueuedInputEvent q) {
7155              final KeyEvent event = (KeyEvent)q.mEvent;
7156  
7157              if (mUnhandledKeyManager.preViewDispatch(event)) {
7158                  return FINISH_HANDLED;
7159              }
7160  
7161              // Deliver the key to the view hierarchy.
7162              if (mView.dispatchKeyEvent(event)) {
7163                  return FINISH_HANDLED;
7164              }
7165  
7166              if (shouldDropInputEvent(q)) {
7167                  return FINISH_NOT_HANDLED;
7168              }
7169  
7170              // This dispatch is for windows that don't have a Window.Callback. Otherwise,
7171              // the Window.Callback usually will have already called this (see
7172              // DecorView.superDispatchKeyEvent) leaving this call a no-op.
7173              if (mUnhandledKeyManager.dispatch(mView, event)) {
7174                  return FINISH_HANDLED;
7175              }
7176  
7177              int groupNavigationDirection = 0;
7178  
7179              if (event.getAction() == KeyEvent.ACTION_DOWN
7180                      && event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
7181                  if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_CTRL_ON)) {
7182                      groupNavigationDirection = View.FOCUS_FORWARD;
7183                  } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),
7184                          KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) {
7185                      groupNavigationDirection = View.FOCUS_BACKWARD;
7186                  }
7187              }
7188  
7189              // If a modifier is held, try to interpret the key as a shortcut.
7190              if (event.getAction() == KeyEvent.ACTION_DOWN
7191                      && !KeyEvent.metaStateHasNoModifiers(event.getMetaState())
7192                      && event.getRepeatCount() == 0
7193                      && !KeyEvent.isModifierKey(event.getKeyCode())
7194                      && groupNavigationDirection == 0) {
7195                  if (mView.dispatchKeyShortcutEvent(event)) {
7196                      return FINISH_HANDLED;
7197                  }
7198                  if (shouldDropInputEvent(q)) {
7199                      return FINISH_NOT_HANDLED;
7200                  }
7201              }
7202  
7203              // Apply the fallback event policy.
7204              if (mFallbackEventHandler.dispatchKeyEvent(event)) {
7205                  return FINISH_HANDLED;
7206              }
7207              if (shouldDropInputEvent(q)) {
7208                  return FINISH_NOT_HANDLED;
7209              }
7210  
7211              // Handle automatic focus changes.
7212              if (event.getAction() == KeyEvent.ACTION_DOWN) {
7213                  if (groupNavigationDirection != 0) {
7214                      if (performKeyboardGroupNavigation(groupNavigationDirection)) {
7215                          return FINISH_HANDLED;
7216                      }
7217                  } else {
7218                      if (performFocusNavigation(event)) {
7219                          return FINISH_HANDLED;
7220                      }
7221                  }
7222              }
7223              return FORWARD;
7224          }
7225  
processPointerEvent(QueuedInputEvent q)7226          private int processPointerEvent(QueuedInputEvent q) {
7227              final MotionEvent event = (MotionEvent)q.mEvent;
7228              boolean handled = mHandwritingInitiator.onTouchEvent(event);
7229              if (handled) {
7230                  // If handwriting is started, toolkit doesn't receive ACTION_UP.
7231                  mLastClickToolType = event.getToolType(event.getActionIndex());
7232              }
7233  
7234              if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
7235                  notifyLeaveTypingEvent();
7236              }
7237  
7238              mAttachInfo.mUnbufferedDispatchRequested = false;
7239              mAttachInfo.mHandlingPointerEvent = true;
7240              // If the event was fully handled by the handwriting initiator, then don't dispatch it
7241              // to the view tree.
7242              handled = handled || mView.dispatchPointerEvent(event);
7243              maybeUpdatePointerIcon(event);
7244              maybeUpdateTooltip(event);
7245              mAttachInfo.mHandlingPointerEvent = false;
7246              if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
7247                  mUnbufferedInputDispatch = true;
7248                  if (mConsumeBatchedInputScheduled) {
7249                      scheduleConsumeBatchedInputImmediately();
7250                  }
7251              }
7252              return handled ? FINISH_HANDLED : FORWARD;
7253          }
7254  
maybeUpdatePointerIcon(MotionEvent event)7255          private void maybeUpdatePointerIcon(MotionEvent event) {
7256              if (event.getPointerCount() != 1) {
7257                  return;
7258              }
7259              final boolean needsStylusPointerIcon = event.isStylusPointer()
7260                      && event.isHoverEvent()
7261                      && mIsStylusPointerIconEnabled;
7262              if (needsStylusPointerIcon || event.isFromSource(InputDevice.SOURCE_MOUSE)) {
7263                  if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
7264                          || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
7265                      // Other apps or the window manager may change the icon type outside of
7266                      // this app, therefore the icon type has to be reset on enter/exit event.
7267                      mPointerIconType = null;
7268                  }
7269  
7270                  if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
7271                      if (!updatePointerIcon(event) &&
7272                              event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
7273                          mPointerIconType = null;
7274                      }
7275                  }
7276              }
7277          }
7278  
processTrackballEvent(QueuedInputEvent q)7279          private int processTrackballEvent(QueuedInputEvent q) {
7280              final MotionEvent event = (MotionEvent)q.mEvent;
7281  
7282              if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
7283                  if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) {
7284                      return FINISH_HANDLED;
7285                  }
7286              }
7287  
7288              if (mView.dispatchTrackballEvent(event)) {
7289                  return FINISH_HANDLED;
7290              }
7291              return FORWARD;
7292          }
7293  
processGenericMotionEvent(QueuedInputEvent q)7294          private int processGenericMotionEvent(QueuedInputEvent q) {
7295              final MotionEvent event = (MotionEvent)q.mEvent;
7296  
7297              if (event.isFromSource(InputDevice.SOURCE_TOUCHPAD)) {
7298                  if (hasPointerCapture() && mView.dispatchCapturedPointerEvent(event)) {
7299                      return FINISH_HANDLED;
7300                  }
7301              }
7302  
7303              // Deliver the event to the view.
7304              if (mView.dispatchGenericMotionEvent(event)) {
7305                  return FINISH_HANDLED;
7306              }
7307              return FORWARD;
7308          }
7309      }
7310  
resetPointerIcon(MotionEvent event)7311      private void resetPointerIcon(MotionEvent event) {
7312          mPointerIconType = null;
7313          updatePointerIcon(event);
7314      }
7315  
updatePointerIcon(MotionEvent event)7316      private boolean updatePointerIcon(MotionEvent event) {
7317          final int pointerIndex = 0;
7318          final float x = event.getX(pointerIndex);
7319          final float y = event.getY(pointerIndex);
7320          if (mView == null) {
7321              // E.g. click outside a popup to dismiss it
7322              Slog.d(mTag, "updatePointerIcon called after view was removed");
7323              return false;
7324          }
7325          if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
7326              // E.g. when moving window divider with mouse
7327              Slog.d(mTag, "updatePointerIcon called with position out of bounds");
7328              return false;
7329          }
7330  
7331          PointerIcon pointerIcon = null;
7332          if (event.isStylusPointer() && mIsStylusPointerIconEnabled) {
7333              pointerIcon = mHandwritingInitiator.onResolvePointerIcon(mContext, event);
7334          }
7335  
7336          if (pointerIcon == null) {
7337              pointerIcon = mView.onResolvePointerIcon(event, pointerIndex);
7338          }
7339  
7340          final int pointerType = (pointerIcon != null) ?
7341                  pointerIcon.getType() : PointerIcon.TYPE_NOT_SPECIFIED;
7342  
7343          if (mPointerIconType == null || mPointerIconType != pointerType) {
7344              mPointerIconType = pointerType;
7345              mCustomPointerIcon = null;
7346              if (mPointerIconType != PointerIcon.TYPE_CUSTOM) {
7347                  InputManagerGlobal
7348                      .getInstance()
7349                      .setPointerIconType(pointerType);
7350                  return true;
7351              }
7352          }
7353          if (mPointerIconType == PointerIcon.TYPE_CUSTOM &&
7354                  !pointerIcon.equals(mCustomPointerIcon)) {
7355              mCustomPointerIcon = pointerIcon;
7356              InputManagerGlobal
7357                      .getInstance()
7358                      .setCustomPointerIcon(mCustomPointerIcon);
7359          }
7360          return true;
7361      }
7362  
maybeUpdateTooltip(MotionEvent event)7363      private void maybeUpdateTooltip(MotionEvent event) {
7364          if (event.getPointerCount() != 1) {
7365              return;
7366          }
7367          final int action = event.getActionMasked();
7368          if (action != MotionEvent.ACTION_HOVER_ENTER
7369                  && action != MotionEvent.ACTION_HOVER_MOVE
7370                  && action != MotionEvent.ACTION_HOVER_EXIT) {
7371              return;
7372          }
7373          AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
7374          if (manager.isEnabled() && manager.isTouchExplorationEnabled()) {
7375              return;
7376          }
7377          if (mView == null) {
7378              Slog.d(mTag, "maybeUpdateTooltip called after view was removed");
7379              return;
7380          }
7381          mView.dispatchTooltipHoverEvent(event);
7382      }
7383  
7384      @Nullable
getFocusedViewOrNull()7385      private View getFocusedViewOrNull() {
7386          return mView != null ? mView.findFocus() : null;
7387      }
7388  
7389      /**
7390       * Performs synthesis of new input events from unhandled input events.
7391       */
7392      final class SyntheticInputStage extends InputStage {
7393          private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
7394          private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
7395          private final SyntheticTouchNavigationHandler mTouchNavigation =
7396                  new SyntheticTouchNavigationHandler();
7397          private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
7398  
SyntheticInputStage()7399          public SyntheticInputStage() {
7400              super(null);
7401          }
7402  
7403          @Override
onProcess(QueuedInputEvent q)7404          protected int onProcess(QueuedInputEvent q) {
7405              q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
7406              if (q.mEvent instanceof MotionEvent) {
7407                  final MotionEvent event = (MotionEvent)q.mEvent;
7408                  final int source = event.getSource();
7409                  if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
7410                      mTrackball.process(event);
7411                      return FINISH_HANDLED;
7412                  } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
7413                      mJoystick.process(event);
7414                      return FINISH_HANDLED;
7415                  } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
7416                          == InputDevice.SOURCE_TOUCH_NAVIGATION) {
7417                      mTouchNavigation.process(event);
7418                      return FINISH_HANDLED;
7419                  }
7420              } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
7421                  mKeyboard.process((KeyEvent)q.mEvent);
7422                  return FINISH_HANDLED;
7423              }
7424  
7425              return FORWARD;
7426          }
7427  
7428          @Override
onDeliverToNext(QueuedInputEvent q)7429          protected void onDeliverToNext(QueuedInputEvent q) {
7430              if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
7431                  // Cancel related synthetic events if any prior stage has handled the event.
7432                  if (q.mEvent instanceof MotionEvent) {
7433                      final MotionEvent event = (MotionEvent)q.mEvent;
7434                      final int source = event.getSource();
7435                      if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
7436                          mTrackball.cancel();
7437                      } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
7438                          mJoystick.cancel();
7439                      } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
7440                              == InputDevice.SOURCE_TOUCH_NAVIGATION) {
7441                          // Touch navigation events cannot be cancelled since they are dispatched
7442                          // immediately.
7443                      }
7444                  }
7445              }
7446              super.onDeliverToNext(q);
7447          }
7448  
7449          @Override
onWindowFocusChanged(boolean hasWindowFocus)7450          protected void onWindowFocusChanged(boolean hasWindowFocus) {
7451              if (!hasWindowFocus) {
7452                  mJoystick.cancel();
7453              }
7454          }
7455  
7456          @Override
onDetachedFromWindow()7457          protected void onDetachedFromWindow() {
7458              mJoystick.cancel();
7459          }
7460      }
7461  
7462      /**
7463       * Creates dpad events from unhandled trackball movements.
7464       */
7465      final class SyntheticTrackballHandler {
7466          private final TrackballAxis mX = new TrackballAxis();
7467          private final TrackballAxis mY = new TrackballAxis();
7468          private long mLastTime;
7469  
process(MotionEvent event)7470          public void process(MotionEvent event) {
7471              // Translate the trackball event into DPAD keys and try to deliver those.
7472              long curTime = SystemClock.uptimeMillis();
7473              if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
7474                  // It has been too long since the last movement,
7475                  // so restart at the beginning.
7476                  mX.reset(0);
7477                  mY.reset(0);
7478                  mLastTime = curTime;
7479              }
7480  
7481              final int action = event.getAction();
7482              final int metaState = event.getMetaState();
7483              switch (action) {
7484                  case MotionEvent.ACTION_DOWN:
7485                      mX.reset(2);
7486                      mY.reset(2);
7487                      enqueueInputEvent(new KeyEvent(curTime, curTime,
7488                              KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
7489                              KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
7490                              InputDevice.SOURCE_KEYBOARD));
7491                      break;
7492                  case MotionEvent.ACTION_UP:
7493                      mX.reset(2);
7494                      mY.reset(2);
7495                      enqueueInputEvent(new KeyEvent(curTime, curTime,
7496                              KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
7497                              KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
7498                              InputDevice.SOURCE_KEYBOARD));
7499                      break;
7500              }
7501  
7502              if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
7503                      + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
7504                      + " move=" + event.getX()
7505                      + " / Y=" + mY.position + " step="
7506                      + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
7507                      + " move=" + event.getY());
7508              final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
7509              final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
7510  
7511              // Generate DPAD events based on the trackball movement.
7512              // We pick the axis that has moved the most as the direction of
7513              // the DPAD.  When we generate DPAD events for one axis, then the
7514              // other axis is reset -- we don't want to perform DPAD jumps due
7515              // to slight movements in the trackball when making major movements
7516              // along the other axis.
7517              int keycode = 0;
7518              int movement = 0;
7519              float accel = 1;
7520              if (xOff > yOff) {
7521                  movement = mX.generate();
7522                  if (movement != 0) {
7523                      keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
7524                              : KeyEvent.KEYCODE_DPAD_LEFT;
7525                      accel = mX.acceleration;
7526                      mY.reset(2);
7527                  }
7528              } else if (yOff > 0) {
7529                  movement = mY.generate();
7530                  if (movement != 0) {
7531                      keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
7532                              : KeyEvent.KEYCODE_DPAD_UP;
7533                      accel = mY.acceleration;
7534                      mX.reset(2);
7535                  }
7536              }
7537  
7538              if (keycode != 0) {
7539                  if (movement < 0) movement = -movement;
7540                  int accelMovement = (int)(movement * accel);
7541                  if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
7542                          + " accelMovement=" + accelMovement
7543                          + " accel=" + accel);
7544                  if (accelMovement > movement) {
7545                      if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
7546                              + keycode);
7547                      movement--;
7548                      int repeatCount = accelMovement - movement;
7549                      enqueueInputEvent(new KeyEvent(curTime, curTime,
7550                              KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
7551                              KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
7552                              InputDevice.SOURCE_KEYBOARD));
7553                  }
7554                  while (movement > 0) {
7555                      if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
7556                              + keycode);
7557                      movement--;
7558                      curTime = SystemClock.uptimeMillis();
7559                      enqueueInputEvent(new KeyEvent(curTime, curTime,
7560                              KeyEvent.ACTION_DOWN, keycode, 0, metaState,
7561                              KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
7562                              InputDevice.SOURCE_KEYBOARD));
7563                      enqueueInputEvent(new KeyEvent(curTime, curTime,
7564                              KeyEvent.ACTION_UP, keycode, 0, metaState,
7565                              KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
7566                              InputDevice.SOURCE_KEYBOARD));
7567                  }
7568                  mLastTime = curTime;
7569              }
7570          }
7571  
cancel()7572          public void cancel() {
7573              mLastTime = Integer.MIN_VALUE;
7574  
7575              // If we reach this, we consumed a trackball event.
7576              // Because we will not translate the trackball event into a key event,
7577              // touch mode will not exit, so we exit touch mode here.
7578              if (mView != null && mAdded) {
7579                  ensureTouchMode(false);
7580              }
7581          }
7582      }
7583  
7584      /**
7585       * Maintains state information for a single trackball axis, generating
7586       * discrete (DPAD) movements based on raw trackball motion.
7587       */
7588      static final class TrackballAxis {
7589          /**
7590           * The maximum amount of acceleration we will apply.
7591           */
7592          static final float MAX_ACCELERATION = 20;
7593  
7594          /**
7595           * The maximum amount of time (in milliseconds) between events in order
7596           * for us to consider the user to be doing fast trackball movements,
7597           * and thus apply an acceleration.
7598           */
7599          static final long FAST_MOVE_TIME = 150;
7600  
7601          /**
7602           * Scaling factor to the time (in milliseconds) between events to how
7603           * much to multiple/divide the current acceleration.  When movement
7604           * is < FAST_MOVE_TIME this multiplies the acceleration; when >
7605           * FAST_MOVE_TIME it divides it.
7606           */
7607          static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
7608  
7609          static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
7610          static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
7611          static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
7612  
7613          float position;
7614          float acceleration = 1;
7615          long lastMoveTime = 0;
7616          int step;
7617          int dir;
7618          int nonAccelMovement;
7619  
reset(int _step)7620          void reset(int _step) {
7621              position = 0;
7622              acceleration = 1;
7623              lastMoveTime = 0;
7624              step = _step;
7625              dir = 0;
7626          }
7627  
7628          /**
7629           * Add trackball movement into the state.  If the direction of movement
7630           * has been reversed, the state is reset before adding the
7631           * movement (so that you don't have to compensate for any previously
7632           * collected movement before see the result of the movement in the
7633           * new direction).
7634           *
7635           * @return Returns the absolute value of the amount of movement
7636           * collected so far.
7637           */
collect(float off, long time, String axis)7638          float collect(float off, long time, String axis) {
7639              long normTime;
7640              if (off > 0) {
7641                  normTime = (long)(off * FAST_MOVE_TIME);
7642                  if (dir < 0) {
7643                      if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
7644                      position = 0;
7645                      step = 0;
7646                      acceleration = 1;
7647                      lastMoveTime = 0;
7648                  }
7649                  dir = 1;
7650              } else if (off < 0) {
7651                  normTime = (long)((-off) * FAST_MOVE_TIME);
7652                  if (dir > 0) {
7653                      if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
7654                      position = 0;
7655                      step = 0;
7656                      acceleration = 1;
7657                      lastMoveTime = 0;
7658                  }
7659                  dir = -1;
7660              } else {
7661                  normTime = 0;
7662              }
7663  
7664              // The number of milliseconds between each movement that is
7665              // considered "normal" and will not result in any acceleration
7666              // or deceleration, scaled by the offset we have here.
7667              if (normTime > 0) {
7668                  long delta = time - lastMoveTime;
7669                  lastMoveTime = time;
7670                  float acc = acceleration;
7671                  if (delta < normTime) {
7672                      // The user is scrolling rapidly, so increase acceleration.
7673                      float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
7674                      if (scale > 1) acc *= scale;
7675                      if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
7676                              + off + " normTime=" + normTime + " delta=" + delta
7677                              + " scale=" + scale + " acc=" + acc);
7678                      acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
7679                  } else {
7680                      // The user is scrolling slowly, so decrease acceleration.
7681                      float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
7682                      if (scale > 1) acc /= scale;
7683                      if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
7684                              + off + " normTime=" + normTime + " delta=" + delta
7685                              + " scale=" + scale + " acc=" + acc);
7686                      acceleration = acc > 1 ? acc : 1;
7687                  }
7688              }
7689              position += off;
7690              return Math.abs(position);
7691          }
7692  
7693          /**
7694           * Generate the number of discrete movement events appropriate for
7695           * the currently collected trackball movement.
7696           *
7697           * @return Returns the number of discrete movements, either positive
7698           * or negative, or 0 if there is not enough trackball movement yet
7699           * for a discrete movement.
7700           */
generate()7701          int generate() {
7702              int movement = 0;
7703              nonAccelMovement = 0;
7704              do {
7705                  final int dir = position >= 0 ? 1 : -1;
7706                  switch (step) {
7707                      // If we are going to execute the first step, then we want
7708                      // to do this as soon as possible instead of waiting for
7709                      // a full movement, in order to make things look responsive.
7710                      case 0:
7711                          if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
7712                              return movement;
7713                          }
7714                          movement += dir;
7715                          nonAccelMovement += dir;
7716                          step = 1;
7717                          break;
7718                      // If we have generated the first movement, then we need
7719                      // to wait for the second complete trackball motion before
7720                      // generating the second discrete movement.
7721                      case 1:
7722                          if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
7723                              return movement;
7724                          }
7725                          movement += dir;
7726                          nonAccelMovement += dir;
7727                          position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
7728                          step = 2;
7729                          break;
7730                      // After the first two, we generate discrete movements
7731                      // consistently with the trackball, applying an acceleration
7732                      // if the trackball is moving quickly.  This is a simple
7733                      // acceleration on top of what we already compute based
7734                      // on how quickly the wheel is being turned, to apply
7735                      // a longer increasing acceleration to continuous movement
7736                      // in one direction.
7737                      default:
7738                          if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
7739                              return movement;
7740                          }
7741                          movement += dir;
7742                          position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
7743                          float acc = acceleration;
7744                          acc *= 1.1f;
7745                          acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
7746                          break;
7747                  }
7748              } while (true);
7749          }
7750      }
7751  
7752      /**
7753       * Creates dpad events from unhandled joystick movements.
7754       */
7755      final class SyntheticJoystickHandler extends Handler {
7756          private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
7757          private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
7758  
7759          private final JoystickAxesState mJoystickAxesState = new JoystickAxesState();
7760          private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>();
7761  
7762          public SyntheticJoystickHandler() {
7763              super(true);
7764          }
7765  
7766          @Override
7767          public void handleMessage(Message msg) {
7768              switch (msg.what) {
7769                  case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
7770                  case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
7771                      if (mAttachInfo.mHasWindowFocus) {
7772                          KeyEvent oldEvent = (KeyEvent) msg.obj;
7773                          KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
7774                                  SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1);
7775                          enqueueInputEvent(e);
7776                          Message m = obtainMessage(msg.what, e);
7777                          m.setAsynchronous(true);
7778                          sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
7779                      }
7780                  } break;
7781              }
7782          }
7783  
7784          public void process(MotionEvent event) {
7785              switch(event.getActionMasked()) {
7786                  case MotionEvent.ACTION_CANCEL:
7787                      cancel();
7788                      break;
7789                  case MotionEvent.ACTION_MOVE:
7790                      update(event);
7791                      break;
7792                  default:
7793                      Log.w(mTag, "Unexpected action: " + event.getActionMasked());
7794              }
7795          }
7796  
7797          private void cancel() {
7798              removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
7799              removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
7800              for (int i = 0; i < mDeviceKeyEvents.size(); i++) {
7801                  final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i);
7802                  if (keyEvent != null) {
7803                      enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent,
7804                              SystemClock.uptimeMillis(), 0));
7805                  }
7806              }
7807              mDeviceKeyEvents.clear();
7808              mJoystickAxesState.resetState();
7809          }
7810  
7811          private void update(MotionEvent event) {
7812              final int historySize = event.getHistorySize();
7813              for (int h = 0; h < historySize; h++) {
7814                  final long time = event.getHistoricalEventTime(h);
7815                  mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
7816                          event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h));
7817                  mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
7818                          event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h));
7819                  mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
7820                          event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h));
7821                  mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
7822                          event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h));
7823              }
7824              final long time = event.getEventTime();
7825              mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
7826                      event.getAxisValue(MotionEvent.AXIS_X));
7827              mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
7828                      event.getAxisValue(MotionEvent.AXIS_Y));
7829              mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
7830                      event.getAxisValue(MotionEvent.AXIS_HAT_X));
7831              mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
7832                      event.getAxisValue(MotionEvent.AXIS_HAT_Y));
7833          }
7834  
7835          final class JoystickAxesState {
7836              // State machine: from neutral state (no button press) can go into
7837              // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event.
7838              // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state,
7839              // emitting an ACTION_UP event.
7840              private static final int STATE_UP_OR_LEFT = -1;
7841              private static final int STATE_NEUTRAL = 0;
7842              private static final int STATE_DOWN_OR_RIGHT = 1;
7843  
7844              final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y}
7845              final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y}
7846  
7847              void resetState() {
7848                  mAxisStatesHat[0] = STATE_NEUTRAL;
7849                  mAxisStatesHat[1] = STATE_NEUTRAL;
7850                  mAxisStatesStick[0] = STATE_NEUTRAL;
7851                  mAxisStatesStick[1] = STATE_NEUTRAL;
7852              }
7853  
7854              void updateStateForAxis(MotionEvent event, long time, int axis, float value) {
7855                  // Emit KeyEvent if necessary
7856                  // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y
7857                  final int axisStateIndex;
7858                  final int repeatMessage;
7859                  if (isXAxis(axis)) {
7860                      axisStateIndex = 0;
7861                      repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT;
7862                  } else if (isYAxis(axis)) {
7863                      axisStateIndex = 1;
7864                      repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT;
7865                  } else {
7866                      Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!");
7867                      return;
7868                  }
7869                  final int newState = joystickAxisValueToState(value);
7870  
7871                  final int currentState;
7872                  if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
7873                      currentState = mAxisStatesStick[axisStateIndex];
7874                  } else {
7875                      currentState = mAxisStatesHat[axisStateIndex];
7876                  }
7877  
7878                  if (currentState == newState) {
7879                      return;
7880                  }
7881  
7882                  final int metaState = event.getMetaState();
7883                  final int deviceId = event.getDeviceId();
7884                  final int source = event.getSource();
7885  
7886                  if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) {
7887                      // send a button release event
7888                      final int keyCode = joystickAxisAndStateToKeycode(axis, currentState);
7889                      if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
7890                          enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
7891                                  0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
7892                          // remove the corresponding pending UP event if focus lost/view detached
7893                          mDeviceKeyEvents.put(deviceId, null);
7894                      }
7895                      removeMessages(repeatMessage);
7896                  }
7897  
7898                  if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) {
7899                      // send a button down event
7900                      final int keyCode = joystickAxisAndStateToKeycode(axis, newState);
7901                      if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
7902                          KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode,
7903                                  0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
7904                          enqueueInputEvent(keyEvent);
7905                          Message m = obtainMessage(repeatMessage, keyEvent);
7906                          m.setAsynchronous(true);
7907                          sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
7908                          // store the corresponding ACTION_UP event so that it can be sent
7909                          // if focus is lost or root view is removed
7910                          mDeviceKeyEvents.put(deviceId,
7911                                  new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
7912                                          0, metaState, deviceId, 0,
7913                                          KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED,
7914                                          source));
7915                      }
7916                  }
7917                  if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
7918                      mAxisStatesStick[axisStateIndex] = newState;
7919                  } else {
7920                      mAxisStatesHat[axisStateIndex] = newState;
7921                  }
7922              }
7923  
7924              private boolean isXAxis(int axis) {
7925                  return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X;
7926              }
7927              private boolean isYAxis(int axis) {
7928                  return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y;
7929              }
7930  
7931              private int joystickAxisAndStateToKeycode(int axis, int state) {
7932                  if (isXAxis(axis) && state == STATE_UP_OR_LEFT) {
7933                      return KeyEvent.KEYCODE_DPAD_LEFT;
7934                  }
7935                  if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
7936                      return KeyEvent.KEYCODE_DPAD_RIGHT;
7937                  }
7938                  if (isYAxis(axis) && state == STATE_UP_OR_LEFT) {
7939                      return KeyEvent.KEYCODE_DPAD_UP;
7940                  }
7941                  if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
7942                      return KeyEvent.KEYCODE_DPAD_DOWN;
7943                  }
7944                  Log.e(mTag, "Unknown axis " + axis + " or direction " + state);
7945                  return KeyEvent.KEYCODE_UNKNOWN; // should never happen
7946              }
7947  
7948              private int joystickAxisValueToState(float value) {
7949                  if (value >= 0.5f) {
7950                      return STATE_DOWN_OR_RIGHT;
7951                  } else if (value <= -0.5f) {
7952                      return STATE_UP_OR_LEFT;
7953                  } else {
7954                      return STATE_NEUTRAL;
7955                  }
7956              }
7957          }
7958      }
7959  
7960      /**
7961       * Creates DPAD events from unhandled touch navigation movements.
7962       */
7963      final class SyntheticTouchNavigationHandler extends Handler {
7964          private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
7965  
7966          // The id of the input device that is being tracked.
7967          private int mCurrentDeviceId = -1;
7968          private int mCurrentSource;
7969  
7970          private int mPendingKeyMetaState;
7971  
7972          private final GestureDetector mGestureDetector = new GestureDetector(mContext,
7973                  new GestureDetector.OnGestureListener() {
7974                      @Override
7975                      public boolean onDown(@NonNull MotionEvent e) {
7976                          // This can be ignored since it's not clear what KeyEvent this will
7977                          // belong to.
7978                          return true;
7979                      }
7980  
7981                      @Override
7982                      public void onShowPress(@NonNull MotionEvent e) {
7983  
7984                      }
7985  
7986                      @Override
7987                      public boolean onSingleTapUp(@NonNull MotionEvent e) {
7988                          dispatchTap(e.getEventTime());
7989                          return true;
7990                      }
7991  
7992                      @Override
7993                      public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
7994                              float distanceX, float distanceY) {
7995                          // Scroll doesn't translate to DPAD events so should be ignored.
7996                          return true;
7997                      }
7998  
7999                      @Override
8000                      public void onLongPress(@NonNull MotionEvent e) {
8001                          // Long presses don't translate to DPAD events so should be ignored.
8002                      }
8003  
8004                      @Override
8005                      public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
8006                              float velocityX, float velocityY) {
8007                          dispatchFling(velocityX, velocityY, e2.getEventTime());
8008                          return true;
8009                      }
8010                  });
8011  
8012          SyntheticTouchNavigationHandler() {
8013              super(true);
8014          }
8015  
8016          public void process(MotionEvent event) {
8017              if (event.getDevice() == null) {
8018                  // The current device is not supported.
8019                  if (DEBUG_TOUCH_NAVIGATION) {
8020                      Log.d(LOCAL_TAG,
8021                              "Current device not supported so motion event is not processed");
8022                  }
8023                  return;
8024              }
8025              mPendingKeyMetaState = event.getMetaState();
8026              // Update the current device information.
8027              final int deviceId = event.getDeviceId();
8028              final int source = event.getSource();
8029              if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
8030                  mCurrentDeviceId = deviceId;
8031                  mCurrentSource = source;
8032              }
8033  
8034              // Interpret the event.
8035              mGestureDetector.onTouchEvent(event);
8036          }
8037  
8038          private void dispatchTap(long time) {
8039              dispatchEvent(time, KeyEvent.KEYCODE_DPAD_CENTER);
8040          }
8041  
8042          private void dispatchFling(float x, float y, long time) {
8043              if (Math.abs(x) > Math.abs(y)) {
8044                  dispatchEvent(time,
8045                          x > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT);
8046              } else {
8047                  dispatchEvent(time, y > 0 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP);
8048              }
8049          }
8050  
dispatchEvent(long time, int keyCode)8051          private void dispatchEvent(long time, int keyCode) {
8052              if (DEBUG_TOUCH_NAVIGATION) {
8053                  Log.d(LOCAL_TAG, "Dispatching DPAD events DOWN and UP with keycode " + keyCode);
8054              }
8055              enqueueInputEvent(new KeyEvent(time, time,
8056                      KeyEvent.ACTION_DOWN, keyCode, /* repeat= */ 0, mPendingKeyMetaState,
8057                      mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK,
8058                      mCurrentSource));
8059              enqueueInputEvent(new KeyEvent(time, time,
8060                      KeyEvent.ACTION_UP, keyCode, /* repeat= */ 0, mPendingKeyMetaState,
8061                      mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK,
8062                      mCurrentSource));
8063          }
8064      }
8065  
8066      final class SyntheticKeyboardHandler {
process(KeyEvent event)8067          public void process(KeyEvent event) {
8068              if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
8069                  return;
8070              }
8071  
8072              final KeyCharacterMap kcm = event.getKeyCharacterMap();
8073              final int keyCode = event.getKeyCode();
8074              final int metaState = event.getMetaState();
8075  
8076              // Check for fallback actions specified by the key character map.
8077              KeyCharacterMap.FallbackAction fallbackAction =
8078                      kcm.getFallbackAction(keyCode, metaState);
8079              if (fallbackAction != null) {
8080                  final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
8081                  KeyEvent fallbackEvent = KeyEvent.obtain(
8082                          event.getDownTime(), event.getEventTime(),
8083                          event.getAction(), fallbackAction.keyCode,
8084                          event.getRepeatCount(), fallbackAction.metaState,
8085                          event.getDeviceId(), event.getScanCode(),
8086                          flags, event.getSource(), null);
8087                  fallbackAction.recycle();
8088                  enqueueInputEvent(fallbackEvent);
8089              }
8090          }
8091      }
8092  
8093      /**
8094       * Returns true if the key is used for keyboard navigation.
8095       * @param keyEvent The key event.
8096       * @return True if the key is used for keyboard navigation.
8097       */
isNavigationKey(KeyEvent keyEvent)8098      private static boolean isNavigationKey(KeyEvent keyEvent) {
8099          switch (keyEvent.getKeyCode()) {
8100          case KeyEvent.KEYCODE_DPAD_LEFT:
8101          case KeyEvent.KEYCODE_DPAD_RIGHT:
8102          case KeyEvent.KEYCODE_DPAD_UP:
8103          case KeyEvent.KEYCODE_DPAD_DOWN:
8104          case KeyEvent.KEYCODE_DPAD_CENTER:
8105          case KeyEvent.KEYCODE_PAGE_UP:
8106          case KeyEvent.KEYCODE_PAGE_DOWN:
8107          case KeyEvent.KEYCODE_MOVE_HOME:
8108          case KeyEvent.KEYCODE_MOVE_END:
8109          case KeyEvent.KEYCODE_TAB:
8110          case KeyEvent.KEYCODE_SPACE:
8111          case KeyEvent.KEYCODE_ENTER:
8112              return true;
8113          }
8114          return false;
8115      }
8116  
8117      /**
8118       * Returns true if the key is used for typing.
8119       * @param keyEvent The key event.
8120       * @return True if the key is used for typing.
8121       */
isTypingKey(KeyEvent keyEvent)8122      private static boolean isTypingKey(KeyEvent keyEvent) {
8123          return keyEvent.getUnicodeChar() > 0;
8124      }
8125  
8126      /**
8127       * See if the key event means we should leave touch mode (and leave touch mode if so).
8128       * @param event The key event.
8129       * @return Whether this key event should be consumed (meaning the act of
8130       *   leaving touch mode alone is considered the event).
8131       */
checkForLeavingTouchModeAndConsume(KeyEvent event)8132      private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
8133          // Only relevant in touch mode.
8134          if (!mAttachInfo.mInTouchMode) {
8135              return false;
8136          }
8137  
8138          // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
8139          final int action = event.getAction();
8140          if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
8141              return false;
8142          }
8143  
8144          // Don't leave touch mode if the IME told us not to.
8145          if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
8146              return false;
8147          }
8148  
8149          // If the key can be used for keyboard navigation then leave touch mode
8150          // and select a focused view if needed (in ensureTouchMode).
8151          // When a new focused view is selected, we consume the navigation key because
8152          // navigation doesn't make much sense unless a view already has focus so
8153          // the key's purpose is to set focus.
8154          if (event.hasNoModifiers() && isNavigationKey(event)) {
8155              return ensureTouchMode(false);
8156          }
8157  
8158          // If the key can be used for typing then leave touch mode
8159          // and select a focused view if needed (in ensureTouchMode).
8160          // Always allow the view to process the typing key.
8161          if (isTypingKey(event)) {
8162              ensureTouchMode(false);
8163              return false;
8164          }
8165  
8166          return false;
8167      }
8168  
8169      /* drag/drop */
8170      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setLocalDragState(Object obj)8171      void setLocalDragState(Object obj) {
8172          mLocalDragState = obj;
8173      }
8174  
handleDragEvent(DragEvent event)8175      private void handleDragEvent(DragEvent event) {
8176          // From the root, only drag start/end/location are dispatched.  entered/exited
8177          // are determined and dispatched by the viewgroup hierarchy, who then report
8178          // that back here for ultimate reporting back to the framework.
8179          if (mView != null && mAdded) {
8180              final int what = event.mAction;
8181  
8182              // Cache the drag description when the operation starts, then fill it in
8183              // on subsequent calls as a convenience
8184              if (what == DragEvent.ACTION_DRAG_STARTED) {
8185                  mCurrentDragView = null;    // Start the current-recipient tracking
8186                  mDragDescription = event.mClipDescription;
8187                  if (mStartedDragViewForA11y != null) {
8188                      // Send a drag started a11y event
8189                      mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
8190                              AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_STARTED);
8191                  }
8192              } else {
8193                  if (what == DragEvent.ACTION_DRAG_ENDED) {
8194                      mDragDescription = null;
8195                  }
8196                  event.mClipDescription = mDragDescription;
8197              }
8198  
8199              if (what == DragEvent.ACTION_DRAG_EXITED) {
8200                  // A direct EXITED event means that the window manager knows we've just crossed
8201                  // a window boundary, so the current drag target within this one must have
8202                  // just been exited. Send the EXITED notification to the current drag view, if any.
8203                  if (View.sCascadedDragDrop) {
8204                      mView.dispatchDragEnterExitInPreN(event);
8205                  }
8206                  setDragFocus(null, event);
8207              } else {
8208                  // For events with a [screen] location, translate into window coordinates
8209                  if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
8210                      mDragPoint.set(event.mX, event.mY);
8211                      if (mTranslator != null) {
8212                          mTranslator.translatePointInScreenToAppWindow(mDragPoint);
8213                      }
8214  
8215                      if (mCurScrollY != 0) {
8216                          mDragPoint.offset(0, mCurScrollY);
8217                      }
8218  
8219                      event.mX = mDragPoint.x;
8220                      event.mY = mDragPoint.y;
8221                  }
8222  
8223                  // Remember who the current drag target is pre-dispatch
8224                  final View prevDragView = mCurrentDragView;
8225  
8226                  if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
8227                      event.mClipData.prepareToEnterProcess(
8228                              mView.getContext().getAttributionSource());
8229                  }
8230  
8231                  // Now dispatch the drag/drop event
8232                  boolean result = mView.dispatchDragEvent(event);
8233  
8234                  if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
8235                      // If the LOCATION event wasn't delivered to any handler, no view now has a drag
8236                      // focus.
8237                      setDragFocus(null, event);
8238                  }
8239  
8240                  // If we changed apparent drag target, tell the OS about it
8241                  if (prevDragView != mCurrentDragView) {
8242                      try {
8243                          if (prevDragView != null) {
8244                              mWindowSession.dragRecipientExited(mWindow);
8245                          }
8246                          if (mCurrentDragView != null) {
8247                              mWindowSession.dragRecipientEntered(mWindow);
8248                          }
8249                      } catch (RemoteException e) {
8250                          Slog.e(mTag, "Unable to note drag target change");
8251                      }
8252                  }
8253  
8254                  // Report the drop result when we're done
8255                  if (what == DragEvent.ACTION_DROP) {
8256                      try {
8257                          Log.i(mTag, "Reporting drop result: " + result);
8258                          mWindowSession.reportDropResult(mWindow, result);
8259                      } catch (RemoteException e) {
8260                          Log.e(mTag, "Unable to report drop result");
8261                      }
8262                  }
8263  
8264                  // When the drag operation ends, reset drag-related state
8265                  if (what == DragEvent.ACTION_DRAG_ENDED) {
8266                      if (mStartedDragViewForA11y != null) {
8267                          // If the drag failed, send a cancelled event from the source. Otherwise,
8268                          // the View that accepted the drop sends CONTENT_CHANGE_TYPE_DRAG_DROPPED
8269                          if (!event.getResult()) {
8270                              mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
8271                                      AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_CANCELLED);
8272                          }
8273                          mStartedDragViewForA11y.setAccessibilityDragStarted(false);
8274                      }
8275                      mStartedDragViewForA11y = null;
8276                      mCurrentDragView = null;
8277                      setLocalDragState(null);
8278                      mAttachInfo.mDragToken = null;
8279                      if (mAttachInfo.mDragSurface != null) {
8280                          mAttachInfo.mDragSurface.release();
8281                          mAttachInfo.mDragSurface = null;
8282                      }
8283                  }
8284              }
8285          }
8286          event.recycle();
8287      }
8288  
8289      /**
8290       * Notify that the window title changed
8291       */
onWindowTitleChanged()8292      public void onWindowTitleChanged() {
8293          mAttachInfo.mForceReportNewAttributes = true;
8294      }
8295  
handleDispatchWindowShown()8296      public void handleDispatchWindowShown() {
8297          mAttachInfo.mTreeObserver.dispatchOnWindowShown();
8298      }
8299  
handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)8300      public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
8301          Bundle data = new Bundle();
8302          ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
8303          if (mView != null) {
8304              mView.requestKeyboardShortcuts(list, deviceId);
8305          }
8306          data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
8307          try {
8308              receiver.send(0, data);
8309          } catch (RemoteException e) {
8310          }
8311      }
8312  
8313      @UnsupportedAppUsage
getLastTouchPoint(Point outLocation)8314      public void getLastTouchPoint(Point outLocation) {
8315          outLocation.x = (int) mLastTouchPoint.x;
8316          outLocation.y = (int) mLastTouchPoint.y;
8317      }
8318  
getLastTouchSource()8319      public int getLastTouchSource() {
8320          return mLastTouchSource;
8321      }
8322  
8323      /**
8324       * Used by InputMethodManager.
8325       * @hide
8326       */
getLastClickToolType()8327      public int getLastClickToolType() {
8328          return mLastClickToolType;
8329      }
8330  
setDragFocus(View newDragTarget, DragEvent event)8331      public void setDragFocus(View newDragTarget, DragEvent event) {
8332          if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
8333              // Send EXITED and ENTERED notifications to the old and new drag focus views.
8334  
8335              final float tx = event.mX;
8336              final float ty = event.mY;
8337              final int action = event.mAction;
8338              final ClipData td = event.mClipData;
8339              // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
8340              event.mX = 0;
8341              event.mY = 0;
8342              event.mClipData = null;
8343  
8344              if (mCurrentDragView != null) {
8345                  event.mAction = DragEvent.ACTION_DRAG_EXITED;
8346                  mCurrentDragView.callDragEventHandler(event);
8347              }
8348  
8349              if (newDragTarget != null) {
8350                  event.mAction = DragEvent.ACTION_DRAG_ENTERED;
8351                  newDragTarget.callDragEventHandler(event);
8352              }
8353  
8354              event.mAction = action;
8355              event.mX = tx;
8356              event.mY = ty;
8357              event.mClipData = td;
8358          }
8359  
8360          mCurrentDragView = newDragTarget;
8361      }
8362  
8363      /** Sets the view that started drag and drop for the purpose of sending AccessibilityEvents */
setDragStartedViewForAccessibility(View view)8364      void setDragStartedViewForAccessibility(View view) {
8365          if (mStartedDragViewForA11y == null) {
8366              mStartedDragViewForA11y = view;
8367          }
8368      }
8369  
getAudioManager()8370      private AudioManager getAudioManager() {
8371          if (mView == null) {
8372              throw new IllegalStateException("getAudioManager called when there is no mView");
8373          }
8374          if (mAudioManager == null) {
8375              mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
8376              mFastScrollSoundEffectsEnabled = mAudioManager.areNavigationRepeatSoundEffectsEnabled();
8377          }
8378          return mAudioManager;
8379      }
8380  
getAutofillManager()8381      private @Nullable AutofillManager getAutofillManager() {
8382          if (mView instanceof ViewGroup) {
8383              ViewGroup decorView = (ViewGroup) mView;
8384              if (decorView.getChildCount() > 0) {
8385                  // We cannot use decorView's Context for querying AutofillManager: DecorView's
8386                  // context is based on Application Context, it would allocate a different
8387                  // AutofillManager instance.
8388                  return decorView.getChildAt(0).getContext()
8389                          .getSystemService(AutofillManager.class);
8390              }
8391          }
8392          return null;
8393      }
8394  
isAutofillUiShowing()8395      private boolean isAutofillUiShowing() {
8396          AutofillManager afm = getAutofillManager();
8397          if (afm == null) {
8398              return false;
8399          }
8400          return afm.isAutofillUiShowing();
8401      }
8402  
getAccessibilityInteractionController()8403      public AccessibilityInteractionController getAccessibilityInteractionController() {
8404          if (mView == null) {
8405              throw new IllegalStateException("getAccessibilityInteractionController"
8406                      + " called when there is no mView");
8407          }
8408          if (mAccessibilityInteractionController == null) {
8409              mAccessibilityInteractionController = new AccessibilityInteractionController(this);
8410          }
8411          return mAccessibilityInteractionController;
8412      }
8413  
relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending)8414      private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
8415              boolean insetsPending) throws RemoteException {
8416          final WindowConfiguration winConfigFromAm = getConfiguration().windowConfiguration;
8417          final WindowConfiguration winConfigFromWm =
8418                  mLastReportedMergedConfiguration.getGlobalConfiguration().windowConfiguration;
8419          final WindowConfiguration winConfig = getCompatWindowConfiguration();
8420          final int measuredWidth = mMeasuredWidth;
8421          final int measuredHeight = mMeasuredHeight;
8422          final boolean relayoutAsync;
8423          if (LOCAL_LAYOUT
8424                  && (mViewFrameInfo.flags & FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED) == 0
8425                  && mWindowAttributes.type != TYPE_APPLICATION_STARTING
8426                  && mSyncSeqId <= mLastSyncSeqId
8427                  && winConfigFromAm.diff(winConfigFromWm, false /* compareUndefined */) == 0) {
8428              final InsetsState state = mInsetsController.getState();
8429              final Rect displayCutoutSafe = mTempRect;
8430              state.getDisplayCutoutSafe(displayCutoutSafe);
8431              mWindowLayout.computeFrames(mWindowAttributes.forRotation(winConfig.getRotation()),
8432                      state, displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
8433                      measuredWidth, measuredHeight, mInsetsController.getRequestedVisibleTypes(),
8434                      1f /* compatScale */, mTmpFrames);
8435              mWinFrameInScreen.set(mTmpFrames.frame);
8436              if (mTranslator != null) {
8437                  mTranslator.translateRectInAppWindowToScreen(mWinFrameInScreen);
8438              }
8439  
8440              // If the position and the size of the frame are both changed, it will trigger a BLAST
8441              // sync, and we still need to call relayout to obtain the syncSeqId. Otherwise, we just
8442              // need to send attributes via relayoutAsync.
8443              final Rect oldFrame = mLastLayoutFrame;
8444              final Rect newFrame = mTmpFrames.frame;
8445              final boolean positionChanged =
8446                      newFrame.top != oldFrame.top || newFrame.left != oldFrame.left;
8447              final boolean sizeChanged =
8448                      newFrame.width() != oldFrame.width() || newFrame.height() != oldFrame.height();
8449              relayoutAsync = !positionChanged || !sizeChanged;
8450          } else {
8451              relayoutAsync = false;
8452          }
8453  
8454          float appScale = mAttachInfo.mApplicationScale;
8455          boolean restore = false;
8456          if (params != null && mTranslator != null) {
8457              restore = true;
8458              params.backup();
8459              mTranslator.translateWindowLayout(params);
8460          }
8461  
8462          if (params != null) {
8463              if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
8464  
8465              if (mOrigWindowType != params.type) {
8466                  // For compatibility with old apps, don't crash here.
8467                  if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
8468                      Slog.w(mTag, "Window type can not be changed after "
8469                              + "the window is added; ignoring change of " + mView);
8470                      params.type = mOrigWindowType;
8471                  }
8472              }
8473          }
8474  
8475          final int requestedWidth = (int) (measuredWidth * appScale + 0.5f);
8476          final int requestedHeight = (int) (measuredHeight * appScale + 0.5f);
8477          int relayoutResult = 0;
8478          mRelayoutSeq++;
8479          if (relayoutAsync) {
8480              mWindowSession.relayoutAsync(mWindow, params,
8481                      requestedWidth, requestedHeight, viewVisibility,
8482                      insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
8483                      mLastSyncSeqId);
8484          } else {
8485              relayoutResult = mWindowSession.relayout(mWindow, params,
8486                      requestedWidth, requestedHeight, viewVisibility,
8487                      insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
8488                      mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
8489                      mTempInsets, mTempControls, mRelayoutBundle);
8490              mRelayoutRequested = true;
8491  
8492              final int maybeSyncSeqId = mRelayoutBundle.getInt("seqid");
8493              if (maybeSyncSeqId > 0) {
8494                  mSyncSeqId = maybeSyncSeqId;
8495              }
8496              mWinFrameInScreen.set(mTmpFrames.frame);
8497              if (mTranslator != null) {
8498                  mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
8499                  mTranslator.translateRectInScreenToAppWindow(mTmpFrames.displayFrame);
8500                  mTranslator.translateRectInScreenToAppWindow(mTmpFrames.attachedFrame);
8501                  mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
8502                  mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls.get());
8503              }
8504              mInvCompatScale = 1f / mTmpFrames.compatScale;
8505              CompatibilityInfo.applyOverrideScaleIfNeeded(mPendingMergedConfiguration);
8506              mInsetsController.onStateChanged(mTempInsets);
8507              mInsetsController.onControlsChanged(mTempControls.get());
8508  
8509              mPendingAlwaysConsumeSystemBars =
8510                      (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
8511          }
8512  
8513          final int transformHint = SurfaceControl.rotationToBufferTransform(
8514                  (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4);
8515  
8516          WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth,
8517                  requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize);
8518  
8519          final boolean transformHintChanged = transformHint != mLastTransformHint;
8520          final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize);
8521          final boolean surfaceControlChanged =
8522                  (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) == RELAYOUT_RES_SURFACE_CHANGED;
8523          if (mAttachInfo.mThreadedRenderer != null &&
8524                  (transformHintChanged || sizeChanged || surfaceControlChanged)) {
8525              if (mAttachInfo.mThreadedRenderer.pause()) {
8526                  // Animations were running so we need to push a frame
8527                  // to resume them
8528                  mDirty.set(0, 0, mWidth, mHeight);
8529              }
8530          }
8531  
8532          if (mSurfaceControl.isValid() && !HardwareRenderer.isDrawingEnabled()) {
8533              // When drawing is disabled the window layer won't have a valid buffer.
8534              // Set a window crop so input can get delivered to the window.
8535              mTransaction.setWindowCrop(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y).apply();
8536          }
8537  
8538          mLastTransformHint = transformHint;
8539  
8540          mSurfaceControl.setTransformHint(transformHint);
8541  
8542          if (mAttachInfo.mContentCaptureManager != null) {
8543              MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
8544                      .getMainContentCaptureSession();
8545              mainSession.notifyWindowBoundsChanged(mainSession.getId(),
8546                      getConfiguration().windowConfiguration.getBounds());
8547          }
8548  
8549          if (mSurfaceControl.isValid()) {
8550              if (!useBLAST()) {
8551                  mSurface.copyFrom(mSurfaceControl);
8552              } else {
8553                  updateBlastSurfaceIfNeeded();
8554              }
8555              if (mAttachInfo.mThreadedRenderer != null) {
8556                  mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
8557              }
8558              updateRenderHdrSdrRatio();
8559              if (mPreviousTransformHint != transformHint) {
8560                  mPreviousTransformHint = transformHint;
8561                  dispatchTransformHintChanged(transformHint);
8562              }
8563          } else {
8564              if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.pause()) {
8565                  mDirty.set(0, 0, mWidth, mHeight);
8566              }
8567              destroySurface();
8568          }
8569  
8570          if (restore) {
8571              params.restore();
8572          }
8573  
8574          setFrame(mTmpFrames.frame, true /* withinRelayout */);
8575          return relayoutResult;
8576      }
8577  
updateOpacity(WindowManager.LayoutParams params, boolean dragResizing, boolean forceUpdate)8578      private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing,
8579              boolean forceUpdate) {
8580          boolean opaque = false;
8581  
8582          if (!PixelFormat.formatHasAlpha(params.format)
8583                  // Don't make surface with surfaceInsets opaque as they display a
8584                  // translucent shadow.
8585                  && params.surfaceInsets.left == 0
8586                  && params.surfaceInsets.top == 0
8587                  && params.surfaceInsets.right == 0
8588                  && params.surfaceInsets.bottom == 0
8589                  // Don't make surface opaque when resizing to reduce the amount of
8590                  // artifacts shown in areas the app isn't drawing content to.
8591                  && !dragResizing) {
8592              opaque = true;
8593          }
8594  
8595          if (!forceUpdate && mIsSurfaceOpaque == opaque) {
8596              return;
8597          }
8598  
8599          final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
8600          if (renderer != null && renderer.rendererOwnsSurfaceControlOpacity()) {
8601              opaque = renderer.setSurfaceControlOpaque(opaque);
8602          } else {
8603              mTransaction.setOpaque(mSurfaceControl, opaque).apply();
8604          }
8605  
8606          mIsSurfaceOpaque = opaque;
8607      }
8608  
8609      /**
8610       * Set the mWinFrame of this window.
8611       * @param frame the new frame of this window.
8612       * @param withinRelayout {@code true} if this setting is within the relayout, or is the initial
8613       *                       setting. That will make sure in the relayout process, we always compare
8614       *                       the window frame with the last processed window frame.
8615       */
setFrame(Rect frame, boolean withinRelayout)8616      private void setFrame(Rect frame, boolean withinRelayout) {
8617          mWinFrame.set(frame);
8618          if (withinRelayout) {
8619              mLastLayoutFrame.set(frame);
8620          }
8621  
8622          final WindowConfiguration winConfig = getCompatWindowConfiguration();
8623          mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop()
8624                  ? winConfig.getMaxBounds()
8625                  : frame);
8626          // Surface position is now inherited from parent, and BackdropFrameRenderer uses backdrop
8627          // frame to position content. Thus, we just keep the size of backdrop frame, and remove the
8628          // offset to avoid double offset from display origin.
8629          mPendingBackDropFrame.offsetTo(0, 0);
8630  
8631          mInsetsController.onFrameChanged(mOverrideInsetsFrame != null ?
8632                  mOverrideInsetsFrame : frame);
8633      }
8634  
8635      /**
8636       * In the normal course of operations we compute insets relative to
8637       * the frame returned from relayout window. In the case of
8638       * SurfaceControlViewHost, this frame is in local coordinates
8639       * instead of global coordinates. We support this override
8640       * frame so we can allow SurfaceControlViewHost to set a frame
8641       * to be used to calculate insets, without disturbing the main
8642       * mFrame.
8643       */
setOverrideInsetsFrame(Rect frame)8644      void setOverrideInsetsFrame(Rect frame) {
8645          mOverrideInsetsFrame = new Rect(frame);
8646          mInsetsController.onFrameChanged(mOverrideInsetsFrame);
8647      }
8648  
8649      /**
8650       * Gets the current display size in which the window is being laid out, accounting for screen
8651       * decorations around it.
8652       */
getDisplayFrame(Rect outFrame)8653      void getDisplayFrame(Rect outFrame) {
8654          outFrame.set(mTmpFrames.displayFrame);
8655          // Apply sandboxing here (in getter) due to possible layout updates on the client after
8656          // mTmpFrames.displayFrame is received from the server.
8657          applyViewBoundsSandboxingIfNeeded(outFrame);
8658      }
8659  
8660      /**
8661       * Gets the current display size in which the window is being laid out, accounting for screen
8662       * decorations around it.
8663       */
getWindowVisibleDisplayFrame(Rect outFrame)8664      void getWindowVisibleDisplayFrame(Rect outFrame) {
8665          outFrame.set(mTmpFrames.displayFrame);
8666          // XXX This is really broken, and probably all needs to be done
8667          // in the window manager, and we need to know more about whether
8668          // we want the area behind or in front of the IME.
8669          final Rect insets = mAttachInfo.mVisibleInsets;
8670          outFrame.left += insets.left;
8671          outFrame.top += insets.top;
8672          outFrame.right -= insets.right;
8673          outFrame.bottom -= insets.bottom;
8674          // Apply sandboxing here (in getter) due to possible layout updates on the client after
8675          // mTmpFrames.displayFrame is received from the server.
8676          applyViewBoundsSandboxingIfNeeded(outFrame);
8677      }
8678  
8679      /**
8680       * Offset outRect to make it sandboxed within Window's bounds.
8681       *
8682       * <p>This is used by {@link android.view.View#getBoundsOnScreen},
8683       * {@link android.view.ViewRootImpl#getDisplayFrame} and
8684       * {@link android.view.ViewRootImpl#getWindowVisibleDisplayFrame}, which are invoked by
8685       * {@link android.view.View#getWindowDisplayFrame} and
8686       * {@link android.view.View#getWindowVisibleDisplayFrame}, as well as
8687       * {@link android.view.ViewDebug#captureLayers} for debugging.
8688       */
applyViewBoundsSandboxingIfNeeded(final Rect inOutRect)8689      void applyViewBoundsSandboxingIfNeeded(final Rect inOutRect) {
8690          if (mViewBoundsSandboxingEnabled) {
8691              final Rect bounds = getConfiguration().windowConfiguration.getBounds();
8692              inOutRect.offset(-bounds.left, -bounds.top);
8693          }
8694      }
8695  
8696      /**
8697       * Offset outLocation to make it sandboxed within Window's bounds.
8698       *
8699       * <p>This is used by {@link android.view.View#getLocationOnScreen(int[])}
8700       */
applyViewLocationSandboxingIfNeeded(@ize2) int[] outLocation)8701      public void applyViewLocationSandboxingIfNeeded(@Size(2) int[] outLocation) {
8702          if (mViewBoundsSandboxingEnabled) {
8703              final Rect bounds = getConfiguration().windowConfiguration.getBounds();
8704              outLocation[0] -= bounds.left;
8705              outLocation[1] -= bounds.top;
8706          }
8707      }
8708  
getViewBoundsSandboxingEnabled()8709      private boolean getViewBoundsSandboxingEnabled() {
8710          // System dialogs (e.g. ANR) can be created within System process, so handleBindApplication
8711          // may be never called. This results into all app compat changes being enabled
8712          // (see b/268007823) because AppCompatCallbacks.install() is never called with non-empty
8713          // array.
8714          // With ActivityThread.isSystem we verify that it is not the system process,
8715          // then this CompatChange can take effect.
8716          if (ActivityThread.isSystem()
8717                  || !CompatChanges.isChangeEnabled(OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS)) {
8718              // It is a system process or OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS change-id is disabled.
8719              return false;
8720          }
8721  
8722          // OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS is enabled by the device manufacturer.
8723          try {
8724              final List<PackageManager.Property> properties = mContext.getPackageManager()
8725                      .queryApplicationProperty(PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS);
8726  
8727              final boolean isOptedOut = !properties.isEmpty() && !properties.get(0).getBoolean();
8728              if (isOptedOut) {
8729                  // PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS is disabled by the app devs.
8730                  return false;
8731              }
8732          } catch (RuntimeException e) {
8733              // remote exception.
8734          }
8735  
8736          return true;
8737      }
8738  
8739      /**
8740       * {@inheritDoc}
8741       */
8742      @Override
playSoundEffect(@oundEffectConstants.SoundEffect int effectId)8743      public void playSoundEffect(@SoundEffectConstants.SoundEffect int effectId) {
8744          if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
8745              return;
8746          }
8747  
8748          checkThread();
8749  
8750          try {
8751              final AudioManager audioManager = getAudioManager();
8752  
8753              if (mFastScrollSoundEffectsEnabled
8754                      && SoundEffectConstants.isNavigationRepeat(effectId)) {
8755                  audioManager.playSoundEffect(
8756                          SoundEffectConstants.nextNavigationRepeatSoundEffectId());
8757                  return;
8758              }
8759  
8760              switch (effectId) {
8761                  case SoundEffectConstants.CLICK:
8762                      audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
8763                      return;
8764                  case SoundEffectConstants.NAVIGATION_DOWN:
8765                  case SoundEffectConstants.NAVIGATION_REPEAT_DOWN:
8766                      audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
8767                      return;
8768                  case SoundEffectConstants.NAVIGATION_LEFT:
8769                  case SoundEffectConstants.NAVIGATION_REPEAT_LEFT:
8770                      audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
8771                      return;
8772                  case SoundEffectConstants.NAVIGATION_RIGHT:
8773                  case SoundEffectConstants.NAVIGATION_REPEAT_RIGHT:
8774                      audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
8775                      return;
8776                  case SoundEffectConstants.NAVIGATION_UP:
8777                  case SoundEffectConstants.NAVIGATION_REPEAT_UP:
8778                      audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
8779                      return;
8780                  default:
8781                      throw new IllegalArgumentException("unknown effect id " + effectId +
8782                              " not defined in " + SoundEffectConstants.class.getCanonicalName());
8783              }
8784          } catch (IllegalStateException e) {
8785              // Exception thrown by getAudioManager() when mView is null
8786              Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
8787              e.printStackTrace();
8788          }
8789      }
8790  
8791      /**
8792       * {@inheritDoc}
8793       */
8794      @Override
performHapticFeedback(int effectId, boolean always)8795      public boolean performHapticFeedback(int effectId, boolean always) {
8796          if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
8797              return false;
8798          }
8799  
8800          try {
8801              if (USE_ASYNC_PERFORM_HAPTIC_FEEDBACK) {
8802                  mWindowSession.performHapticFeedbackAsync(effectId, always);
8803                  return true;
8804              } else {
8805                  // Original blocking binder call path.
8806                  return mWindowSession.performHapticFeedback(effectId, always);
8807              }
8808          } catch (RemoteException e) {
8809              return false;
8810          }
8811      }
8812  
8813      /**
8814       * {@inheritDoc}
8815       */
8816      @Override
focusSearch(View focused, int direction)8817      public View focusSearch(View focused, int direction) {
8818          checkThread();
8819          if (!(mView instanceof ViewGroup)) {
8820              return null;
8821          }
8822          return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
8823      }
8824  
8825      /**
8826       * {@inheritDoc}
8827       */
8828      @Override
keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)8829      public View keyboardNavigationClusterSearch(View currentCluster,
8830              @FocusDirection int direction) {
8831          checkThread();
8832          return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
8833                  mView, currentCluster, direction);
8834      }
8835  
debug()8836      public void debug() {
8837          mView.debug();
8838      }
8839  
8840      /**
8841       * Export the state of {@link ViewRootImpl} and other relevant classes into a protocol buffer
8842       * output stream.
8843       *
8844       * @param proto Stream to write the state to
8845       * @param fieldId FieldId of ViewRootImpl as defined in the parent message
8846       */
8847      @GuardedBy("this")
dumpDebug(ProtoOutputStream proto, long fieldId)8848      public void dumpDebug(ProtoOutputStream proto, long fieldId) {
8849          final long token = proto.start(fieldId);
8850          proto.write(VIEW, Objects.toString(mView));
8851          proto.write(DISPLAY_ID, mDisplay.getDisplayId());
8852          proto.write(APP_VISIBLE, mAppVisible);
8853          proto.write(HEIGHT, mHeight);
8854          proto.write(WIDTH, mWidth);
8855          proto.write(IS_ANIMATING, mIsAnimating);
8856          mVisRect.dumpDebug(proto, VISIBLE_RECT);
8857          proto.write(IS_DRAWING, mIsDrawing);
8858          proto.write(ADDED, mAdded);
8859          mWinFrame.dumpDebug(proto, WIN_FRAME);
8860          proto.write(LAST_WINDOW_INSETS, Objects.toString(mLastWindowInsets));
8861          proto.write(SOFT_INPUT_MODE, InputMethodDebug.softInputModeToString(mSoftInputMode));
8862          proto.write(SCROLL_Y, mScrollY);
8863          proto.write(CUR_SCROLL_Y, mCurScrollY);
8864          proto.write(REMOVED, mRemoved);
8865          mWindowAttributes.dumpDebug(proto, WINDOW_ATTRIBUTES);
8866          proto.end(token);
8867          mInsetsController.dumpDebug(proto, INSETS_CONTROLLER);
8868          mImeFocusController.dumpDebug(proto, IME_FOCUS_CONTROLLER);
8869      }
8870  
8871      /**
8872       * Dump information about this ViewRootImpl
8873       * @param prefix the prefix that will be prepended to each line of the produced output
8874       * @param writer the writer that will receive the resulting text
8875       */
dump(String prefix, PrintWriter writer)8876      public void dump(String prefix, PrintWriter writer) {
8877          String innerPrefix = prefix + "  ";
8878          writer.println(prefix + "ViewRoot:");
8879          writer.println(innerPrefix + "mAdded=" + mAdded);
8880          writer.println(innerPrefix + "mRemoved=" + mRemoved);
8881          writer.println(innerPrefix + "mStopped=" + mStopped);
8882          writer.println(innerPrefix + "mPausedForTransition=" + mPausedForTransition);
8883          writer.println(innerPrefix + "mConsumeBatchedInputScheduled="
8884                  + mConsumeBatchedInputScheduled);
8885          writer.println(innerPrefix + "mConsumeBatchedInputImmediatelyScheduled="
8886                  + mConsumeBatchedInputImmediatelyScheduled);
8887          writer.println(innerPrefix + "mPendingInputEventCount=" + mPendingInputEventCount);
8888          writer.println(innerPrefix + "mProcessInputEventsScheduled="
8889                  + mProcessInputEventsScheduled);
8890          writer.println(innerPrefix + "mTraversalScheduled=" + mTraversalScheduled);
8891          if (mTraversalScheduled) {
8892              writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")");
8893          }
8894          writer.println(innerPrefix + "mReportNextDraw=" + mReportNextDraw);
8895          if (mReportNextDraw) {
8896              writer.println(innerPrefix + " (reason=" + mLastReportNextDrawReason + ")");
8897          }
8898          if (mLastPerformTraversalsSkipDrawReason != null) {
8899              writer.println(innerPrefix + "mLastPerformTraversalsFailedReason="
8900                  + mLastPerformTraversalsSkipDrawReason);
8901          }
8902          if (mLastPerformDrawSkippedReason != null) {
8903              writer.println(innerPrefix + "mLastPerformDrawFailedReason="
8904                  + mLastPerformDrawSkippedReason);
8905          }
8906          if (mWmsRequestSyncGroupState != WMS_SYNC_NONE) {
8907              writer.println(innerPrefix + "mWmsRequestSyncGroupState=" + mWmsRequestSyncGroupState);
8908          }
8909          writer.println(innerPrefix + "mLastReportedMergedConfiguration="
8910                  + mLastReportedMergedConfiguration);
8911          writer.println(innerPrefix + "mLastConfigurationFromResources="
8912                  + mLastConfigurationFromResources);
8913          writer.println(innerPrefix + "mIsAmbientMode="  + mIsAmbientMode);
8914          writer.println(innerPrefix + "mUnbufferedInputSource="
8915                  + Integer.toHexString(mUnbufferedInputSource));
8916          if (mAttachInfo != null) {
8917              writer.print(innerPrefix + "mAttachInfo= ");
8918              mAttachInfo.dump(innerPrefix, writer);
8919          } else {
8920              writer.println(innerPrefix + "mAttachInfo=<null>");
8921          }
8922  
8923          mFirstInputStage.dump(innerPrefix, writer);
8924  
8925          if (mInputEventReceiver != null) {
8926              mInputEventReceiver.dump(innerPrefix, writer);
8927          }
8928  
8929          mChoreographer.dump(prefix, writer);
8930  
8931          mInsetsController.dump(prefix, writer);
8932  
8933          mOnBackInvokedDispatcher.dump(prefix, writer);
8934  
8935          writer.println(prefix + "View Hierarchy:");
8936          dumpViewHierarchy(innerPrefix, writer, mView);
8937      }
8938  
dumpViewHierarchy(String prefix, PrintWriter writer, View view)8939      private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
8940          writer.print(prefix);
8941          if (view == null) {
8942              writer.println("null");
8943              return;
8944          }
8945          writer.println(view.toString());
8946          if (!(view instanceof ViewGroup)) {
8947              return;
8948          }
8949          ViewGroup grp = (ViewGroup)view;
8950          final int N = grp.getChildCount();
8951          if (N <= 0) {
8952              return;
8953          }
8954          prefix = prefix + "  ";
8955          for (int i=0; i<N; i++) {
8956              dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
8957          }
8958      }
8959  
8960      static final class GfxInfo {
8961          public int viewCount;
8962          public long renderNodeMemoryUsage;
8963          public long renderNodeMemoryAllocated;
8964  
add(GfxInfo other)8965          void add(GfxInfo other) {
8966              viewCount += other.viewCount;
8967              renderNodeMemoryUsage += other.renderNodeMemoryUsage;
8968              renderNodeMemoryAllocated += other.renderNodeMemoryAllocated;
8969          }
8970      }
8971  
getGfxInfo()8972      GfxInfo getGfxInfo() {
8973          GfxInfo info = new GfxInfo();
8974          if (mView != null) {
8975              appendGfxInfo(mView, info);
8976          }
8977          return info;
8978      }
8979  
computeRenderNodeUsage(RenderNode node, GfxInfo info)8980      private static void computeRenderNodeUsage(RenderNode node, GfxInfo info) {
8981          if (node == null) return;
8982          info.renderNodeMemoryUsage += node.computeApproximateMemoryUsage();
8983          info.renderNodeMemoryAllocated += node.computeApproximateMemoryAllocated();
8984      }
8985  
appendGfxInfo(View view, GfxInfo info)8986      private static void appendGfxInfo(View view, GfxInfo info) {
8987          info.viewCount++;
8988          computeRenderNodeUsage(view.mRenderNode, info);
8989          computeRenderNodeUsage(view.mBackgroundRenderNode, info);
8990          if (view instanceof ViewGroup) {
8991              ViewGroup group = (ViewGroup) view;
8992  
8993              int count = group.getChildCount();
8994              for (int i = 0; i < count; i++) {
8995                  appendGfxInfo(group.getChildAt(i), info);
8996              }
8997          }
8998      }
8999  
9000      /**
9001       * @param immediate True, do now if not in traversal. False, put on queue and do later.
9002       * @return True, request has been queued. False, request has been completed.
9003       */
die(boolean immediate)9004      boolean die(boolean immediate) {
9005          // Make sure we do execute immediately if we are in the middle of a traversal or the damage
9006          // done by dispatchDetachedFromWindow will cause havoc on return.
9007          if (immediate && !mIsInTraversal) {
9008              doDie();
9009              return false;
9010          }
9011  
9012          if (!mIsDrawing) {
9013              destroyHardwareRenderer();
9014          } else {
9015              Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
9016                      "  window=" + this + ", title=" + mWindowAttributes.getTitle());
9017          }
9018          mHandler.sendEmptyMessage(MSG_DIE);
9019          return true;
9020      }
9021  
doDie()9022      void doDie() {
9023          checkThread();
9024          if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
9025          synchronized (this) {
9026              if (mRemoved) {
9027                  return;
9028              }
9029              mRemoved = true;
9030              mOnBackInvokedDispatcher.detachFromWindow();
9031              if (mAdded) {
9032                  dispatchDetachedFromWindow();
9033              }
9034  
9035              if (mAdded && !mFirst) {
9036                  destroyHardwareRenderer();
9037  
9038                  if (mView != null) {
9039                      int viewVisibility = mView.getVisibility();
9040                      boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
9041                      if (mWindowAttributesChanged || viewVisibilityChanged) {
9042                          // If layout params have been changed, first give them
9043                          // to the window manager to make sure it has the correct
9044                          // animation info.
9045                          try {
9046                              if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
9047                                      & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
9048                                  mWindowSession.finishDrawing(
9049                                      mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
9050                              }
9051                          } catch (RemoteException e) {
9052                          }
9053                      }
9054  
9055                      destroySurface();
9056                  }
9057              }
9058  
9059              // If our window is removed, we might not get notified about losing control.
9060              // Invoking this can release the leashes as soon as possible instead of relying on GC.
9061              mInsetsController.onControlsChanged(null);
9062  
9063              mAdded = false;
9064              AnimationHandler.removeRequestor(this);
9065          }
9066          if (mActiveSurfaceSyncGroup != null) {
9067              mActiveSurfaceSyncGroup.markSyncReady();
9068              mActiveSurfaceSyncGroup = null;
9069          }
9070          if (mHasPendingTransactions) {
9071              mPendingTransaction.apply();
9072          }
9073          WindowManagerGlobal.getInstance().doRemoveView(this);
9074      }
9075  
requestUpdateConfiguration(Configuration config)9076      public void requestUpdateConfiguration(Configuration config) {
9077          Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
9078          mHandler.sendMessage(msg);
9079      }
9080  
loadSystemProperties()9081      public void loadSystemProperties() {
9082          mHandler.post(new Runnable() {
9083              @Override
9084              public void run() {
9085                  // Profiling
9086                  mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
9087                  profileRendering(mAttachInfo.mHasWindowFocus);
9088  
9089                  // Hardware rendering
9090                  if (mAttachInfo.mThreadedRenderer != null) {
9091                      if (mAttachInfo.mThreadedRenderer.loadSystemProperties()) {
9092                          invalidate();
9093                      }
9094                  }
9095  
9096                  // Layout debugging
9097                  boolean layout = DisplayProperties.debug_layout().orElse(false);
9098                  if (layout != mAttachInfo.mDebugLayout) {
9099                      mAttachInfo.mDebugLayout = layout;
9100                      if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
9101                          mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
9102                      }
9103                  }
9104              }
9105          });
9106      }
9107  
destroyHardwareRenderer()9108      private void destroyHardwareRenderer() {
9109          ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
9110  
9111          if (mHdrSdrRatioChangedListener != null) {
9112              mDisplay.unregisterHdrSdrRatioChangedListener(mHdrSdrRatioChangedListener);
9113          }
9114  
9115          if (hardwareRenderer != null) {
9116              if (mHardwareRendererObserver != null) {
9117                  hardwareRenderer.removeObserver(mHardwareRendererObserver);
9118              }
9119              if (mView != null) {
9120                  hardwareRenderer.destroyHardwareResources(mView);
9121              }
9122              hardwareRenderer.destroy();
9123              hardwareRenderer.setRequested(false);
9124  
9125              mAttachInfo.mThreadedRenderer = null;
9126              mAttachInfo.mHardwareAccelerated = false;
9127          }
9128      }
9129  
9130      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
dispatchResized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing)9131      private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
9132              MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
9133              boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing) {
9134          Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
9135          SomeArgs args = SomeArgs.obtain();
9136          final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
9137          if (sameProcessCall) {
9138              insetsState = new InsetsState(insetsState, true /* copySource */);
9139          }
9140          if (mTranslator != null) {
9141              mTranslator.translateInsetsStateInScreenToAppWindow(insetsState);
9142          }
9143          if (insetsState.isSourceOrDefaultVisible(ID_IME, Type.ime())) {
9144              ImeTracing.getInstance().triggerClientDump("ViewRootImpl#dispatchResized",
9145                      getInsetsController().getHost().getInputMethodManager(), null /* icProto */);
9146          }
9147          args.arg1 = sameProcessCall ? new ClientWindowFrames(frames) : frames;
9148          args.arg2 = sameProcessCall && mergedConfiguration != null
9149                  ? new MergedConfiguration(mergedConfiguration) : mergedConfiguration;
9150          args.arg3 = insetsState;
9151          args.argi1 = forceLayout ? 1 : 0;
9152          args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
9153          args.argi3 = displayId;
9154          args.argi4 = syncSeqId;
9155          args.argi5 = dragResizing ? 1 : 0;
9156  
9157          msg.obj = args;
9158          mHandler.sendMessage(msg);
9159      }
9160  
dispatchInsetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)9161      private void dispatchInsetsControlChanged(InsetsState insetsState,
9162              InsetsSourceControl[] activeControls) {
9163          if (Binder.getCallingPid() == android.os.Process.myPid()) {
9164              insetsState = new InsetsState(insetsState, true /* copySource */);
9165              if (activeControls != null) {
9166                  for (int i = activeControls.length - 1; i >= 0; i--) {
9167                      activeControls[i] = new InsetsSourceControl(activeControls[i]);
9168                  }
9169              }
9170          }
9171          if (mTranslator != null) {
9172              mTranslator.translateInsetsStateInScreenToAppWindow(insetsState);
9173              mTranslator.translateSourceControlsInScreenToAppWindow(activeControls);
9174          }
9175          if (insetsState != null && insetsState.isSourceOrDefaultVisible(ID_IME, Type.ime())) {
9176              ImeTracing.getInstance().triggerClientDump("ViewRootImpl#dispatchInsetsControlChanged",
9177                      getInsetsController().getHost().getInputMethodManager(), null /* icProto */);
9178          }
9179          SomeArgs args = SomeArgs.obtain();
9180          args.arg1 = insetsState;
9181          args.arg2 = activeControls;
9182          mHandler.obtainMessage(MSG_INSETS_CONTROL_CHANGED, args).sendToTarget();
9183      }
9184  
showInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)9185      private void showInsets(@InsetsType int types, boolean fromIme,
9186              @Nullable ImeTracker.Token statsToken) {
9187          mHandler.obtainMessage(MSG_SHOW_INSETS, types, fromIme ? 1 : 0, statsToken).sendToTarget();
9188      }
9189  
hideInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)9190      private void hideInsets(@InsetsType int types, boolean fromIme,
9191              @Nullable ImeTracker.Token statsToken) {
9192          mHandler.obtainMessage(MSG_HIDE_INSETS, types, fromIme ? 1 : 0, statsToken).sendToTarget();
9193      }
9194  
dispatchMoved(int newX, int newY)9195      public void dispatchMoved(int newX, int newY) {
9196          if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
9197          if (mTranslator != null) {
9198              PointF point = new PointF(newX, newY);
9199              mTranslator.translatePointInScreenToAppWindow(point);
9200              newX = (int) (point.x + 0.5);
9201              newY = (int) (point.y + 0.5);
9202          }
9203          Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
9204          mHandler.sendMessage(msg);
9205      }
9206  
9207      /**
9208       * Represents a pending input event that is waiting in a queue.
9209       *
9210       * Input events are processed in serial order by the timestamp specified by
9211       * {@link InputEvent#getEventTimeNanos()}.  In general, the input dispatcher delivers
9212       * one input event to the application at a time and waits for the application
9213       * to finish handling it before delivering the next one.
9214       *
9215       * However, because the application or IME can synthesize and inject multiple
9216       * key events at a time without going through the input dispatcher, we end up
9217       * needing a queue on the application's side.
9218       */
9219      private static final class QueuedInputEvent {
9220          public static final int FLAG_DELIVER_POST_IME = 1 << 0;
9221          public static final int FLAG_DEFERRED = 1 << 1;
9222          public static final int FLAG_FINISHED = 1 << 2;
9223          public static final int FLAG_FINISHED_HANDLED = 1 << 3;
9224          public static final int FLAG_RESYNTHESIZED = 1 << 4;
9225          public static final int FLAG_UNHANDLED = 1 << 5;
9226          public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6;
9227  
9228          public QueuedInputEvent mNext;
9229  
9230          public InputEvent mEvent;
9231          public InputEventReceiver mReceiver;
9232          public int mFlags;
9233  
shouldSkipIme()9234          public boolean shouldSkipIme() {
9235              if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
9236                  return true;
9237              }
9238              return mEvent instanceof MotionEvent
9239                      && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
9240                          || mEvent.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER));
9241          }
9242  
shouldSendToSynthesizer()9243          public boolean shouldSendToSynthesizer() {
9244              if ((mFlags & FLAG_UNHANDLED) != 0) {
9245                  return true;
9246              }
9247  
9248              return false;
9249          }
9250  
9251          @Override
toString()9252          public String toString() {
9253              StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
9254              boolean hasPrevious = false;
9255              hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
9256              hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
9257              hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
9258              hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
9259              hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
9260              hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
9261              if (!hasPrevious) {
9262                  sb.append("0");
9263              }
9264              sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
9265              sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
9266              sb.append(", mEvent=" + mEvent + "}");
9267              return sb.toString();
9268          }
9269  
flagToString(String name, int flag, boolean hasPrevious, StringBuilder sb)9270          private boolean flagToString(String name, int flag,
9271                  boolean hasPrevious, StringBuilder sb) {
9272              if ((mFlags & flag) != 0) {
9273                  if (hasPrevious) {
9274                      sb.append("|");
9275                  }
9276                  sb.append(name);
9277                  return true;
9278              }
9279              return hasPrevious;
9280          }
9281      }
9282  
obtainQueuedInputEvent(InputEvent event, InputEventReceiver receiver, int flags)9283      private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
9284              InputEventReceiver receiver, int flags) {
9285          QueuedInputEvent q = mQueuedInputEventPool;
9286          if (q != null) {
9287              mQueuedInputEventPoolSize -= 1;
9288              mQueuedInputEventPool = q.mNext;
9289              q.mNext = null;
9290          } else {
9291              q = new QueuedInputEvent();
9292          }
9293  
9294          q.mEvent = event;
9295          q.mReceiver = receiver;
9296          q.mFlags = flags;
9297          return q;
9298      }
9299  
recycleQueuedInputEvent(QueuedInputEvent q)9300      private void recycleQueuedInputEvent(QueuedInputEvent q) {
9301          q.mEvent = null;
9302          q.mReceiver = null;
9303  
9304          if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
9305              mQueuedInputEventPoolSize += 1;
9306              q.mNext = mQueuedInputEventPool;
9307              mQueuedInputEventPool = q;
9308          }
9309      }
9310  
9311      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
enqueueInputEvent(InputEvent event)9312      public void enqueueInputEvent(InputEvent event) {
9313          enqueueInputEvent(event, null, 0, false);
9314      }
9315  
9316      @UnsupportedAppUsage
enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately)9317      void enqueueInputEvent(InputEvent event,
9318              InputEventReceiver receiver, int flags, boolean processImmediately) {
9319          QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
9320  
9321          if (event instanceof MotionEvent) {
9322              MotionEvent me = (MotionEvent) event;
9323              if (me.getAction() == MotionEvent.ACTION_CANCEL) {
9324                  EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Motion - Cancel",
9325                          getTitle().toString());
9326              }
9327          } else if (event instanceof KeyEvent) {
9328              KeyEvent ke = (KeyEvent) event;
9329              if (ke.isCanceled()) {
9330                  EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Key - Cancel",
9331                          getTitle().toString());
9332              }
9333          }
9334          // Always enqueue the input event in order, regardless of its time stamp.
9335          // We do this because the application or the IME may inject key events
9336          // in response to touch events and we want to ensure that the injected keys
9337          // are processed in the order they were received and we cannot trust that
9338          // the time stamp of injected events are monotonic.
9339          QueuedInputEvent last = mPendingInputEventTail;
9340          if (last == null) {
9341              mPendingInputEventHead = q;
9342              mPendingInputEventTail = q;
9343          } else {
9344              last.mNext = q;
9345              mPendingInputEventTail = q;
9346          }
9347          mPendingInputEventCount += 1;
9348          Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
9349                  mPendingInputEventCount);
9350  
9351          if (processImmediately) {
9352              doProcessInputEvents();
9353          } else {
9354              scheduleProcessInputEvents();
9355          }
9356      }
9357  
scheduleProcessInputEvents()9358      private void scheduleProcessInputEvents() {
9359          if (!mProcessInputEventsScheduled) {
9360              mProcessInputEventsScheduled = true;
9361              Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
9362              msg.setAsynchronous(true);
9363              mHandler.sendMessage(msg);
9364          }
9365      }
9366  
doProcessInputEvents()9367      void doProcessInputEvents() {
9368          // Deliver all pending input events in the queue.
9369          while (mPendingInputEventHead != null) {
9370              QueuedInputEvent q = mPendingInputEventHead;
9371              mPendingInputEventHead = q.mNext;
9372              if (mPendingInputEventHead == null) {
9373                  mPendingInputEventTail = null;
9374              }
9375              q.mNext = null;
9376  
9377              mPendingInputEventCount -= 1;
9378              Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
9379                      mPendingInputEventCount);
9380  
9381              mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
9382  
9383              deliverInputEvent(q);
9384          }
9385  
9386          // We are done processing all input events that we can process right now
9387          // so we can clear the pending flag immediately.
9388          if (mProcessInputEventsScheduled) {
9389              mProcessInputEventsScheduled = false;
9390              mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
9391          }
9392      }
9393  
deliverInputEvent(QueuedInputEvent q)9394      private void deliverInputEvent(QueuedInputEvent q) {
9395          Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
9396                  q.mEvent.getId());
9397  
9398          if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
9399              Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x"
9400                      + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano="
9401                      + q.mEvent.getEventTimeNanos() + " id=0x"
9402                      + Integer.toHexString(q.mEvent.getId()));
9403          }
9404          try {
9405              if (mInputEventConsistencyVerifier != null) {
9406                  Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency");
9407                  try {
9408                      mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
9409                  } finally {
9410                      Trace.traceEnd(Trace.TRACE_TAG_VIEW);
9411                  }
9412              }
9413  
9414              InputStage stage;
9415              if (q.shouldSendToSynthesizer()) {
9416                  stage = mSyntheticInputStage;
9417              } else {
9418                  stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
9419              }
9420  
9421              if (q.mEvent instanceof KeyEvent) {
9422                  Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager");
9423                  try {
9424                      mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
9425                  } finally {
9426                      Trace.traceEnd(Trace.TRACE_TAG_VIEW);
9427                  }
9428              }
9429  
9430              if (stage != null) {
9431                  handleWindowFocusChanged();
9432                  stage.deliver(q);
9433              } else {
9434                  finishInputEvent(q);
9435              }
9436          } finally {
9437              Trace.traceEnd(Trace.TRACE_TAG_VIEW);
9438          }
9439      }
9440  
finishInputEvent(QueuedInputEvent q)9441      private void finishInputEvent(QueuedInputEvent q) {
9442          Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
9443                  q.mEvent.getId());
9444  
9445          if (q.mReceiver != null) {
9446              boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
9447              boolean modified = (q.mFlags & QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY) != 0;
9448              if (modified) {
9449                  Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventBeforeFinish");
9450                  InputEvent processedEvent;
9451                  try {
9452                      processedEvent =
9453                              mInputCompatProcessor.processInputEventBeforeFinish(q.mEvent);
9454                  } finally {
9455                      Trace.traceEnd(Trace.TRACE_TAG_VIEW);
9456                  }
9457                  if (processedEvent != null) {
9458                      q.mReceiver.finishInputEvent(processedEvent, handled);
9459                  }
9460              } else {
9461                  q.mReceiver.finishInputEvent(q.mEvent, handled);
9462              }
9463          } else {
9464              q.mEvent.recycleIfNeededAfterDispatch();
9465          }
9466  
9467          recycleQueuedInputEvent(q);
9468      }
9469  
isTerminalInputEvent(InputEvent event)9470      static boolean isTerminalInputEvent(InputEvent event) {
9471          if (event instanceof KeyEvent) {
9472              final KeyEvent keyEvent = (KeyEvent)event;
9473              return keyEvent.getAction() == KeyEvent.ACTION_UP;
9474          } else {
9475              final MotionEvent motionEvent = (MotionEvent)event;
9476              final int action = motionEvent.getAction();
9477              return action == MotionEvent.ACTION_UP
9478                      || action == MotionEvent.ACTION_CANCEL
9479                      || action == MotionEvent.ACTION_HOVER_EXIT;
9480          }
9481      }
9482  
scheduleConsumeBatchedInput()9483      void scheduleConsumeBatchedInput() {
9484          // If anything is currently scheduled to consume batched input then there's no point in
9485          // scheduling it again.
9486          if (!mConsumeBatchedInputScheduled && !mConsumeBatchedInputImmediatelyScheduled) {
9487              mConsumeBatchedInputScheduled = true;
9488              mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
9489                      mConsumedBatchedInputRunnable, null);
9490              if (mAttachInfo.mThreadedRenderer != null) {
9491                  mAttachInfo.mThreadedRenderer.notifyCallbackPending();
9492              }
9493          }
9494      }
9495  
unscheduleConsumeBatchedInput()9496      void unscheduleConsumeBatchedInput() {
9497          if (mConsumeBatchedInputScheduled) {
9498              mConsumeBatchedInputScheduled = false;
9499              mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
9500                      mConsumedBatchedInputRunnable, null);
9501          }
9502      }
9503  
scheduleConsumeBatchedInputImmediately()9504      void scheduleConsumeBatchedInputImmediately() {
9505          if (!mConsumeBatchedInputImmediatelyScheduled) {
9506              unscheduleConsumeBatchedInput();
9507              mConsumeBatchedInputImmediatelyScheduled = true;
9508              mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
9509          }
9510      }
9511  
doConsumeBatchedInput(long frameTimeNanos)9512      boolean doConsumeBatchedInput(long frameTimeNanos) {
9513          final boolean consumedBatches;
9514          if (mInputEventReceiver != null) {
9515              consumedBatches = mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos);
9516          } else {
9517              consumedBatches = false;
9518          }
9519          doProcessInputEvents();
9520          return consumedBatches;
9521      }
9522  
9523      final class TraversalRunnable implements Runnable {
9524          @Override
run()9525          public void run() {
9526              doTraversal();
9527          }
9528      }
9529      final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
9530  
9531      final class WindowInputEventReceiver extends InputEventReceiver {
WindowInputEventReceiver(InputChannel inputChannel, Looper looper)9532          public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
9533              super(inputChannel, looper);
9534          }
9535  
9536          @Override
onInputEvent(InputEvent event)9537          public void onInputEvent(InputEvent event) {
9538              Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
9539              List<InputEvent> processedEvents;
9540              try {
9541                  processedEvents =
9542                      mInputCompatProcessor.processInputEventForCompatibility(event);
9543              } finally {
9544                  Trace.traceEnd(Trace.TRACE_TAG_VIEW);
9545              }
9546              if (processedEvents != null) {
9547                  if (processedEvents.isEmpty()) {
9548                      // InputEvent consumed by mInputCompatProcessor
9549                      finishInputEvent(event, true);
9550                  } else {
9551                      for (int i = 0; i < processedEvents.size(); i++) {
9552                          enqueueInputEvent(
9553                                  processedEvents.get(i), this,
9554                                  QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
9555                      }
9556                  }
9557              } else {
9558                  enqueueInputEvent(event, this, 0, true);
9559              }
9560          }
9561  
9562          @Override
onBatchedInputEventPending(int source)9563          public void onBatchedInputEventPending(int source) {
9564              final boolean unbuffered = mUnbufferedInputDispatch
9565                      || (source & mUnbufferedInputSource) != SOURCE_CLASS_NONE;
9566              if (unbuffered) {
9567                  if (mConsumeBatchedInputScheduled) {
9568                      unscheduleConsumeBatchedInput();
9569                  }
9570                  // Consume event immediately if unbuffered input dispatch has been requested.
9571                  consumeBatchedInputEvents(-1);
9572                  return;
9573              }
9574              scheduleConsumeBatchedInput();
9575          }
9576  
9577          @Override
onFocusEvent(boolean hasFocus)9578          public void onFocusEvent(boolean hasFocus) {
9579              windowFocusChanged(hasFocus);
9580          }
9581  
9582          @Override
onTouchModeChanged(boolean inTouchMode)9583          public void onTouchModeChanged(boolean inTouchMode) {
9584              touchModeChanged(inTouchMode);
9585          }
9586  
9587          @Override
onPointerCaptureEvent(boolean pointerCaptureEnabled)9588          public void onPointerCaptureEvent(boolean pointerCaptureEnabled) {
9589              dispatchPointerCaptureChanged(pointerCaptureEnabled);
9590          }
9591  
9592          @Override
onDragEvent(boolean isExiting, float x, float y)9593          public void onDragEvent(boolean isExiting, float x, float y) {
9594              // force DRAG_EXITED_EVENT if appropriate
9595              DragEvent event = DragEvent.obtain(
9596                      isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION,
9597                      x, y, 0 /* offsetX */, 0 /* offsetY */, null/* localState */,
9598                      null/* description */, null /* data */, null /* dragSurface */,
9599                      null /* dragAndDropPermissions */, false /* result */);
9600              dispatchDragEvent(event);
9601          }
9602  
9603          @Override
dispose()9604          public void dispose() {
9605              unscheduleConsumeBatchedInput();
9606              super.dispose();
9607          }
9608      }
9609      private WindowInputEventReceiver mInputEventReceiver;
9610  
9611      final class InputMetricsListener
9612              implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
9613          public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT];
9614  
9615          @Override
onFrameMetricsAvailable(int dropCountSinceLastInvocation)9616          public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
9617              final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID];
9618              if (inputEventId == INVALID_INPUT_EVENT_ID) {
9619                  return;
9620              }
9621              final long presentTime = data[FrameMetrics.Index.DISPLAY_PRESENT_TIME];
9622              if (presentTime <= 0) {
9623                  // Present time is not available for this frame. If the present time is not
9624                  // available, we cannot compute end-to-end input latency metrics.
9625                  return;
9626              }
9627              final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED];
9628              if (mInputEventReceiver == null) {
9629                  return;
9630              }
9631              if (gpuCompletedTime >= presentTime) {
9632                  final double discrepancyMs = (gpuCompletedTime - presentTime) * 1E-6;
9633                  final long vsyncId = data[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID];
9634                  Log.w(TAG, "Not reporting timeline because gpuCompletedTime is " + discrepancyMs
9635                          + "ms ahead of presentTime. FRAME_TIMELINE_VSYNC_ID=" + vsyncId
9636                          + ", INPUT_EVENT_ID=" + inputEventId);
9637                  // TODO(b/186664409): figure out why this sometimes happens
9638                  return;
9639              }
9640              mInputEventReceiver.reportTimeline(inputEventId, gpuCompletedTime, presentTime);
9641          }
9642      }
9643      HardwareRendererObserver mHardwareRendererObserver;
9644  
9645      final class ConsumeBatchedInputRunnable implements Runnable {
9646          @Override
run()9647          public void run() {
9648              mConsumeBatchedInputScheduled = false;
9649              if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) {
9650                  // If we consumed a batch here, we want to go ahead and schedule the
9651                  // consumption of batched input events on the next frame. Otherwise, we would
9652                  // wait until we have more input events pending and might get starved by other
9653                  // things occurring in the process.
9654                  scheduleConsumeBatchedInput();
9655              }
9656          }
9657      }
9658      final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
9659              new ConsumeBatchedInputRunnable();
9660      boolean mConsumeBatchedInputScheduled;
9661  
9662      final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
9663          @Override
run()9664          public void run() {
9665              mConsumeBatchedInputImmediatelyScheduled = false;
9666              doConsumeBatchedInput(-1);
9667          }
9668      }
9669      final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
9670              new ConsumeBatchedInputImmediatelyRunnable();
9671      boolean mConsumeBatchedInputImmediatelyScheduled;
9672  
9673      final class InvalidateOnAnimationRunnable implements Runnable {
9674          private boolean mPosted;
9675          private final ArrayList<View> mViews = new ArrayList<View>();
9676          private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
9677                  new ArrayList<AttachInfo.InvalidateInfo>();
9678          private View[] mTempViews;
9679          private AttachInfo.InvalidateInfo[] mTempViewRects;
9680  
addView(View view)9681          public void addView(View view) {
9682              synchronized (this) {
9683                  mViews.add(view);
9684                  postIfNeededLocked();
9685              }
9686              if (mAttachInfo.mThreadedRenderer != null) {
9687                  mAttachInfo.mThreadedRenderer.notifyCallbackPending();
9688              }
9689          }
9690  
addViewRect(AttachInfo.InvalidateInfo info)9691          public void addViewRect(AttachInfo.InvalidateInfo info) {
9692              synchronized (this) {
9693                  mViewRects.add(info);
9694                  postIfNeededLocked();
9695              }
9696              if (mAttachInfo.mThreadedRenderer != null) {
9697                  mAttachInfo.mThreadedRenderer.notifyCallbackPending();
9698              }
9699          }
9700  
removeView(View view)9701          public void removeView(View view) {
9702              synchronized (this) {
9703                  mViews.remove(view);
9704  
9705                  for (int i = mViewRects.size(); i-- > 0; ) {
9706                      AttachInfo.InvalidateInfo info = mViewRects.get(i);
9707                      if (info.target == view) {
9708                          mViewRects.remove(i);
9709                          info.recycle();
9710                      }
9711                  }
9712  
9713                  if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
9714                      mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
9715                      mPosted = false;
9716                  }
9717              }
9718          }
9719  
9720          @Override
run()9721          public void run() {
9722              final int viewCount;
9723              final int viewRectCount;
9724              synchronized (this) {
9725                  mPosted = false;
9726  
9727                  viewCount = mViews.size();
9728                  if (viewCount != 0) {
9729                      mTempViews = mViews.toArray(mTempViews != null
9730                              ? mTempViews : new View[viewCount]);
9731                      mViews.clear();
9732                  }
9733  
9734                  viewRectCount = mViewRects.size();
9735                  if (viewRectCount != 0) {
9736                      mTempViewRects = mViewRects.toArray(mTempViewRects != null
9737                              ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
9738                      mViewRects.clear();
9739                  }
9740              }
9741  
9742              for (int i = 0; i < viewCount; i++) {
9743                  mTempViews[i].invalidate();
9744                  mTempViews[i] = null;
9745              }
9746  
9747              for (int i = 0; i < viewRectCount; i++) {
9748                  final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
9749                  info.target.invalidate(info.left, info.top, info.right, info.bottom);
9750                  info.recycle();
9751              }
9752          }
9753  
postIfNeededLocked()9754          private void postIfNeededLocked() {
9755              if (!mPosted) {
9756                  mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
9757                  mPosted = true;
9758              }
9759          }
9760      }
9761      final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
9762              new InvalidateOnAnimationRunnable();
9763  
dispatchInvalidateDelayed(View view, long delayMilliseconds)9764      public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
9765          Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
9766          mHandler.sendMessageDelayed(msg, delayMilliseconds);
9767      }
9768  
dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, long delayMilliseconds)9769      public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
9770              long delayMilliseconds) {
9771          final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
9772          mHandler.sendMessageDelayed(msg, delayMilliseconds);
9773      }
9774  
dispatchInvalidateOnAnimation(View view)9775      public void dispatchInvalidateOnAnimation(View view) {
9776          mInvalidateOnAnimationRunnable.addView(view);
9777      }
9778  
dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info)9779      public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
9780          mInvalidateOnAnimationRunnable.addViewRect(info);
9781      }
9782  
9783      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
cancelInvalidate(View view)9784      public void cancelInvalidate(View view) {
9785          mHandler.removeMessages(MSG_INVALIDATE, view);
9786          // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
9787          // them to the pool
9788          mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
9789          mInvalidateOnAnimationRunnable.removeView(view);
9790      }
9791  
9792      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
dispatchInputEvent(InputEvent event)9793      public void dispatchInputEvent(InputEvent event) {
9794          dispatchInputEvent(event, null);
9795      }
9796  
9797      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
dispatchInputEvent(InputEvent event, InputEventReceiver receiver)9798      public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
9799          SomeArgs args = SomeArgs.obtain();
9800          args.arg1 = event;
9801          args.arg2 = receiver;
9802          Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
9803          msg.setAsynchronous(true);
9804          mHandler.sendMessage(msg);
9805      }
9806  
synthesizeInputEvent(InputEvent event)9807      public void synthesizeInputEvent(InputEvent event) {
9808          Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
9809          msg.setAsynchronous(true);
9810          mHandler.sendMessage(msg);
9811      }
9812  
9813      @UnsupportedAppUsage
dispatchKeyFromIme(KeyEvent event)9814      public void dispatchKeyFromIme(KeyEvent event) {
9815          Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
9816          msg.setAsynchronous(true);
9817          mHandler.sendMessage(msg);
9818      }
9819  
dispatchKeyFromAutofill(KeyEvent event)9820      public void dispatchKeyFromAutofill(KeyEvent event) {
9821          Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event);
9822          msg.setAsynchronous(true);
9823          mHandler.sendMessage(msg);
9824      }
9825  
9826      /**
9827       * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
9828       *
9829       * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
9830       * passes in.
9831       */
9832      @UnsupportedAppUsage
dispatchUnhandledInputEvent(InputEvent event)9833      public void dispatchUnhandledInputEvent(InputEvent event) {
9834          if (event instanceof MotionEvent) {
9835              event = MotionEvent.obtain((MotionEvent) event);
9836          }
9837          synthesizeInputEvent(event);
9838      }
9839  
dispatchAppVisibility(boolean visible)9840      public void dispatchAppVisibility(boolean visible) {
9841          Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
9842          msg.arg1 = visible ? 1 : 0;
9843          mHandler.sendMessage(msg);
9844      }
9845  
dispatchGetNewSurface()9846      public void dispatchGetNewSurface() {
9847          Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
9848          mHandler.sendMessage(msg);
9849      }
9850  
9851      /**
9852       * Notifies this {@link ViewRootImpl} object that window focus has changed.
9853       */
windowFocusChanged(boolean hasFocus)9854      public void windowFocusChanged(boolean hasFocus) {
9855          synchronized (this) {
9856              mWindowFocusChanged = true;
9857              mUpcomingWindowFocus = hasFocus;
9858          }
9859          Message msg = Message.obtain();
9860          msg.what = MSG_WINDOW_FOCUS_CHANGED;
9861          mHandler.sendMessage(msg);
9862      }
9863  
9864      /**
9865       * Notifies this {@link ViewRootImpl} object that touch mode state has changed.
9866       */
touchModeChanged(boolean inTouchMode)9867      public void touchModeChanged(boolean inTouchMode) {
9868          synchronized (this) {
9869              mUpcomingInTouchMode = inTouchMode;
9870          }
9871          Message msg = Message.obtain();
9872          msg.what = MSG_WINDOW_TOUCH_MODE_CHANGED;
9873          mHandler.sendMessage(msg);
9874      }
9875  
dispatchWindowShown()9876      public void dispatchWindowShown() {
9877          mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
9878      }
9879  
dispatchCloseSystemDialogs(String reason)9880      public void dispatchCloseSystemDialogs(String reason) {
9881          Message msg = Message.obtain();
9882          msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
9883          msg.obj = reason;
9884          mHandler.sendMessage(msg);
9885      }
9886  
dispatchDragEvent(DragEvent event)9887      public void dispatchDragEvent(DragEvent event) {
9888          final int what;
9889          if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
9890              what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
9891              mHandler.removeMessages(what);
9892          } else {
9893              what = MSG_DISPATCH_DRAG_EVENT;
9894          }
9895          Message msg = mHandler.obtainMessage(what, event);
9896          mHandler.sendMessage(msg);
9897      }
9898  
updatePointerIcon(float x, float y)9899      public void updatePointerIcon(float x, float y) {
9900          final int what = MSG_UPDATE_POINTER_ICON;
9901          mHandler.removeMessages(what);
9902          final long now = SystemClock.uptimeMillis();
9903          final MotionEvent event = MotionEvent.obtain(
9904                  0, now, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
9905          Message msg = mHandler.obtainMessage(what, event);
9906          mHandler.sendMessage(msg);
9907      }
9908  
dispatchCheckFocus()9909      public void dispatchCheckFocus() {
9910          if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
9911              // This will result in a call to checkFocus() below.
9912              mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
9913          }
9914      }
9915  
dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)9916      public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
9917          mHandler.obtainMessage(
9918                  MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
9919      }
9920  
dispatchPointerCaptureChanged(boolean on)9921      private void dispatchPointerCaptureChanged(boolean on) {
9922          final int what = MSG_POINTER_CAPTURE_CHANGED;
9923          mHandler.removeMessages(what);
9924          Message msg = mHandler.obtainMessage(what);
9925          msg.arg1 = on ? 1 : 0;
9926          mHandler.sendMessage(msg);
9927      }
9928  
9929      /**
9930       * Post a callback to send a
9931       * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
9932       * This event is send at most once every
9933       * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
9934       */
postSendWindowContentChangedCallback(View source, int changeType)9935      private void postSendWindowContentChangedCallback(View source, int changeType) {
9936          if (mSendWindowContentChangedAccessibilityEvent == null) {
9937              mSendWindowContentChangedAccessibilityEvent =
9938                  new SendWindowContentChangedAccessibilityEvent();
9939          }
9940          mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
9941      }
9942  
9943      /**
9944       * Remove a posted callback to send a
9945       * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
9946       */
removeSendWindowContentChangedCallback()9947      private void removeSendWindowContentChangedCallback() {
9948          if (mSendWindowContentChangedAccessibilityEvent != null) {
9949              mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
9950          }
9951      }
9952  
9953      /**
9954       * Return the connection ID for the {@link AccessibilityInteractionController} of this instance.
9955       * @see AccessibilityNodeInfo#setQueryFromAppProcessEnabled
9956       */
getDirectAccessibilityConnectionId()9957      public int getDirectAccessibilityConnectionId() {
9958          return mAccessibilityInteractionConnectionManager.ensureDirectConnection();
9959      }
9960  
9961      @Override
showContextMenuForChild(View originalView)9962      public boolean showContextMenuForChild(View originalView) {
9963          return false;
9964      }
9965  
9966      @Override
showContextMenuForChild(View originalView, float x, float y)9967      public boolean showContextMenuForChild(View originalView, float x, float y) {
9968          return false;
9969      }
9970  
9971      @Override
startActionModeForChild(View originalView, ActionMode.Callback callback)9972      public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
9973          return null;
9974      }
9975  
9976      @Override
startActionModeForChild( View originalView, ActionMode.Callback callback, int type)9977      public ActionMode startActionModeForChild(
9978              View originalView, ActionMode.Callback callback, int type) {
9979          return null;
9980      }
9981  
9982      @Override
createContextMenu(ContextMenu menu)9983      public void createContextMenu(ContextMenu menu) {
9984      }
9985  
9986      @Override
childDrawableStateChanged(View child)9987      public void childDrawableStateChanged(View child) {
9988      }
9989  
9990      @Override
requestSendAccessibilityEvent(View child, AccessibilityEvent event)9991      public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
9992          if (mView == null || mStopped || mPausedForTransition) {
9993              return false;
9994          }
9995  
9996          // Immediately flush pending content changed event (if any) to preserve event order
9997          if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
9998                  && mSendWindowContentChangedAccessibilityEvent != null
9999                  && mSendWindowContentChangedAccessibilityEvent.mSource != null) {
10000              mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun();
10001          }
10002  
10003          // Intercept accessibility focus events fired by virtual nodes to keep
10004          // track of accessibility focus position in such nodes.
10005          final int eventType = event.getEventType();
10006          final View source = getSourceForAccessibilityEvent(event);
10007          switch (eventType) {
10008              case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
10009                  if (source != null) {
10010                      AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
10011                      if (provider != null) {
10012                          final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
10013                                  event.getSourceNodeId());
10014                          final AccessibilityNodeInfo node;
10015                          node = provider.createAccessibilityNodeInfo(virtualNodeId);
10016                          setAccessibilityFocus(source, node);
10017                      }
10018                  }
10019              } break;
10020              case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
10021                  if (source != null && source.getAccessibilityNodeProvider() != null) {
10022                      setAccessibilityFocus(null, null);
10023                  }
10024              } break;
10025  
10026  
10027              case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
10028                  handleWindowContentChangedEvent(event);
10029              } break;
10030          }
10031          mAccessibilityManager.sendAccessibilityEvent(event);
10032          return true;
10033      }
10034  
getSourceForAccessibilityEvent(AccessibilityEvent event)10035      private View getSourceForAccessibilityEvent(AccessibilityEvent event) {
10036          final long sourceNodeId = event.getSourceNodeId();
10037          final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
10038                  sourceNodeId);
10039          return AccessibilityNodeIdManager.getInstance().findView(accessibilityViewId);
10040      }
10041  
10042      /**
10043       * Updates the focused virtual view, when necessary, in response to a
10044       * content changed event.
10045       * <p>
10046       * This is necessary to get updated bounds after a position change.
10047       *
10048       * @param event an accessibility event of type
10049       *              {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
10050       */
handleWindowContentChangedEvent(AccessibilityEvent event)10051      private void handleWindowContentChangedEvent(AccessibilityEvent event) {
10052          final View focusedHost = mAccessibilityFocusedHost;
10053          if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
10054              // No virtual view focused, nothing to do here.
10055              return;
10056          }
10057  
10058          final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
10059          if (provider == null) {
10060              // Error state: virtual view with no provider. Clear focus.
10061              mAccessibilityFocusedHost = null;
10062              mAccessibilityFocusedVirtualView = null;
10063              focusedHost.clearAccessibilityFocusNoCallbacks(0);
10064              return;
10065          }
10066  
10067          // We only care about change types that may affect the bounds of the
10068          // focused virtual view.
10069          final int changes = event.getContentChangeTypes();
10070          if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
10071                  && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
10072              return;
10073          }
10074  
10075          final long eventSourceNodeId = event.getSourceNodeId();
10076          final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
10077  
10078          // Search up the tree for subtree containment.
10079          boolean hostInSubtree = false;
10080          View root = mAccessibilityFocusedHost;
10081          while (root != null && !hostInSubtree) {
10082              if (changedViewId == root.getAccessibilityViewId()) {
10083                  hostInSubtree = true;
10084              } else {
10085                  final ViewParent parent = root.getParent();
10086                  if (parent instanceof View) {
10087                      root = (View) parent;
10088                  } else {
10089                      root = null;
10090                  }
10091              }
10092          }
10093  
10094          // We care only about changes in subtrees containing the host view.
10095          if (!hostInSubtree) {
10096              return;
10097          }
10098  
10099          final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
10100          int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
10101  
10102          // Refresh the node for the focused virtual view.
10103          final Rect oldBounds = mTempRect;
10104          mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
10105          mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
10106          if (mAccessibilityFocusedVirtualView == null) {
10107              // Error state: The node no longer exists. Clear focus.
10108              mAccessibilityFocusedHost = null;
10109              focusedHost.clearAccessibilityFocusNoCallbacks(0);
10110  
10111              // This will probably fail, but try to keep the provider's internal
10112              // state consistent by clearing focus.
10113              provider.performAction(focusedChildId,
10114                      AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
10115              invalidateRectOnScreen(oldBounds);
10116          } else {
10117              // The node was refreshed, invalidate bounds if necessary.
10118              final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
10119              if (!oldBounds.equals(newBounds)) {
10120                  oldBounds.union(newBounds);
10121                  invalidateRectOnScreen(oldBounds);
10122              }
10123          }
10124      }
10125  
10126      @Override
notifySubtreeAccessibilityStateChanged(View child, View source, int changeType)10127      public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
10128          postSendWindowContentChangedCallback(Preconditions.checkNotNull(source), changeType);
10129      }
10130  
10131      @Override
canResolveLayoutDirection()10132      public boolean canResolveLayoutDirection() {
10133          return true;
10134      }
10135  
10136      @Override
isLayoutDirectionResolved()10137      public boolean isLayoutDirectionResolved() {
10138          return true;
10139      }
10140  
10141      @Override
getLayoutDirection()10142      public int getLayoutDirection() {
10143          return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
10144      }
10145  
10146      @Override
canResolveTextDirection()10147      public boolean canResolveTextDirection() {
10148          return true;
10149      }
10150  
10151      @Override
isTextDirectionResolved()10152      public boolean isTextDirectionResolved() {
10153          return true;
10154      }
10155  
10156      @Override
getTextDirection()10157      public int getTextDirection() {
10158          return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
10159      }
10160  
10161      @Override
canResolveTextAlignment()10162      public boolean canResolveTextAlignment() {
10163          return true;
10164      }
10165  
10166      @Override
isTextAlignmentResolved()10167      public boolean isTextAlignmentResolved() {
10168          return true;
10169      }
10170  
10171      @Override
getTextAlignment()10172      public int getTextAlignment() {
10173          return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
10174      }
10175  
getCommonPredecessor(View first, View second)10176      private View getCommonPredecessor(View first, View second) {
10177          if (mTempHashSet == null) {
10178              mTempHashSet = new HashSet<View>();
10179          }
10180          HashSet<View> seen = mTempHashSet;
10181          seen.clear();
10182          View firstCurrent = first;
10183          while (firstCurrent != null) {
10184              seen.add(firstCurrent);
10185              ViewParent firstCurrentParent = firstCurrent.mParent;
10186              if (firstCurrentParent instanceof View) {
10187                  firstCurrent = (View) firstCurrentParent;
10188              } else {
10189                  firstCurrent = null;
10190              }
10191          }
10192          View secondCurrent = second;
10193          while (secondCurrent != null) {
10194              if (seen.contains(secondCurrent)) {
10195                  seen.clear();
10196                  return secondCurrent;
10197              }
10198              ViewParent secondCurrentParent = secondCurrent.mParent;
10199              if (secondCurrentParent instanceof View) {
10200                  secondCurrent = (View) secondCurrentParent;
10201              } else {
10202                  secondCurrent = null;
10203              }
10204          }
10205          seen.clear();
10206          return null;
10207      }
10208  
checkThread()10209      void checkThread() {
10210          Thread current = Thread.currentThread();
10211          if (mThread != current) {
10212              throw new CalledFromWrongThreadException(
10213                      "Only the original thread that created a view hierarchy can touch its views."
10214                              + " Expected: " + mThread.getName()
10215                              + " Calling: " + current.getName());
10216          }
10217      }
10218  
10219      @Override
requestDisallowInterceptTouchEvent(boolean disallowIntercept)10220      public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
10221          // ViewAncestor never intercepts touch event, so this can be a no-op
10222      }
10223  
10224      @Override
requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)10225      public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
10226          if (rectangle == null) {
10227              return scrollToRectOrFocus(null, immediate);
10228          }
10229          rectangle.offset(child.getLeft() - child.getScrollX(),
10230                  child.getTop() - child.getScrollY());
10231          final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
10232          mTempRect.set(rectangle);
10233          mTempRect.offset(0, -mCurScrollY);
10234          mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
10235          try {
10236              mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
10237          } catch (RemoteException re) {
10238              /* ignore */
10239          }
10240          return scrolled;
10241      }
10242  
10243      @Override
childHasTransientStateChanged(View child, boolean hasTransientState)10244      public void childHasTransientStateChanged(View child, boolean hasTransientState) {
10245          // Do nothing.
10246      }
10247  
10248      @Override
onStartNestedScroll(View child, View target, int nestedScrollAxes)10249      public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
10250          return false;
10251      }
10252  
10253      @Override
onStopNestedScroll(View target)10254      public void onStopNestedScroll(View target) {
10255      }
10256  
10257      @Override
onNestedScrollAccepted(View child, View target, int nestedScrollAxes)10258      public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
10259      }
10260  
10261      @Override
onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)10262      public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
10263              int dxUnconsumed, int dyUnconsumed) {
10264      }
10265  
10266      @Override
onNestedPreScroll(View target, int dx, int dy, int[] consumed)10267      public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
10268      }
10269  
10270      @Override
onNestedFling(View target, float velocityX, float velocityY, boolean consumed)10271      public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
10272          return false;
10273      }
10274  
10275      @Override
onNestedPreFling(View target, float velocityX, float velocityY)10276      public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
10277          return false;
10278      }
10279  
10280      @Override
onNestedPrePerformAccessibilityAction(View target, int action, Bundle args)10281      public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
10282          return false;
10283      }
10284  
10285      /**
10286       * Adds a scroll capture callback to this window.
10287       *
10288       * @param callback the callback to add
10289       */
addScrollCaptureCallback(ScrollCaptureCallback callback)10290      public void addScrollCaptureCallback(ScrollCaptureCallback callback) {
10291          if (mRootScrollCaptureCallbacks == null) {
10292              mRootScrollCaptureCallbacks = new HashSet<>();
10293          }
10294          mRootScrollCaptureCallbacks.add(callback);
10295      }
10296  
10297      /**
10298       * Removes a scroll capture callback from this window.
10299       *
10300       * @param callback the callback to remove
10301       */
removeScrollCaptureCallback(ScrollCaptureCallback callback)10302      public void removeScrollCaptureCallback(ScrollCaptureCallback callback) {
10303          if (mRootScrollCaptureCallbacks != null) {
10304              mRootScrollCaptureCallbacks.remove(callback);
10305              if (mRootScrollCaptureCallbacks.isEmpty()) {
10306                  mRootScrollCaptureCallbacks = null;
10307              }
10308          }
10309      }
10310  
10311      /**
10312       * Dispatches a scroll capture request to the view hierarchy on the ui thread.
10313       *
10314       * @param listener for the response
10315       */
dispatchScrollCaptureRequest(@onNull IScrollCaptureResponseListener listener)10316      public void dispatchScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) {
10317          mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, listener).sendToTarget();
10318      }
10319  
10320      /**
10321       * Collect and include any ScrollCaptureCallback instances registered with the window.
10322       *
10323       * @see #addScrollCaptureCallback(ScrollCaptureCallback)
10324       * @param results an object to collect the results of the search
10325       */
collectRootScrollCaptureTargets(ScrollCaptureSearchResults results)10326      private void collectRootScrollCaptureTargets(ScrollCaptureSearchResults results) {
10327          if (mRootScrollCaptureCallbacks == null) {
10328              return;
10329          }
10330          for (ScrollCaptureCallback cb : mRootScrollCaptureCallbacks) {
10331              // Add to the list for consideration
10332              Point offset = new Point(mView.getLeft(), mView.getTop());
10333              Rect rect = new Rect(0, 0, mView.getWidth(), mView.getHeight());
10334              results.addTarget(new ScrollCaptureTarget(mView, rect, offset, cb));
10335          }
10336      }
10337  
10338      /**
10339       * Update the timeout for scroll capture requests. Only affects this view root.
10340       * The default value is {@link #SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS}.
10341       *
10342       * @param timeMillis the new timeout in milliseconds
10343       */
setScrollCaptureRequestTimeout(int timeMillis)10344      public void setScrollCaptureRequestTimeout(int timeMillis) {
10345          mScrollCaptureRequestTimeout = timeMillis;
10346      }
10347  
10348      /**
10349       * Get the current timeout for scroll capture requests.
10350       *
10351       * @return the timeout in milliseconds
10352       */
getScrollCaptureRequestTimeout()10353      public long getScrollCaptureRequestTimeout() {
10354          return mScrollCaptureRequestTimeout;
10355      }
10356  
10357      /**
10358       * Handles an inbound request for scroll capture from the system. A search will be
10359       * dispatched through the view tree to locate scrolling content.
10360       * <p>
10361       * A call to
10362       * {@link IScrollCaptureResponseListener#onScrollCaptureResponse} will follow.
10363       *
10364       * @param listener to receive responses
10365       * @see ScrollCaptureSearchResults
10366       */
handleScrollCaptureRequest(@onNull IScrollCaptureResponseListener listener)10367      public void handleScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) {
10368          ScrollCaptureSearchResults results =
10369                  new ScrollCaptureSearchResults(mContext.getMainExecutor());
10370  
10371          // Window (root) level callbacks
10372          collectRootScrollCaptureTargets(results);
10373  
10374          // Search through View-tree
10375          View rootView = getView();
10376          if (rootView != null) {
10377              Point point = new Point();
10378              Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight());
10379              getChildVisibleRect(rootView, rect, point);
10380              rootView.dispatchScrollCaptureSearch(rect, point, results::addTarget);
10381          }
10382          Runnable onComplete = () -> dispatchScrollCaptureSearchResponse(listener, results);
10383          results.setOnCompleteListener(onComplete);
10384          if (!results.isComplete()) {
10385              mHandler.postDelayed(results::finish, getScrollCaptureRequestTimeout());
10386          }
10387      }
10388  
10389      /** Called by {@link #handleScrollCaptureRequest} when a result is returned */
dispatchScrollCaptureSearchResponse( @onNull IScrollCaptureResponseListener listener, @NonNull ScrollCaptureSearchResults results)10390      private void dispatchScrollCaptureSearchResponse(
10391              @NonNull IScrollCaptureResponseListener listener,
10392              @NonNull ScrollCaptureSearchResults results) {
10393  
10394          ScrollCaptureTarget selectedTarget = results.getTopResult();
10395  
10396          ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
10397          response.setWindowTitle(getTitle().toString());
10398          response.setPackageName(mContext.getPackageName());
10399  
10400          StringWriter writer =  new StringWriter();
10401          IndentingPrintWriter pw = new IndentingPrintWriter(writer);
10402          results.dump(pw);
10403          pw.flush();
10404          response.addMessage(writer.toString());
10405  
10406          if (selectedTarget == null) {
10407              response.setDescription("No scrollable targets found in window");
10408              try {
10409                  listener.onScrollCaptureResponse(response.build());
10410              } catch (RemoteException e) {
10411                  Log.e(TAG, "Failed to send scroll capture search result", e);
10412              }
10413              return;
10414          }
10415  
10416          response.setDescription("Connected");
10417  
10418          // Compute area covered by scrolling content within window
10419          Rect boundsInWindow = new Rect();
10420          View containingView = selectedTarget.getContainingView();
10421          containingView.getLocationInWindow(mAttachInfo.mTmpLocation);
10422          boundsInWindow.set(selectedTarget.getScrollBounds());
10423          boundsInWindow.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]);
10424          response.setBoundsInWindow(boundsInWindow);
10425  
10426          // Compute the area on screen covered by the window
10427          Rect boundsOnScreen = new Rect();
10428          mView.getLocationOnScreen(mAttachInfo.mTmpLocation);
10429          boundsOnScreen.set(0, 0, mView.getWidth(), mView.getHeight());
10430          boundsOnScreen.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]);
10431          response.setWindowBounds(boundsOnScreen);
10432  
10433          // Create a connection and return it to the caller
10434          ScrollCaptureConnection connection = new ScrollCaptureConnection(
10435                  mView.getContext().getMainExecutor(), selectedTarget);
10436          response.setConnection(connection);
10437  
10438          try {
10439              listener.onScrollCaptureResponse(response.build());
10440          } catch (RemoteException e) {
10441              if (DEBUG_SCROLL_CAPTURE) {
10442                  Log.w(TAG, "Failed to send scroll capture search response.", e);
10443              }
10444              connection.close();
10445          }
10446      }
10447  
reportNextDraw(String reason)10448      private void reportNextDraw(String reason) {
10449          if (DEBUG_BLAST) {
10450              Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
10451          }
10452          mReportNextDraw = true;
10453          mLastReportNextDrawReason = reason;
10454      }
10455  
10456      /**
10457       * Force the window to report its next draw.
10458       * <p>
10459       * This method is only supposed to be used to speed up the interaction from SystemUI and window
10460       * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
10461       * unless you fully understand this interaction.
10462       *
10463       * @param syncBuffer If true, the transaction that contains the buffer from the draw should be
10464       *                   sent to system to be synced. If false, VRI will not try to sync the buffer,
10465       *                   but only report back that a buffer was drawn.
10466       * @param reason A debug string indicating the reason for reporting the next draw
10467       * @hide
10468       */
setReportNextDraw(boolean syncBuffer, String reason)10469      public void setReportNextDraw(boolean syncBuffer, String reason) {
10470          mSyncBuffer = syncBuffer;
10471          reportNextDraw(reason);
10472          invalidate();
10473      }
10474  
changeCanvasOpacity(boolean opaque)10475      void changeCanvasOpacity(boolean opaque) {
10476          Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
10477          opaque = opaque & ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0);
10478          if (mAttachInfo.mThreadedRenderer != null) {
10479              mAttachInfo.mThreadedRenderer.setOpaque(opaque);
10480          }
10481      }
10482  
10483      /**
10484       * Dispatches a KeyEvent to all registered key fallback handlers.
10485       *
10486       * @param event
10487       * @return {@code true} if the event was handled, {@code false} otherwise.
10488       */
dispatchUnhandledKeyEvent(KeyEvent event)10489      public boolean dispatchUnhandledKeyEvent(KeyEvent event) {
10490          return mUnhandledKeyManager.dispatch(mView, event);
10491      }
10492  
10493      class TakenSurfaceHolder extends BaseSurfaceHolder {
10494          @Override
onAllowLockCanvas()10495          public boolean onAllowLockCanvas() {
10496              return mDrawingAllowed;
10497          }
10498  
10499          @Override
onRelayoutContainer()10500          public void onRelayoutContainer() {
10501              // Not currently interesting -- from changing between fixed and layout size.
10502          }
10503  
10504          @Override
setFormat(int format)10505          public void setFormat(int format) {
10506              ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
10507          }
10508  
10509          @Override
setType(int type)10510          public void setType(int type) {
10511              ((RootViewSurfaceTaker)mView).setSurfaceType(type);
10512          }
10513  
10514          @Override
onUpdateSurface()10515          public void onUpdateSurface() {
10516              // We take care of format and type changes on our own.
10517              throw new IllegalStateException("Shouldn't be here");
10518          }
10519  
10520          @Override
isCreating()10521          public boolean isCreating() {
10522              return mIsCreating;
10523          }
10524  
10525          @Override
setFixedSize(int width, int height)10526          public void setFixedSize(int width, int height) {
10527              throw new UnsupportedOperationException(
10528                      "Currently only support sizing from layout");
10529          }
10530  
10531          @Override
setKeepScreenOn(boolean screenOn)10532          public void setKeepScreenOn(boolean screenOn) {
10533              ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
10534          }
10535      }
10536  
10537      static class W extends IWindow.Stub {
10538          private final WeakReference<ViewRootImpl> mViewAncestor;
10539          private final IWindowSession mWindowSession;
10540  
W(ViewRootImpl viewAncestor)10541          W(ViewRootImpl viewAncestor) {
10542              mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
10543              mWindowSession = viewAncestor.mWindowSession;
10544          }
10545  
10546          @Override
resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing)10547          public void resized(ClientWindowFrames frames, boolean reportDraw,
10548                  MergedConfiguration mergedConfiguration, InsetsState insetsState,
10549                  boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
10550                  boolean dragResizing) {
10551              final ViewRootImpl viewAncestor = mViewAncestor.get();
10552              if (viewAncestor != null) {
10553                  viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState,
10554                          forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing);
10555              }
10556          }
10557  
10558          @Override
insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)10559          public void insetsControlChanged(InsetsState insetsState,
10560                  InsetsSourceControl[] activeControls) {
10561              final ViewRootImpl viewAncestor = mViewAncestor.get();
10562              if (viewAncestor != null) {
10563                  viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls);
10564              }
10565          }
10566  
10567          @Override
showInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)10568          public void showInsets(@InsetsType int types, boolean fromIme,
10569                  @Nullable ImeTracker.Token statsToken) {
10570              final ViewRootImpl viewAncestor = mViewAncestor.get();
10571              if (fromIme) {
10572                  ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#showInsets",
10573                          viewAncestor.getInsetsController().getHost().getInputMethodManager(),
10574                          null /* icProto */);
10575              }
10576              if (viewAncestor != null) {
10577                  ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
10578                  viewAncestor.showInsets(types, fromIme, statsToken);
10579              } else {
10580                  ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
10581              }
10582          }
10583  
10584          @Override
hideInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)10585          public void hideInsets(@InsetsType int types, boolean fromIme,
10586                  @Nullable ImeTracker.Token statsToken) {
10587              final ViewRootImpl viewAncestor = mViewAncestor.get();
10588              if (fromIme) {
10589                  ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#hideInsets",
10590                          viewAncestor.getInsetsController().getHost().getInputMethodManager(),
10591                          null /* icProto */);
10592              }
10593              if (viewAncestor != null) {
10594                  ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
10595                  viewAncestor.hideInsets(types, fromIme, statsToken);
10596              } else {
10597                  ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
10598              }
10599          }
10600  
10601          @Override
moved(int newX, int newY)10602          public void moved(int newX, int newY) {
10603              final ViewRootImpl viewAncestor = mViewAncestor.get();
10604              if (viewAncestor != null) {
10605                  viewAncestor.dispatchMoved(newX, newY);
10606              }
10607          }
10608  
10609          @Override
dispatchAppVisibility(boolean visible)10610          public void dispatchAppVisibility(boolean visible) {
10611              final ViewRootImpl viewAncestor = mViewAncestor.get();
10612              if (viewAncestor != null) {
10613                  viewAncestor.dispatchAppVisibility(visible);
10614              }
10615          }
10616  
10617          @Override
dispatchGetNewSurface()10618          public void dispatchGetNewSurface() {
10619              final ViewRootImpl viewAncestor = mViewAncestor.get();
10620              if (viewAncestor != null) {
10621                  viewAncestor.dispatchGetNewSurface();
10622              }
10623          }
10624  
checkCallingPermission(String permission)10625          private static int checkCallingPermission(String permission) {
10626              try {
10627                  return ActivityManager.getService().checkPermission(
10628                          permission, Binder.getCallingPid(), Binder.getCallingUid());
10629              } catch (RemoteException e) {
10630                  return PackageManager.PERMISSION_DENIED;
10631              }
10632          }
10633  
10634          @Override
executeCommand(String command, String parameters, ParcelFileDescriptor out)10635          public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
10636              final ViewRootImpl viewAncestor = mViewAncestor.get();
10637              if (viewAncestor != null) {
10638                  final View view = viewAncestor.mView;
10639                  if (view != null) {
10640                      if (checkCallingPermission(Manifest.permission.DUMP) !=
10641                              PackageManager.PERMISSION_GRANTED) {
10642                          throw new SecurityException("Insufficient permissions to invoke"
10643                                  + " executeCommand() from pid=" + Binder.getCallingPid()
10644                                  + ", uid=" + Binder.getCallingUid());
10645                      }
10646  
10647                      OutputStream clientStream = null;
10648                      try {
10649                          clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
10650                          ViewDebug.dispatchCommand(view, command, parameters, clientStream);
10651                      } catch (IOException e) {
10652                          e.printStackTrace();
10653                      } finally {
10654                          if (clientStream != null) {
10655                              try {
10656                                  clientStream.close();
10657                              } catch (IOException e) {
10658                                  e.printStackTrace();
10659                              }
10660                          }
10661                      }
10662                  }
10663              }
10664          }
10665  
10666          @Override
closeSystemDialogs(String reason)10667          public void closeSystemDialogs(String reason) {
10668              final ViewRootImpl viewAncestor = mViewAncestor.get();
10669              if (viewAncestor != null) {
10670                  viewAncestor.dispatchCloseSystemDialogs(reason);
10671              }
10672          }
10673  
10674          @Override
dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom, boolean sync)10675          public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
10676                  float zoom, boolean sync) {
10677              if (sync) {
10678                  try {
10679                      mWindowSession.wallpaperOffsetsComplete(asBinder());
10680                  } catch (RemoteException e) {
10681                  }
10682              }
10683          }
10684  
10685          @Override
dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync)10686          public void dispatchWallpaperCommand(String action, int x, int y,
10687                  int z, Bundle extras, boolean sync) {
10688              if (sync) {
10689                  try {
10690                      mWindowSession.wallpaperCommandComplete(asBinder(), null);
10691                  } catch (RemoteException e) {
10692                  }
10693              }
10694          }
10695  
10696          /* Drag/drop */
10697          @Override
dispatchDragEvent(DragEvent event)10698          public void dispatchDragEvent(DragEvent event) {
10699              final ViewRootImpl viewAncestor = mViewAncestor.get();
10700              if (viewAncestor != null) {
10701                  viewAncestor.dispatchDragEvent(event);
10702              }
10703          }
10704  
10705          @Override
updatePointerIcon(float x, float y)10706          public void updatePointerIcon(float x, float y) {
10707              final ViewRootImpl viewAncestor = mViewAncestor.get();
10708              if (viewAncestor != null) {
10709                  viewAncestor.updatePointerIcon(x, y);
10710              }
10711          }
10712  
10713          @Override
dispatchWindowShown()10714          public void dispatchWindowShown() {
10715              final ViewRootImpl viewAncestor = mViewAncestor.get();
10716              if (viewAncestor != null) {
10717                  viewAncestor.dispatchWindowShown();
10718              }
10719          }
10720  
10721          @Override
requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId)10722          public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
10723              ViewRootImpl viewAncestor = mViewAncestor.get();
10724              if (viewAncestor != null) {
10725                  viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
10726              }
10727          }
10728  
10729          @Override
requestScrollCapture(IScrollCaptureResponseListener listener)10730          public void requestScrollCapture(IScrollCaptureResponseListener listener) {
10731              final ViewRootImpl viewAncestor = mViewAncestor.get();
10732              if (viewAncestor != null) {
10733                  viewAncestor.dispatchScrollCaptureRequest(listener);
10734              }
10735          }
10736      }
10737  
10738      public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
10739          @UnsupportedAppUsage
CalledFromWrongThreadException(String msg)10740          public CalledFromWrongThreadException(String msg) {
10741              super(msg);
10742          }
10743      }
10744  
getRunQueue()10745      static HandlerActionQueue getRunQueue() {
10746          HandlerActionQueue rq = sRunQueues.get();
10747          if (rq != null) {
10748              return rq;
10749          }
10750          rq = new HandlerActionQueue();
10751          sRunQueues.set(rq);
10752          return rq;
10753      }
10754  
10755      /**
10756       * Start a drag resizing which will inform all listeners that a window resize is taking place.
10757       */
startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, Rect stableInsets)10758      private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
10759              Rect stableInsets) {
10760          if (!mDragResizing) {
10761              mDragResizing = true;
10762              if (mUseMTRenderer) {
10763                  for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
10764                      mWindowCallbacks.get(i).onWindowDragResizeStart(
10765                              initialBounds, fullscreen, systemInsets, stableInsets);
10766                  }
10767              }
10768              mFullRedrawNeeded = true;
10769          }
10770      }
10771  
10772      /**
10773       * End a drag resize which will inform all listeners that a window resize has ended.
10774       */
endDragResizing()10775      private void endDragResizing() {
10776          if (mDragResizing) {
10777              mDragResizing = false;
10778              if (mUseMTRenderer) {
10779                  for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
10780                      mWindowCallbacks.get(i).onWindowDragResizeEnd();
10781                  }
10782              }
10783              mFullRedrawNeeded = true;
10784          }
10785      }
10786  
updateContentDrawBounds()10787      private boolean updateContentDrawBounds() {
10788          boolean updated = false;
10789          if (mUseMTRenderer) {
10790              for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
10791                  updated |=
10792                          mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left,
10793                                  mWindowAttributes.surfaceInsets.top, mWidth, mHeight);
10794              }
10795          }
10796          return updated | (mDragResizing && mReportNextDraw);
10797      }
10798  
requestDrawWindow()10799      private void requestDrawWindow() {
10800          if (!mUseMTRenderer) {
10801              return;
10802          }
10803          // Only wait if it will report next draw.
10804          if (mReportNextDraw) {
10805              mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
10806          }
10807          for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
10808              mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
10809          }
10810      }
10811  
getSurfaceControl()10812      public SurfaceControl getSurfaceControl() {
10813          return mSurfaceControl;
10814      }
10815  
10816      /**
10817       * @return Returns a token used to identify the windows input channel.
10818       */
getInputToken()10819      public IBinder getInputToken() {
10820          if (mInputEventReceiver == null) {
10821              return null;
10822          }
10823          return mInputEventReceiver.getToken();
10824      }
10825  
10826      @NonNull
getWindowToken()10827      public IBinder getWindowToken() {
10828          return mAttachInfo.mWindowToken;
10829      }
10830  
10831      /**
10832       * Class for managing the accessibility interaction connection
10833       * based on the global accessibility state.
10834       */
10835      final class AccessibilityInteractionConnectionManager
10836              implements AccessibilityStateChangeListener {
10837          private int mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID;
10838  
10839          @Override
onAccessibilityStateChanged(boolean enabled)10840          public void onAccessibilityStateChanged(boolean enabled) {
10841              if (enabled) {
10842                  ensureConnection();
10843                  setAccessibilityWindowAttributesIfNeeded();
10844                  if (mAttachInfo.mHasWindowFocus && (mView != null)) {
10845                      mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
10846                      View focusedView = mView.findFocus();
10847                      if (focusedView != null && focusedView != mView) {
10848                          focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
10849                      }
10850                  }
10851                  if (mAttachInfo.mLeashedParentToken != null) {
10852                      mAccessibilityManager.associateEmbeddedHierarchy(
10853                              mAttachInfo.mLeashedParentToken, mLeashToken);
10854                  }
10855              } else {
10856                  ensureNoConnection();
10857                  mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
10858              }
10859          }
10860  
ensureConnection()10861          public void ensureConnection() {
10862              final boolean registered = mAttachInfo.mAccessibilityWindowId
10863                      != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
10864              if (!registered) {
10865                  mAttachInfo.mAccessibilityWindowId =
10866                          mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
10867                                  mLeashToken,
10868                                  mContext.getPackageName(),
10869                                  new AccessibilityInteractionConnection(ViewRootImpl.this));
10870              }
10871          }
10872  
ensureNoConnection()10873          public void ensureNoConnection() {
10874              final boolean registered = mAttachInfo.mAccessibilityWindowId
10875                      != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
10876              if (registered) {
10877                  mAttachInfo.mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
10878                  mAccessibilityWindowAttributes = null;
10879                  mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
10880              }
10881          }
10882  
ensureDirectConnection()10883          public int ensureDirectConnection() {
10884              if (mDirectConnectionId == AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) {
10885                  mDirectConnectionId = AccessibilityInteractionClient.addDirectConnection(
10886                          new AccessibilityInteractionConnection(ViewRootImpl.this),
10887                          mAccessibilityManager);
10888                  // Notify listeners in the app process.
10889                  mAccessibilityManager.notifyAccessibilityStateChanged();
10890              }
10891              return mDirectConnectionId;
10892          }
10893  
ensureNoDirectConnection()10894          public void ensureNoDirectConnection() {
10895              if (mDirectConnectionId != AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) {
10896                  AccessibilityInteractionClient.removeConnection(mDirectConnectionId);
10897                  mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID;
10898                  // Notify listeners in the app process.
10899                  mAccessibilityManager.notifyAccessibilityStateChanged();
10900              }
10901          }
10902      }
10903  
10904      final class HighContrastTextManager implements HighTextContrastChangeListener {
HighContrastTextManager()10905          HighContrastTextManager() {
10906              ThreadedRenderer.setHighContrastText(mAccessibilityManager.isHighTextContrastEnabled());
10907          }
10908          @Override
onHighTextContrastStateChanged(boolean enabled)10909          public void onHighTextContrastStateChanged(boolean enabled) {
10910              ThreadedRenderer.setHighContrastText(enabled);
10911  
10912              // Destroy Displaylists so they can be recreated with high contrast recordings
10913              destroyHardwareResources();
10914  
10915              // Schedule redraw, which will rerecord + redraw all text
10916              invalidate();
10917          }
10918      }
10919  
10920      /**
10921       * This class is an interface this ViewAncestor provides to the
10922       * AccessibilityManagerService to the latter can interact with
10923       * the view hierarchy in this ViewAncestor.
10924       */
10925      static final class AccessibilityInteractionConnection
10926              extends IAccessibilityInteractionConnection.Stub {
10927          private final WeakReference<ViewRootImpl> mViewRootImpl;
10928  
AccessibilityInteractionConnection(ViewRootImpl viewRootImpl)10929          AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
10930              mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
10931          }
10932  
10933          @Override
findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix, Bundle args)10934          public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
10935                  Region interactiveRegion, int interactionId,
10936                  IAccessibilityInteractionConnectionCallback callback, int flags,
10937                  int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix,
10938                  Bundle args) {
10939              ViewRootImpl viewRootImpl = mViewRootImpl.get();
10940              if (viewRootImpl != null && viewRootImpl.mView != null) {
10941                  viewRootImpl.getAccessibilityInteractionController()
10942                      .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
10943                              interactiveRegion, interactionId, callback, flags, interrogatingPid,
10944                              interrogatingTid, spec, matrix, args);
10945              } else {
10946                  // We cannot make the call and notify the caller so it does not wait.
10947                  try {
10948                      callback.setFindAccessibilityNodeInfosResult(null, interactionId);
10949                  } catch (RemoteException re) {
10950                      /* best effort - ignore */
10951                  }
10952              }
10953          }
10954  
10955          @Override
performAccessibilityAction(long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)10956          public void performAccessibilityAction(long accessibilityNodeId, int action,
10957                  Bundle arguments, int interactionId,
10958                  IAccessibilityInteractionConnectionCallback callback, int flags,
10959                  int interrogatingPid, long interrogatingTid) {
10960              ViewRootImpl viewRootImpl = mViewRootImpl.get();
10961              if (viewRootImpl != null && viewRootImpl.mView != null) {
10962                  viewRootImpl.getAccessibilityInteractionController()
10963                      .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
10964                              interactionId, callback, flags, interrogatingPid, interrogatingTid);
10965              } else {
10966                  // We cannot make the call and notify the caller so it does not wait.
10967                  try {
10968                      callback.setPerformAccessibilityActionResult(false, interactionId);
10969                  } catch (RemoteException re) {
10970                      /* best effort - ignore */
10971                  }
10972              }
10973          }
10974  
10975          @Override
findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)10976          public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
10977                  String viewId, Region interactiveRegion, int interactionId,
10978                  IAccessibilityInteractionConnectionCallback callback, int flags,
10979                  int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
10980                  float[] matrix) {
10981              ViewRootImpl viewRootImpl = mViewRootImpl.get();
10982              if (viewRootImpl != null && viewRootImpl.mView != null) {
10983                  viewRootImpl.getAccessibilityInteractionController()
10984                      .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
10985                              viewId, interactiveRegion, interactionId, callback, flags,
10986                              interrogatingPid, interrogatingTid, spec, matrix);
10987              } else {
10988                  // We cannot make the call and notify the caller so it does not wait.
10989                  try {
10990                      callback.setFindAccessibilityNodeInfoResult(null, interactionId);
10991                  } catch (RemoteException re) {
10992                      /* best effort - ignore */
10993                  }
10994              }
10995          }
10996  
10997          @Override
findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)10998          public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
10999                  Region interactiveRegion, int interactionId,
11000                  IAccessibilityInteractionConnectionCallback callback, int flags,
11001                  int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
11002                  float[] matrix) {
11003              ViewRootImpl viewRootImpl = mViewRootImpl.get();
11004              if (viewRootImpl != null && viewRootImpl.mView != null) {
11005                  viewRootImpl.getAccessibilityInteractionController()
11006                      .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
11007                              interactiveRegion, interactionId, callback, flags, interrogatingPid,
11008                              interrogatingTid, spec, matrix);
11009              } else {
11010                  // We cannot make the call and notify the caller so it does not wait.
11011                  try {
11012                      callback.setFindAccessibilityNodeInfosResult(null, interactionId);
11013                  } catch (RemoteException re) {
11014                      /* best effort - ignore */
11015                  }
11016              }
11017          }
11018  
11019          @Override
findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)11020          public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
11021                  int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
11022                  int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
11023                  float[] matrix) {
11024              ViewRootImpl viewRootImpl = mViewRootImpl.get();
11025              if (viewRootImpl != null && viewRootImpl.mView != null) {
11026                  viewRootImpl.getAccessibilityInteractionController()
11027                      .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
11028                              interactionId, callback, flags, interrogatingPid, interrogatingTid,
11029                              spec, matrix);
11030              } else {
11031                  // We cannot make the call and notify the caller so it does not wait.
11032                  try {
11033                      callback.setFindAccessibilityNodeInfoResult(null, interactionId);
11034                  } catch (RemoteException re) {
11035                      /* best effort - ignore */
11036                  }
11037              }
11038          }
11039  
11040          @Override
focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)11041          public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
11042                  int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
11043                  int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
11044                  float[] matrix) {
11045              ViewRootImpl viewRootImpl = mViewRootImpl.get();
11046              if (viewRootImpl != null && viewRootImpl.mView != null) {
11047                  viewRootImpl.getAccessibilityInteractionController()
11048                      .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
11049                              interactionId, callback, flags, interrogatingPid, interrogatingTid,
11050                              spec, matrix);
11051              } else {
11052                  // We cannot make the call and notify the caller so it does not wait.
11053                  try {
11054                      callback.setFindAccessibilityNodeInfoResult(null, interactionId);
11055                  } catch (RemoteException re) {
11056                      /* best effort - ignore */
11057                  }
11058              }
11059          }
11060  
11061          @Override
clearAccessibilityFocus()11062          public void clearAccessibilityFocus() {
11063              ViewRootImpl viewRootImpl = mViewRootImpl.get();
11064              if (viewRootImpl != null && viewRootImpl.mView != null) {
11065                  viewRootImpl.getAccessibilityInteractionController()
11066                          .clearAccessibilityFocusClientThread();
11067              }
11068          }
11069  
11070          @Override
notifyOutsideTouch()11071          public void notifyOutsideTouch() {
11072              ViewRootImpl viewRootImpl = mViewRootImpl.get();
11073              if (viewRootImpl != null && viewRootImpl.mView != null) {
11074                  viewRootImpl.getAccessibilityInteractionController()
11075                          .notifyOutsideTouchClientThread();
11076              }
11077          }
11078  
11079          @Override
takeScreenshotOfWindow(int interactionId, ScreenCapture.ScreenCaptureListener listener, IAccessibilityInteractionConnectionCallback callback)11080          public void takeScreenshotOfWindow(int interactionId,
11081                  ScreenCapture.ScreenCaptureListener listener,
11082                  IAccessibilityInteractionConnectionCallback callback) {
11083              ViewRootImpl viewRootImpl = mViewRootImpl.get();
11084              if (viewRootImpl != null && viewRootImpl.mView != null) {
11085                  viewRootImpl.getAccessibilityInteractionController()
11086                          .takeScreenshotOfWindowClientThread(interactionId, listener, callback);
11087              } else {
11088                  try {
11089                      callback.sendTakeScreenshotOfWindowError(
11090                              AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR,
11091                              interactionId);
11092                  } catch (RemoteException re) {
11093                      /* best effort - ignore */
11094                  }
11095              }
11096          }
11097  
attachAccessibilityOverlayToWindow(SurfaceControl sc)11098          public void attachAccessibilityOverlayToWindow(SurfaceControl sc) {
11099              ViewRootImpl viewRootImpl = mViewRootImpl.get();
11100              if (viewRootImpl != null) {
11101                  viewRootImpl
11102                          .getAccessibilityInteractionController()
11103                          .attachAccessibilityOverlayToWindowClientThread(sc);
11104              }
11105          }
11106      }
11107  
11108      /**
11109       * Gets an accessibility embedded connection interface for this ViewRootImpl.
11110       * @hide
11111       */
getAccessibilityEmbeddedConnection()11112      public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
11113          if (mAccessibilityEmbeddedConnection == null) {
11114              mAccessibilityEmbeddedConnection = new AccessibilityEmbeddedConnection(
11115                      ViewRootImpl.this);
11116          }
11117          return mAccessibilityEmbeddedConnection;
11118      }
11119  
11120      private class SendWindowContentChangedAccessibilityEvent implements Runnable {
11121          private int mChangeTypes = 0;
11122  
11123          public View mSource;
11124          public long mLastEventTimeMillis;
11125          /**
11126           * Keep track of action that caused the event.
11127           * This is empty if there's no performing actions for pending events.
11128           * This is zero if there're multiple events performed for pending events.
11129           */
11130          @NonNull public OptionalInt mAction = OptionalInt.empty();
11131          /**
11132           * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace
11133           * of the original {@link #runOrPost} call instead of one for sending the delayed event
11134           * from a looper.
11135           */
11136          public StackTraceElement[] mOrigin;
11137  
11138          @Override
run()11139          public void run() {
11140              // Protect against re-entrant code and attempt to do the right thing in the case that
11141              // we're multithreaded.
11142              View source = mSource;
11143              mSource = null;
11144              if (source == null) {
11145                  Log.e(TAG, "Accessibility content change has no source");
11146                  return;
11147              }
11148              // The accessibility may be turned off while we were waiting so check again.
11149              if (AccessibilityManager.getInstance(mContext).isEnabled()) {
11150                  mLastEventTimeMillis = SystemClock.uptimeMillis();
11151                  AccessibilityEvent event = AccessibilityEvent.obtain();
11152                  event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
11153                  event.setContentChangeTypes(mChangeTypes);
11154                  if (mAction.isPresent()) event.setAction(mAction.getAsInt());
11155                  if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin;
11156                  source.sendAccessibilityEventUnchecked(event);
11157              } else {
11158                  mLastEventTimeMillis = 0;
11159              }
11160              // In any case reset to initial state.
11161              source.resetSubtreeAccessibilityStateChanged();
11162              mChangeTypes = 0;
11163              mAction = OptionalInt.empty();
11164              if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null;
11165          }
11166  
runOrPost(View source, int changeType)11167          public void runOrPost(View source, int changeType) {
11168              if (mHandler.getLooper() != Looper.myLooper()) {
11169                  CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the "
11170                          + "original thread that created a view hierarchy can touch its views.");
11171                  // TODO: Throw the exception
11172                  Log.e(TAG, "Accessibility content change on non-UI thread. Future Android "
11173                          + "versions will throw an exception.", e);
11174                  // Attempt to recover. This code does not eliminate the thread safety issue, but
11175                  // it should force any issues to happen near the above log.
11176                  mHandler.removeCallbacks(this);
11177                  if (mSource != null) {
11178                      // Dispatch whatever was pending. It's still possible that the runnable started
11179                      // just before we removed the callbacks, and bad things will happen, but at
11180                      // least they should happen very close to the logged error.
11181                      run();
11182                  }
11183              }
11184              if (mSource != null) {
11185                  // If there is no common predecessor, then mSource points to
11186                  // a removed view, hence in this case always prefer the source.
11187                  View predecessor = getCommonPredecessor(mSource, source);
11188                  if (predecessor != null) {
11189                      predecessor = predecessor.getSelfOrParentImportantForA11y();
11190                  }
11191                  mSource = (predecessor != null) ? predecessor : source;
11192                  mChangeTypes |= changeType;
11193  
11194                  final int performingAction = mAccessibilityManager.getPerformingAction();
11195                  if (performingAction != 0) {
11196                      if (mAction.isEmpty()) {
11197                          mAction = OptionalInt.of(performingAction);
11198                      } else if (mAction.getAsInt() != performingAction) {
11199                          // Multiple actions are performed for pending events. We cannot decide one
11200                          // action here.
11201                          // We're doing best effort to set action value, and it's fine to set
11202                          // no action this case.
11203                          mAction = OptionalInt.of(0);
11204                      }
11205                  }
11206  
11207                  return;
11208              }
11209              mSource = source;
11210              mChangeTypes = changeType;
11211              if (mAccessibilityManager.getPerformingAction() != 0) {
11212                  mAction = OptionalInt.of(mAccessibilityManager.getPerformingAction());
11213              }
11214              if (AccessibilityEvent.DEBUG_ORIGIN) {
11215                  mOrigin = Thread.currentThread().getStackTrace();
11216              }
11217              final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
11218              final long minEventIntevalMillis =
11219                      ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
11220              if (timeSinceLastMillis >= minEventIntevalMillis) {
11221                  removeCallbacksAndRun();
11222              } else {
11223                  mHandler.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
11224              }
11225          }
11226  
removeCallbacksAndRun()11227          public void removeCallbacksAndRun() {
11228              mHandler.removeCallbacks(this);
11229              run();
11230          }
11231      }
11232  
11233      private static class UnhandledKeyManager {
11234          // This is used to ensure that unhandled events are only dispatched once. We attempt
11235          // to dispatch more than once in order to achieve a certain order. Specifically, if we
11236          // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should
11237          // be dispatched after the view hierarchy, but before the Callback. However, if we aren't
11238          // in an activity, we still want unhandled keys to be dispatched.
11239          private boolean mDispatched = true;
11240  
11241          // Keeps track of which Views have unhandled key focus for which keys. This doesn't
11242          // include modifiers.
11243          private final SparseArray<WeakReference<View>> mCapturedKeys = new SparseArray<>();
11244  
11245          // The current receiver. This value is transient and used between the pre-dispatch and
11246          // pre-view phase to ensure that other input-stages don't interfere with tracking.
11247          private WeakReference<View> mCurrentReceiver = null;
11248  
dispatch(View root, KeyEvent event)11249          boolean dispatch(View root, KeyEvent event) {
11250              if (mDispatched) {
11251                  return false;
11252              }
11253              View consumer;
11254              try {
11255                  Trace.traceBegin(Trace.TRACE_TAG_VIEW, "UnhandledKeyEvent dispatch");
11256                  mDispatched = true;
11257  
11258                  consumer = root.dispatchUnhandledKeyEvent(event);
11259  
11260                  // If an unhandled listener handles one, then keep track of it so that the
11261                  // consuming view is first to receive its repeats and release as well.
11262                  if (event.getAction() == KeyEvent.ACTION_DOWN) {
11263                      int keycode = event.getKeyCode();
11264                      if (consumer != null && !KeyEvent.isModifierKey(keycode)) {
11265                          mCapturedKeys.put(keycode, new WeakReference<>(consumer));
11266                      }
11267                  }
11268              } finally {
11269                  Trace.traceEnd(Trace.TRACE_TAG_VIEW);
11270              }
11271              return consumer != null;
11272          }
11273  
11274          /**
11275           * Called before the event gets dispatched to anything
11276           */
preDispatch(KeyEvent event)11277          void preDispatch(KeyEvent event) {
11278              // Always clean-up 'up' events since it's possible for earlier dispatch stages to
11279              // consume them without consuming the corresponding 'down' event.
11280              mCurrentReceiver = null;
11281              if (event.getAction() == KeyEvent.ACTION_UP) {
11282                  int idx = mCapturedKeys.indexOfKey(event.getKeyCode());
11283                  if (idx >= 0) {
11284                      mCurrentReceiver = mCapturedKeys.valueAt(idx);
11285                      mCapturedKeys.removeAt(idx);
11286                  }
11287              }
11288          }
11289  
11290          /**
11291           * Called before the event gets dispatched to the view hierarchy
11292           * @return {@code true} if an unhandled handler has focus and consumed the event
11293           */
preViewDispatch(KeyEvent event)11294          boolean preViewDispatch(KeyEvent event) {
11295              mDispatched = false;
11296              if (mCurrentReceiver == null) {
11297                  mCurrentReceiver = mCapturedKeys.get(event.getKeyCode());
11298              }
11299              if (mCurrentReceiver != null) {
11300                  View target = mCurrentReceiver.get();
11301                  if (event.getAction() == KeyEvent.ACTION_UP) {
11302                      mCurrentReceiver = null;
11303                  }
11304                  if (target != null && target.isAttachedToWindow()) {
11305                      target.onUnhandledKeyEvent(event);
11306                  }
11307                  // consume anyways so that we don't feed uncaptured key events to other views
11308                  return true;
11309              }
11310              return false;
11311          }
11312      }
11313  
11314      /**
11315       * @hide
11316       */
setDisplayDecoration(boolean displayDecoration)11317      public void setDisplayDecoration(boolean displayDecoration) {
11318          if (displayDecoration == mDisplayDecorationCached) return;
11319  
11320          mDisplayDecorationCached = displayDecoration;
11321  
11322          if (mSurfaceControl.isValid()) {
11323              updateDisplayDecoration();
11324          }
11325      }
11326  
updateDisplayDecoration()11327      private void updateDisplayDecoration() {
11328          mTransaction.setDisplayDecoration(mSurfaceControl, mDisplayDecorationCached).apply();
11329      }
11330  
11331      /**
11332       * Sends a list of blur regions to SurfaceFlinger, tagged with a frame.
11333       *
11334       * @param regionCopy List of regions
11335       * @param frameNumber Frame where it should be applied (or current when using BLAST)
11336       */
dispatchBlurRegions(float[][] regionCopy, long frameNumber)11337      public void dispatchBlurRegions(float[][] regionCopy, long frameNumber) {
11338          final SurfaceControl surfaceControl = getSurfaceControl();
11339          if (!surfaceControl.isValid()) {
11340              return;
11341          }
11342  
11343          SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
11344          transaction.setBlurRegions(surfaceControl, regionCopy);
11345  
11346          if (useBLAST() && mBlastBufferQueue != null) {
11347              mBlastBufferQueue.mergeWithNextTransaction(transaction, frameNumber);
11348          }
11349      }
11350  
11351      /**
11352       * Creates a background blur drawable for the backing {@link Surface}.
11353       */
createBackgroundBlurDrawable()11354      public BackgroundBlurDrawable createBackgroundBlurDrawable() {
11355          return mBlurRegionAggregator.createBackgroundBlurDrawable(mContext);
11356      }
11357  
11358      @Override
onDescendantUnbufferedRequested()11359      public void onDescendantUnbufferedRequested() {
11360          mUnbufferedInputSource = mView.mUnbufferedInputSource;
11361      }
11362  
11363      /**
11364       * Force disabling use of the BLAST adapter regardless of the system
11365       * flag. Needs to be called before addView.
11366       */
forceDisableBLAST()11367      void forceDisableBLAST() {
11368          mForceDisableBLAST = true;
11369      }
11370  
useBLAST()11371      boolean useBLAST() {
11372          return mUseBLASTAdapter && !mForceDisableBLAST;
11373      }
11374  
getSurfaceSequenceId()11375      int getSurfaceSequenceId() {
11376          return mSurfaceSequenceId;
11377      }
11378  
11379      /**
11380       * Merges the transaction passed in with the next transaction in BLASTBufferQueue. This ensures
11381       * you can add transactions to the upcoming frame.
11382       */
mergeWithNextTransaction(Transaction t, long frameNumber)11383      public void mergeWithNextTransaction(Transaction t, long frameNumber) {
11384          if (mBlastBufferQueue != null) {
11385              mBlastBufferQueue.mergeWithNextTransaction(t, frameNumber);
11386          } else {
11387              t.apply();
11388          }
11389      }
11390  
11391      @Override
buildReparentTransaction( @onNull SurfaceControl child)11392      @Nullable public SurfaceControl.Transaction buildReparentTransaction(
11393          @NonNull SurfaceControl child) {
11394          if (mSurfaceControl.isValid()) {
11395              Transaction t = new Transaction();
11396              return t.reparent(child, updateAndGetBoundsLayer(t));
11397          }
11398          return null;
11399      }
11400  
11401      @Override
applyTransactionOnDraw(@onNull SurfaceControl.Transaction t)11402      public boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t) {
11403          if (mRemoved || !isHardwareEnabled()) {
11404              t.apply();
11405          } else {
11406              // Copy and clear the passed in transaction for thread safety. The new transaction is
11407              // accessed on the render thread.
11408              mPendingTransaction.merge(t);
11409              mHasPendingTransactions = true;
11410              // Schedule the traversal to ensure there's an attempt to draw a frame and apply the
11411              // pending transactions. This is also where the registerFrameCallback will be scheduled.
11412              scheduleTraversals();
11413          }
11414          return true;
11415      }
11416  
11417      @Override
getBufferTransformHint()11418      public @SurfaceControl.BufferTransform int getBufferTransformHint() {
11419          return mSurfaceControl.getTransformHint();
11420      }
11421  
11422      @Override
addOnBufferTransformHintChangedListener( OnBufferTransformHintChangedListener listener)11423      public void addOnBufferTransformHintChangedListener(
11424              OnBufferTransformHintChangedListener listener) {
11425          Objects.requireNonNull(listener);
11426          if (mTransformHintListeners.contains(listener)) {
11427              throw new IllegalArgumentException(
11428                      "attempt to call addOnBufferTransformHintChangedListener() "
11429                              + "with a previously registered listener");
11430          }
11431          mTransformHintListeners.add(listener);
11432      }
11433  
11434      @Override
removeOnBufferTransformHintChangedListener( OnBufferTransformHintChangedListener listener)11435      public void removeOnBufferTransformHintChangedListener(
11436              OnBufferTransformHintChangedListener listener) {
11437          Objects.requireNonNull(listener);
11438          mTransformHintListeners.remove(listener);
11439      }
11440  
dispatchTransformHintChanged(@urfaceControl.BufferTransform int hint)11441      private void dispatchTransformHintChanged(@SurfaceControl.BufferTransform int hint) {
11442          if (mTransformHintListeners.isEmpty()) {
11443              return;
11444          }
11445          ArrayList<OnBufferTransformHintChangedListener> listeners =
11446                  (ArrayList<OnBufferTransformHintChangedListener>) mTransformHintListeners.clone();
11447          for (int i = 0; i < listeners.size(); i++) {
11448              OnBufferTransformHintChangedListener listener = listeners.get(i);
11449              listener.onBufferTransformHintChanged(hint);
11450          }
11451      }
11452  
11453      /**
11454       * Shows or hides a Camera app compat toggle for stretched issues with the requested state
11455       * for the corresponding activity.
11456       *
11457       * @param showControl Whether the control should be shown or hidden.
11458       * @param transformationApplied Whether the treatment is already applied.
11459       * @param callback The callback executed when the user clicks on a control.
11460      */
requestCompatCameraControl(boolean showControl, boolean transformationApplied, ICompatCameraControlCallback callback)11461      public void requestCompatCameraControl(boolean showControl, boolean transformationApplied,
11462                  ICompatCameraControlCallback callback) {
11463          mActivityConfigCallback.requestCompatCameraControl(
11464                  showControl, transformationApplied, callback);
11465      }
11466  
wasRelayoutRequested()11467      boolean wasRelayoutRequested() {
11468          return mRelayoutRequested;
11469      }
11470  
forceWmRelayout()11471      void forceWmRelayout() {
11472         mForceNextWindowRelayout = true;
11473         scheduleTraversals();
11474      }
11475  
11476      /**
11477       * Returns the {@link OnBackInvokedDispatcher} on the decor view if one exists, or the
11478       * fallback {@link OnBackInvokedDispatcher} instance.
11479       */
11480      @NonNull
getOnBackInvokedDispatcher()11481      public WindowOnBackInvokedDispatcher getOnBackInvokedDispatcher() {
11482          return mOnBackInvokedDispatcher;
11483      }
11484  
11485      @NonNull
11486      @Override
findOnBackInvokedDispatcherForChild( @onNull View child, @NonNull View requester)11487      public OnBackInvokedDispatcher findOnBackInvokedDispatcherForChild(
11488              @NonNull View child, @NonNull View requester) {
11489          return getOnBackInvokedDispatcher();
11490      }
11491  
11492      /**
11493       * When this ViewRootImpl is added to the window manager, transfers the first
11494       * {@link OnBackInvokedCallback} to be called to the server.
11495       */
registerBackCallbackOnWindow()11496      private void registerBackCallbackOnWindow() {
11497          if (OnBackInvokedDispatcher.DEBUG) {
11498              Log.d(OnBackInvokedDispatcher.TAG, TextUtils.formatSimple(
11499                      "ViewRootImpl.registerBackCallbackOnWindow. Dispatcher:%s Package:%s "
11500                              + "IWindow:%s Session:%s",
11501                      mOnBackInvokedDispatcher, mBasePackageName, mWindow, mWindowSession));
11502          }
11503          mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow);
11504      }
11505  
sendBackKeyEvent(int action)11506      private void sendBackKeyEvent(int action) {
11507          long when = SystemClock.uptimeMillis();
11508          final KeyEvent ev = new KeyEvent(when, when, action,
11509                  KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
11510                  KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
11511                  KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
11512                  InputDevice.SOURCE_KEYBOARD);
11513          enqueueInputEvent(ev);
11514      }
11515  
registerCompatOnBackInvokedCallback()11516      private void registerCompatOnBackInvokedCallback() {
11517          mCompatOnBackInvokedCallback = () -> {
11518              sendBackKeyEvent(KeyEvent.ACTION_DOWN);
11519              sendBackKeyEvent(KeyEvent.ACTION_UP);
11520          };
11521          if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) {
11522              Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher");
11523              return;
11524          }
11525          mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
11526                  OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatOnBackInvokedCallback);
11527      }
11528  
11529      @Override
setTouchableRegion(Region r)11530      public void setTouchableRegion(Region r) {
11531          if (r != null) {
11532              mTouchableRegion = new Region(r);
11533          } else {
11534              mTouchableRegion = null;
11535          }
11536          mLastGivenInsets.reset();
11537          requestLayout();
11538      }
11539  
getWindowSession()11540      IWindowSession getWindowSession() {
11541          return mWindowSession;
11542      }
11543  
registerCallbacksForSync(boolean syncBuffer, final SurfaceSyncGroup surfaceSyncGroup)11544      private void registerCallbacksForSync(boolean syncBuffer,
11545              final SurfaceSyncGroup surfaceSyncGroup) {
11546          if (!isHardwareEnabled()) {
11547              return;
11548          }
11549  
11550          if (DEBUG_BLAST) {
11551              Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer);
11552          }
11553  
11554          Transaction t = new Transaction();
11555          t.merge(mPendingTransaction);
11556  
11557          mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
11558              @Override
11559              public void onFrameDraw(long frame) {
11560              }
11561  
11562              @Override
11563              public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
11564                  if (DEBUG_BLAST) {
11565                      Log.d(mTag,
11566                              "Received frameDrawingCallback syncResult=" + syncResult + " frameNum="
11567                                      + frame + ".");
11568                  }
11569  
11570                  mergeWithNextTransaction(t, frame);
11571                  // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
11572                  // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
11573                  // any blast sync or commit callback, and the code should directly call
11574                  // pendingDrawFinished.
11575                  if ((syncResult
11576                          & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
11577                      surfaceSyncGroup.addTransaction(
11578                              mBlastBufferQueue.gatherPendingTransactions(frame));
11579                      surfaceSyncGroup.markSyncReady();
11580                      return null;
11581                  }
11582  
11583                  if (DEBUG_BLAST) {
11584                      Log.d(mTag, "Setting up sync and frameCommitCallback");
11585                  }
11586  
11587                  if (syncBuffer) {
11588                      boolean result = mBlastBufferQueue.syncNextTransaction(transaction -> {
11589                          surfaceSyncGroup.addTransaction(transaction);
11590                          surfaceSyncGroup.markSyncReady();
11591                      });
11592                      if (!result) {
11593                          // syncNextTransaction can only return false if something is already trying
11594                          // to sync the same frame in the same BBQ. That shouldn't be possible, but
11595                          // if it did happen, invoke markSyncReady so the active SSG doesn't get
11596                          // stuck.
11597                          Log.w(mTag, "Unable to syncNextTransaction. Possibly something else is"
11598                                  + " trying to sync?");
11599                          surfaceSyncGroup.markSyncReady();
11600                      }
11601                  }
11602  
11603                  return didProduceBuffer -> {
11604                      if (DEBUG_BLAST) {
11605                          Log.d(mTag, "Received frameCommittedCallback"
11606                                  + " lastAttemptedDrawFrameNum=" + frame
11607                                  + " didProduceBuffer=" + didProduceBuffer);
11608                      }
11609  
11610                      // If frame wasn't drawn, clear out the next transaction so it doesn't affect
11611                      // the next draw attempt. The next transaction and transaction complete callback
11612                      // were only set for the current draw attempt.
11613                      if (!didProduceBuffer) {
11614                          mBlastBufferQueue.clearSyncTransaction();
11615  
11616                          // Gather the transactions that were sent to mergeWithNextTransaction
11617                          // since the frame didn't draw on this vsync. It's possible the frame will
11618                          // draw later, but it's better to not be sync than to block on a frame that
11619                          // may never come.
11620                          surfaceSyncGroup.addTransaction(
11621                                  mBlastBufferQueue.gatherPendingTransactions(frame));
11622                          surfaceSyncGroup.markSyncReady();
11623                          return;
11624                      }
11625  
11626                      // If we didn't request to sync a buffer, then we won't get the
11627                      // syncNextTransaction callback. Instead, just report back to the Syncer so it
11628                      // knows that this sync request is complete.
11629                      if (!syncBuffer) {
11630                          surfaceSyncGroup.markSyncReady();
11631                      }
11632                  };
11633              }
11634          });
11635      }
11636  
11637      /**
11638       * This code will ensure that if multiple SurfaceSyncGroups are created for the same
11639       * ViewRootImpl the SurfaceSyncGroups will maintain an order. The scenario that could occur
11640       * is the following:
11641       * <p>
11642       * 1. SSG1 is created that includes the target VRI. There could be other VRIs in SSG1
11643       * 2. The target VRI draws its frame and marks its own active SSG as ready, but SSG1 is still
11644       *    waiting on other things in the SSG
11645       * 3. Another SSG2 is created for the target VRI. The second frame renders and marks its own
11646       *    second SSG as complete. SSG2 has nothing else to wait on, so it will apply at this point,
11647       *    even though SSG1 has not finished.
11648       * 4. Frame2 will get to SF first and Frame1 will later get to SF when SSG1 completes.
11649       * <p>
11650       * The code below ensures the SSGs that contains the VRI maintain an order. We create a new SSG
11651       * that's a safeguard SSG. Its only job is to prevent the next active SSG from completing.
11652       * The current active SSG for VRI will add a transaction committed callback and when that's
11653       * invoked, it will mark the safeguard SSG as ready. If a new request to create a SSG comes
11654       * in and the safeguard SSG is not null, it's added as part of the new active SSG. A new
11655       * safeguard SSG is created to correspond to the new active SSG. This creates a chain to
11656       * ensure the latter SSG always waits for the former SSG's transaction to get to SF.
11657       */
safeguardOverlappingSyncs(SurfaceSyncGroup activeSurfaceSyncGroup)11658      private void safeguardOverlappingSyncs(SurfaceSyncGroup activeSurfaceSyncGroup) {
11659          SurfaceSyncGroup safeguardSsg = new SurfaceSyncGroup("Safeguard-" + mTag);
11660          // Always disable timeout on the safeguard sync
11661          safeguardSsg.toggleTimeout(false /* enable */);
11662          synchronized (mPreviousSyncSafeguardLock) {
11663              if (mPreviousSyncSafeguard != null) {
11664                  activeSurfaceSyncGroup.add(mPreviousSyncSafeguard, null /* runnable */);
11665                  // Temporarily disable the timeout on the SSG that will contain the buffer. This
11666                  // is to ensure we don't timeout the active SSG before the previous one completes to
11667                  // ensure the order is maintained. The previous SSG has a timeout on its own SSG
11668                  // so it's guaranteed to complete.
11669                  activeSurfaceSyncGroup.toggleTimeout(false /* enable */);
11670                  mPreviousSyncSafeguard.addSyncCompleteCallback(mSimpleExecutor, () -> {
11671                      // Once we receive that the previous sync guard has been invoked, we can re-add
11672                      // the timeout on the active sync to ensure we eventually complete so it's not
11673                      // stuck permanently.
11674                      activeSurfaceSyncGroup.toggleTimeout(true /*enable */);
11675                  });
11676              }
11677              mPreviousSyncSafeguard = safeguardSsg;
11678          }
11679  
11680          Transaction t = new Transaction();
11681          t.addTransactionCommittedListener(mSimpleExecutor, () -> {
11682              safeguardSsg.markSyncReady();
11683              synchronized (mPreviousSyncSafeguardLock) {
11684                  if (mPreviousSyncSafeguard == safeguardSsg) {
11685                      mPreviousSyncSafeguard = null;
11686                  }
11687              }
11688          });
11689          activeSurfaceSyncGroup.addTransaction(t);
11690      }
11691  
11692      @Override
getOrCreateSurfaceSyncGroup()11693      public SurfaceSyncGroup getOrCreateSurfaceSyncGroup() {
11694          boolean newSyncGroup = false;
11695          if (mActiveSurfaceSyncGroup == null) {
11696              mActiveSurfaceSyncGroup = new SurfaceSyncGroup(mTag);
11697              mActiveSurfaceSyncGroup.setAddedToSyncListener(() -> {
11698                  Runnable runnable = () -> {
11699                      // Check if it's already 0 because the timeout could have reset the count to
11700                      // 0 and we don't want to go negative.
11701                      if (mNumPausedForSync > 0) {
11702                          mNumPausedForSync--;
11703                      }
11704                      if (mNumPausedForSync == 0) {
11705                          mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
11706                          if (!mIsInTraversal) {
11707                              scheduleTraversals();
11708                          }
11709                      }
11710                  };
11711  
11712                  if (Thread.currentThread() == mThread) {
11713                      runnable.run();
11714                  } else {
11715                      mHandler.post(runnable);
11716                  }
11717              });
11718              newSyncGroup = true;
11719          }
11720  
11721          Trace.instant(Trace.TRACE_TAG_VIEW,
11722                  "getOrCreateSurfaceSyncGroup isNew=" + newSyncGroup + " " + mTag);
11723  
11724          if (DEBUG_BLAST) {
11725              if (newSyncGroup) {
11726                  Log.d(mTag, "Creating new active sync group " + mActiveSurfaceSyncGroup.getName());
11727              } else {
11728                  Log.d(mTag, "Return already created active sync group "
11729                          + mActiveSurfaceSyncGroup.getName());
11730              }
11731          }
11732  
11733          mNumPausedForSync++;
11734          mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
11735          mHandler.sendEmptyMessageDelayed(MSG_PAUSED_FOR_SYNC_TIMEOUT,
11736                  1000 * Build.HW_TIMEOUT_MULTIPLIER);
11737          return mActiveSurfaceSyncGroup;
11738      };
11739  
11740      private final Executor mSimpleExecutor = Runnable::run;
11741  
updateSyncInProgressCount(SurfaceSyncGroup syncGroup)11742      private void updateSyncInProgressCount(SurfaceSyncGroup syncGroup) {
11743          if (mAttachInfo.mThreadedRenderer == null) {
11744              return;
11745          }
11746  
11747          synchronized (sSyncProgressLock) {
11748              if (sNumSyncsInProgress++ == 0) {
11749                  HardwareRenderer.setRtAnimationsEnabled(false);
11750              }
11751          }
11752  
11753          syncGroup.addSyncCompleteCallback(mSimpleExecutor, () -> {
11754              synchronized (sSyncProgressLock) {
11755                  if (--sNumSyncsInProgress == 0) {
11756                      HardwareRenderer.setRtAnimationsEnabled(true);
11757                  }
11758              }
11759          });
11760      }
11761  
addToSync(SurfaceSyncGroup syncable)11762      void addToSync(SurfaceSyncGroup syncable) {
11763          if (mActiveSurfaceSyncGroup == null) {
11764              return;
11765          }
11766          mActiveSurfaceSyncGroup.add(syncable, null /* Runnable */);
11767      }
11768  
11769      @Override
setChildBoundingInsets(@onNull Rect insets)11770      public void setChildBoundingInsets(@NonNull Rect insets) {
11771          if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) {
11772              throw new IllegalArgumentException("Negative insets passed to setChildBoundingInsets.");
11773          }
11774          mChildBoundingInsets.set(insets);
11775          mChildBoundingInsetsChanged = true;
11776          scheduleTraversals();
11777      }
11778  
11779      @Override
addTrustedPresentationCallback(@onNull SurfaceControl.Transaction t, @NonNull SurfaceControl.TrustedPresentationThresholds thresholds, @NonNull Executor executor, @NonNull Consumer<Boolean> listener)11780      public void addTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t,
11781              @NonNull SurfaceControl.TrustedPresentationThresholds thresholds,
11782              @NonNull Executor executor, @NonNull Consumer<Boolean> listener) {
11783          t.setTrustedPresentationCallback(getSurfaceControl(), thresholds, executor, listener);
11784      }
11785  
11786      @Override
removeTrustedPresentationCallback(@onNull SurfaceControl.Transaction t, @NonNull Consumer<Boolean> listener)11787      public void removeTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t,
11788              @NonNull Consumer<Boolean> listener) {
11789          t.clearTrustedPresentationCallback(getSurfaceControl());
11790      }
11791  }
11792