• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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