• 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.adpf.Flags.adpfViewrootimplActionDownBoost;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
22 import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS;
23 import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED;
24 import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND;
25 import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID;
26 import static android.os.Trace.TRACE_TAG_VIEW;
27 import static android.util.SequenceUtils.getInitSeq;
28 import static android.util.SequenceUtils.isIncomingSeqStale;
29 import static android.view.Display.DEFAULT_DISPLAY;
30 import static android.view.Display.INVALID_DISPLAY;
31 import static android.view.DragEvent.ACTION_DRAG_LOCATION;
32 import static android.view.InputDevice.SOURCE_CLASS_NONE;
33 import static android.view.InsetsSource.ID_IME;
34 import static android.view.Surface.FRAME_RATE_CATEGORY_DEFAULT;
35 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
36 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT;
37 import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
38 import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
39 import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
40 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
41 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST;
42 import static android.view.View.FRAME_RATE_CATEGORY_REASON_BOOST;
43 import static android.view.View.FRAME_RATE_CATEGORY_REASON_CONFLICTED;
44 import static android.view.View.FRAME_RATE_CATEGORY_REASON_INTERMITTENT;
45 import static android.view.View.FRAME_RATE_CATEGORY_REASON_INVALID;
46 import static android.view.View.FRAME_RATE_CATEGORY_REASON_LARGE;
47 import static android.view.View.FRAME_RATE_CATEGORY_REASON_REQUESTED;
48 import static android.view.View.FRAME_RATE_CATEGORY_REASON_SMALL;
49 import static android.view.View.FRAME_RATE_CATEGORY_REASON_TOUCH;
50 import static android.view.View.FRAME_RATE_CATEGORY_REASON_UNKNOWN;
51 import static android.view.View.FRAME_RATE_CATEGORY_REASON_VELOCITY;
52 import static android.view.View.MAX_FRAME_RATE;
53 import static android.view.View.PFLAG_DRAW_ANIMATION;
54 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
55 import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
56 import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
57 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
58 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
59 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
60 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
61 import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
62 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
63 import static android.view.ViewRootImplProto.ADDED;
64 import static android.view.ViewRootImplProto.APP_VISIBLE;
65 import static android.view.ViewRootImplProto.CUR_SCROLL_Y;
66 import static android.view.ViewRootImplProto.DISPLAY_ID;
67 import static android.view.ViewRootImplProto.HEIGHT;
68 import static android.view.ViewRootImplProto.IS_ANIMATING;
69 import static android.view.ViewRootImplProto.IS_DRAWING;
70 import static android.view.ViewRootImplProto.LAST_WINDOW_INSETS;
71 import static android.view.ViewRootImplProto.REMOVED;
72 import static android.view.ViewRootImplProto.SCROLL_Y;
73 import static android.view.ViewRootImplProto.SOFT_INPUT_MODE;
74 import static android.view.ViewRootImplProto.VIEW;
75 import static android.view.ViewRootImplProto.VISIBLE_RECT;
76 import static android.view.ViewRootImplProto.WIDTH;
77 import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
78 import static android.view.ViewRootImplProto.WIN_FRAME;
79 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
80 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
81 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
82 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
83 import static android.view.WindowInsetsController.Appearance;
84 import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
85 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
86 import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
87 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
88 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
89 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
90 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
91 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
92 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
93 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
94 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
95 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED;
96 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED;
97 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
98 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
99 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
100 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
101 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
102 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE;
103 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
104 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
105 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
106 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
107 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
108 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
109 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
110 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
111 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS;
112 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
113 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
114 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
115 import static android.view.accessibility.Flags.forceInvertColor;
116 import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle;
117 import static android.view.flags.Flags.addSchandleToVriSurface;
118 import static android.view.flags.Flags.disableDrawWakeLock;
119 import static android.view.flags.Flags.sensitiveContentAppProtection;
120 import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix;
121 import static android.view.flags.Flags.toolkitFrameRateDebug;
122 import static android.view.flags.Flags.toolkitFrameRateFunctionEnablingReadOnly;
123 import static android.view.flags.Flags.toolkitFrameRateTouchBoost25q1;
124 import static android.view.flags.Flags.toolkitFrameRateTypingReadOnly;
125 import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly;
126 import static android.view.flags.Flags.toolkitFrameRateViewEnablingReadOnly;
127 import static android.view.flags.Flags.toolkitInitialTouchBoost;
128 import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
129 import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
130 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
131 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
132 import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
133 
134 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
135 import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
136 import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
137 import static com.android.window.flags.Flags.enableWindowContextResourcesUpdateOnConfigChange;
138 import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi;
139 import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs;
140 import static com.android.window.flags.Flags.setScPropertiesInClient;
141 import static com.android.window.flags.Flags.fixViewRootCallTrace;
142 
143 import android.Manifest;
144 import android.accessibilityservice.AccessibilityService;
145 import android.animation.AnimationHandler;
146 import android.animation.LayoutTransition;
147 import android.annotation.AnyThread;
148 import android.annotation.CallbackExecutor;
149 import android.annotation.FlaggedApi;
150 import android.annotation.NonNull;
151 import android.annotation.Nullable;
152 import android.annotation.Size;
153 import android.annotation.UiContext;
154 import android.app.ActivityManager;
155 import android.app.ActivityThread;
156 import android.app.ResourcesManager;
157 import android.app.UiModeManager;
158 import android.app.WindowConfiguration;
159 import android.app.compat.CompatChanges;
160 import android.app.servertransaction.WindowStateTransactionItem;
161 import android.compat.annotation.ChangeId;
162 import android.compat.annotation.EnabledSince;
163 import android.compat.annotation.UnsupportedAppUsage;
164 import android.content.ClipData;
165 import android.content.ClipDescription;
166 import android.content.Context;
167 import android.content.pm.ActivityInfo;
168 import android.content.pm.PackageManager;
169 import android.content.res.CompatibilityInfo;
170 import android.content.res.Configuration;
171 import android.content.res.Resources;
172 import android.content.res.TypedArray;
173 import android.database.ContentObserver;
174 import android.graphics.BLASTBufferQueue;
175 import android.graphics.Canvas;
176 import android.graphics.Color;
177 import android.graphics.ForceDarkType;
178 import android.graphics.FrameInfo;
179 import android.graphics.HardwareRenderer;
180 import android.graphics.HardwareRenderer.FrameDrawingCallback;
181 import android.graphics.HardwareRendererObserver;
182 import android.graphics.Matrix;
183 import android.graphics.Paint;
184 import android.graphics.PixelFormat;
185 import android.graphics.Point;
186 import android.graphics.PointF;
187 import android.graphics.PorterDuff;
188 import android.graphics.RecordingCanvas;
189 import android.graphics.Rect;
190 import android.graphics.RectF;
191 import android.graphics.Region;
192 import android.graphics.RenderNode;
193 import android.graphics.drawable.ColorDrawable;
194 import android.graphics.drawable.Drawable;
195 import android.graphics.drawable.GradientDrawable;
196 import android.hardware.SyncFence;
197 import android.hardware.display.DisplayManager.DisplayListener;
198 import android.hardware.display.DisplayManagerGlobal;
199 import android.hardware.input.InputManagerGlobal;
200 import android.hardware.input.InputSettings;
201 import android.media.AudioManager;
202 import android.net.Uri;
203 import android.os.Binder;
204 import android.os.Build;
205 import android.os.Bundle;
206 import android.os.Debug;
207 import android.os.Handler;
208 import android.os.IBinder;
209 import android.os.Looper;
210 import android.os.Message;
211 import android.os.ParcelFileDescriptor;
212 import android.os.Process;
213 import android.os.RemoteException;
214 import android.os.ServiceManager;
215 import android.os.StrictMode;
216 import android.os.SystemClock;
217 import android.os.SystemProperties;
218 import android.os.Trace;
219 import android.os.UserHandle;
220 import android.os.Vibrator;
221 import android.provider.Settings;
222 import android.sysprop.DisplayProperties;
223 import android.sysprop.ViewProperties;
224 import android.text.TextUtils;
225 import android.util.AndroidRuntimeException;
226 import android.util.DisplayMetrics;
227 import android.util.EventLog;
228 import android.util.IndentingPrintWriter;
229 import android.util.Log;
230 import android.util.LongArray;
231 import android.util.MergedConfiguration;
232 import android.util.Slog;
233 import android.util.SparseArray;
234 import android.util.TimeUtils;
235 import android.util.TypedValue;
236 import android.util.proto.ProtoOutputStream;
237 import android.view.InputDevice.InputSourceClass;
238 import android.view.Surface.OutOfResourcesException;
239 import android.view.SurfaceControl.Transaction;
240 import android.view.SurfaceControl.TransactionStats;
241 import android.view.View.AttachInfo;
242 import android.view.View.FocusDirection;
243 import android.view.View.MeasureSpec;
244 import android.view.Window.OnContentApplyWindowInsetsListener;
245 import android.view.WindowInsets.Type;
246 import android.view.WindowInsets.Type.InsetsType;
247 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
248 import android.view.accessibility.AccessibilityEvent;
249 import android.view.accessibility.AccessibilityInteractionClient;
250 import android.view.accessibility.AccessibilityManager;
251 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
252 import android.view.accessibility.AccessibilityManager.HighContrastTextStateChangeListener;
253 import android.view.accessibility.AccessibilityNodeIdManager;
254 import android.view.accessibility.AccessibilityNodeInfo;
255 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
256 import android.view.accessibility.AccessibilityNodeProvider;
257 import android.view.accessibility.AccessibilityWindowAttributes;
258 import android.view.accessibility.AccessibilityWindowInfo;
259 import android.view.accessibility.IAccessibilityEmbeddedConnection;
260 import android.view.accessibility.IAccessibilityInteractionConnection;
261 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
262 import android.view.accessibility.IWindowSurfaceInfoCallback;
263 import android.view.animation.AccelerateDecelerateInterpolator;
264 import android.view.animation.Interpolator;
265 import android.view.autofill.AutofillManager;
266 import android.view.contentcapture.ContentCaptureManager;
267 import android.view.contentcapture.ContentCaptureSession;
268 import android.view.flags.Flags;
269 import android.view.inputmethod.ImeTracker;
270 import android.view.inputmethod.InputMethodManager;
271 import android.widget.Scroller;
272 import android.window.ActivityWindowInfo;
273 import android.window.BackEvent;
274 import android.window.ClientWindowFrames;
275 import android.window.CompatOnBackInvokedCallback;
276 import android.window.InputTransferToken;
277 import android.window.OnBackAnimationCallback;
278 import android.window.OnBackInvokedCallback;
279 import android.window.OnBackInvokedDispatcher;
280 import android.window.ScreenCapture;
281 import android.window.SurfaceSyncGroup;
282 import android.window.WindowOnBackInvokedDispatcher;
283 import android.window.WindowTokenClient;
284 import android.window.WindowTokenClientController;
285 
286 import com.android.internal.R;
287 import com.android.internal.annotations.GuardedBy;
288 import com.android.internal.annotations.VisibleForTesting;
289 import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
290 import com.android.internal.inputmethod.ImeTracing;
291 import com.android.internal.inputmethod.InputMethodDebug;
292 import com.android.internal.os.IResultReceiver;
293 import com.android.internal.os.SomeArgs;
294 import com.android.internal.policy.DecorView;
295 import com.android.internal.policy.PhoneFallbackEventHandler;
296 import com.android.internal.protolog.ProtoLog;
297 import com.android.internal.util.ContrastColorUtil;
298 import com.android.internal.util.FastPrintWriter;
299 import com.android.internal.view.BaseSurfaceHolder;
300 import com.android.internal.view.RootViewSurfaceTaker;
301 import com.android.internal.view.SurfaceCallbackHelper;
302 import com.android.modules.expresslog.Counter;
303 import com.android.os.coregraphics.HwuiStatsLog;
304 
305 import libcore.io.IoUtils;
306 
307 import java.io.FileOutputStream;
308 import java.io.IOException;
309 import java.io.OutputStream;
310 import java.io.PrintWriter;
311 import java.io.StringWriter;
312 import java.lang.ref.WeakReference;
313 import java.util.ArrayDeque;
314 import java.util.ArrayList;
315 import java.util.HashSet;
316 import java.util.List;
317 import java.util.Objects;
318 import java.util.OptionalInt;
319 import java.util.Queue;
320 import java.util.concurrent.CountDownLatch;
321 import java.util.concurrent.Executor;
322 import java.util.concurrent.atomic.AtomicBoolean;
323 import java.util.function.Consumer;
324 import java.util.function.Predicate;
325 /**
326  * The top of a view hierarchy, implementing the needed protocol between View
327  * and the WindowManager.  This is for the most part an internal implementation
328  * detail of {@link WindowManagerGlobal}.
329  *
330  * {@hide}
331  */
332 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
333 public final class ViewRootImpl implements ViewParent,
334         View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
335         AttachedSurfaceControl {
336     private static final String TAG = "ViewRootImpl";
337     private static final boolean DBG = false;
338     private static final boolean LOCAL_LOGV = false;
339     /** @noinspection PointlessBooleanExpression*/
340     private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
341     private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
342     private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
343     private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
344     private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
345     private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
346     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
347     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
348     private static final boolean DEBUG_FPS = false;
349     private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
350     private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
351     private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV;
352     private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV;
353     private static final boolean DEBUG_TOUCH_NAVIGATION = false || LOCAL_LOGV;
354     private static final boolean DEBUG_BLAST = false || LOCAL_LOGV;
355     private static final boolean DEBUG_SENSITIVE_CONTENT = false || LOCAL_LOGV;
356     private static final int LOGTAG_INPUT_FOCUS = 62001;
357     private static final int LOGTAG_VIEWROOT_DRAW_EVENT = 60004;
358 
359     /**
360      * This change disables the {@code DRAW_WAKE_LOCK}, an internal wakelock acquired per-frame
361      * duration display DOZE. It was added to allow animation during AOD. This wakelock consumes
362      * battery severely if the animation is too heavy, so, it will be removed.
363      */
364     @ChangeId
365     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
366     private static final long DISABLE_DRAW_WAKE_LOCK = 349153669L;
367 
368     /**
369      * Set to false if we do not want to use the multi threaded renderer even though
370      * threaded renderer (aka hardware renderering) is used. Note that by disabling
371      * this, WindowCallbacks will not fire.
372      */
373     private static final boolean MT_RENDERER_AVAILABLE = true;
374 
375     /**
376      * Whether or not to report end-to-end input latency. Can be disabled temporarily as a
377      * risk mitigation against potential jank caused by acquiring a weak reference
378      * per frame.
379      */
380     private static final boolean ENABLE_INPUT_LATENCY_TRACKING = true;
381 
382     /**
383      * Whether the client (system UI) is handling the transient gesture and the corresponding
384      * animation.
385      * @hide
386      */
387     public static final boolean CLIENT_TRANSIENT =
388             SystemProperties.getBoolean("persist.wm.debug.client_transient", false);
389 
390     /**
391      * Set this system property to true to force the view hierarchy to render
392      * at 60 Hz. This can be used to measure the potential framerate.
393      */
394     private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
395 
396     /**
397      * Maximum time we allow the user to roll the trackball enough to generate
398      * a key event, before resetting the counters.
399      */
400     static final int MAX_TRACKBALL_DELAY = 250;
401 
402     /**
403      * Initial value for {@link #mContentCaptureEnabled}.
404      */
405     private static final int CONTENT_CAPTURE_ENABLED_NOT_CHECKED = 0;
406 
407     /**
408      * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code true}.
409      */
410     private static final int CONTENT_CAPTURE_ENABLED_TRUE = 1;
411 
412     /**
413      * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code false}.
414      */
415     private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2;
416 
417     /**
418      * Maximum time to wait for {@link View#dispatchScrollCaptureSearch} to complete.
419      */
420     private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500;
421 
422     private static final int UNSET_SYNC_ID = -1;
423 
424     private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100;
425     private static final int INFREQUENT_UPDATE_COUNTS = 2;
426 
427     /**
428      * The {@link #intermittentUpdateState()} value when the ViewRootImpl isn't intermittent.
429      */
430     public static final int INTERMITTENT_STATE_NOT_INTERMITTENT = 1;
431 
432     /**
433      * The {@link #intermittentUpdateState()} value when the ViewRootImpl is transitioning either
434      * to or from intermittent to not intermittent. This indicates that the frame rate shouldn't
435      * change.
436      */
437     public static final int INTERMITTENT_STATE_IN_TRANSITION = -1;
438 
439     /**
440      * The {@link #intermittentUpdateState()} value when the ViewRootImpl is intermittent.
441      */
442     public static final int INTERMITTENT_STATE_INTERMITTENT = 0;
443 
444     /**
445      * Minimum time to wait before reporting changes to keep clear areas.
446      */
447     private static final int KEEP_CLEAR_AREA_REPORT_RATE_MILLIS = 100;
448 
449     private static final long NANOS_PER_SEC = 1000000000;
450 
451     // If the ViewRootImpl has been idle for more than 750ms, clear the preferred
452     // frame rate category and frame rate.
453     private static final int IDLE_TIME_MILLIS = 750;
454 
455     private static final long NANOS_PER_MILLI = 1_000_000;
456 
457     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
458     static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
459 
460     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<>();
461     static boolean sFirstDrawComplete = false;
462 
463     private ArrayList<OnBufferTransformHintChangedListener> mTransformHintListeners =
464             new ArrayList<>();
465     private @SurfaceControl.BufferTransform
466             int mPreviousTransformHint = SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
467     /**
468      * The top level {@link OnBackInvokedDispatcher}.
469      */
470     private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
471     /**
472      * Compatibility {@link OnBackInvokedCallback} that dispatches KEYCODE_BACK events
473      * to view root for apps using legacy back behavior.
474      */
475     private CompatOnBackInvokedCallback mCompatOnBackInvokedCallback;
476 
477     @Nullable
478     private ContentObserver mForceInvertObserver;
479 
480     /**
481      * Callback for notifying about global configuration changes.
482      */
483     public interface ConfigChangedCallback {
484 
485         /** Notifies about global config change. */
onConfigurationChanged(Configuration globalConfig)486         void onConfigurationChanged(Configuration globalConfig);
487     }
488 
489     private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>();
490 
491     /**
492      * Callback for notifying activities.
493      */
494     public interface ActivityConfigCallback {
495         /**
496          * Notifies about override config change and/or move to different display.
497          * @param overrideConfig New override config to apply to activity.
498          * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed.
499          */
onConfigurationChanged(@onNull Configuration overrideConfig, int newDisplayId)500         default void onConfigurationChanged(@NonNull Configuration overrideConfig,
501                 int newDisplayId) {
502             // Must override one of the #onConfigurationChanged.
503             throw new IllegalStateException("Not implemented");
504         }
505 
506         /**
507          * Notifies about override config change and/or move to different display.
508          * @param overrideConfig New override config to apply to activity.
509          * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed.
510          * @param activityWindowInfo New ActivityWindowInfo to apply to activity.
511          */
onConfigurationChanged(@onNull Configuration overrideConfig, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo)512         default void onConfigurationChanged(@NonNull Configuration overrideConfig,
513                 int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) {
514             onConfigurationChanged(overrideConfig, newDisplayId);
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      * Used when configuration change first updates the config of corresponding activity.
527      * In that case we receive a call back from {@link ActivityThread} and this flag is used to
528      * preserve the initial value.
529      *
530      * @see #performConfigurationChange
531      */
532     private boolean mForceNextConfigUpdate;
533 
534     /** lazily-initialized in getAudioManager() */
535     private boolean mFastScrollSoundEffectsEnabled = false;
536 
537     /**
538      * Signals that compatibility booleans have been initialized according to
539      * target SDK versions.
540      */
541     private static boolean sCompatibilityDone = false;
542 
543     /**
544      * Always assign focus if a focusable View is available.
545      */
546     private static boolean sAlwaysAssignFocus;
547 
548     /**
549      * whether we pre-initialized the Buffer Allocator
550      */
551     private static boolean sPreInitializedBufferAllocator = false;
552 
553     /**
554      * This list must only be modified by the main thread.
555      */
556     final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
557     @UnsupportedAppUsage
558     @UiContext
559     public final Context mContext;
560 
561     @UnsupportedAppUsage
562     final IWindowSession mWindowSession;
563     @NonNull Display mDisplay;
564     final String mBasePackageName;
565 
566     // If we would like to keep a particular eye on the corresponding package.
567     final boolean mExtraDisplayListenerLogging;
568 
569     final int[] mTmpLocation = new int[2];
570 
571     final TypedValue mTmpValue = new TypedValue();
572 
573     final Thread mThread;
574 
575     final WindowLeaked mLocation;
576 
577     public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
578 
579     final W mWindow;
580 
581     final IBinder mLeashToken;
582 
583     final int mTargetSdkVersion;
584 
585     @UnsupportedAppUsage
586     View mView;
587 
588     View mAccessibilityFocusedHost;
589     // Accessibility-focused virtual view. The bounds and sourceNodeId of
590     // mAccessibilityFocusedVirtualView is up-to-date while other fields may be stale.
591     AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
592 
593     // True if the window currently has pointer capture enabled.
594     boolean mPointerCapture;
595 
596     int mViewVisibility;
597     boolean mAppVisible = true;
598     // For recents to freeform transition we need to keep drawing after the app receives information
599     // that it became invisible. This will ignore that information and depend on the decor view
600     // visibility to control drawing. The decor view visibility will get adjusted when the app get
601     // stopped and that's when the app will stop drawing further frames.
602     private boolean mForceDecorViewVisibility = false;
603     // Used for tracking app visibility updates separately in case we get double change. This will
604     // make sure that we always call relayout for the corresponding window.
605     private boolean mAppVisibilityChanged;
606     int mOrigWindowType = -1;
607 
608     // Set to true if the owner of this window is in the stopped state,
609     // so the window should no longer be active.
610     @UnsupportedAppUsage
611     boolean mStopped = false;
612 
613     // Set to true if the owner of this window is in ambient mode,
614     // which means it won't receive input events.
615     boolean mIsAmbientMode = false;
616 
617     // Set to true to stop input during an Activity Transition.
618     boolean mPausedForTransition = false;
619 
620     SurfaceHolder.Callback2 mSurfaceHolderCallback;
621     BaseSurfaceHolder mSurfaceHolder;
622     boolean mIsCreating;
623     boolean mDrawingAllowed;
624 
625     final Region mTransparentRegion;
626     final Region mPreviousTransparentRegion;
627 
628     Region mTouchableRegion;
629     Region mPreviousTouchableRegion;
630 
631     private int mMeasuredWidth;
632     private int mMeasuredHeight;
633 
634     // This indicates that we've already known the window size but without measuring the views.
635     // If this is true, we must measure the views before laying out them.
636     private boolean mViewMeasureDeferred;
637 
638     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
639     int mWidth;
640     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
641     int mHeight;
642     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
643     private Rect mDirty;
644     public boolean mIsAnimating;
645 
646     private boolean mUseMTRenderer;
647     private boolean mPendingDragResizing;
648     private boolean mDragResizing;
649     private boolean mInvalidateRootRequested;
650     private int mCanvasOffsetX;
651     private int mCanvasOffsetY;
652     CompatibilityInfo.Translator mTranslator;
653 
654     @UnsupportedAppUsage
655     final View.AttachInfo mAttachInfo;
656     final SystemUiVisibilityInfo mCompatibleVisibilityInfo;
657     int mDispatchedSystemUiVisibility;
658     int mDispatchedSystemBarAppearance;
659     InputQueue.Callback mInputQueueCallback;
660     InputQueue mInputQueue;
661     @UnsupportedAppUsage
662     FallbackEventHandler mFallbackEventHandler;
663     final Choreographer mChoreographer;
664     protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo();
665     private final InputEventAssigner mInputEventAssigner = new InputEventAssigner();
666 
667     // Whether to draw this surface as DISPLAY_DECORATION.
668     boolean mDisplayDecorationCached = false;
669 
670     // Is the stylus pointer icon enabled
671     private final boolean mIsStylusPointerIconEnabled;
672 
673     // VRR check for number of infrequent updates
674     private int mInfrequentUpdateCount = 0;
675     // VRR time of last update
676     private long mLastUpdateTimeMillis = 0;
677     // VRR interval since the previous
678     private int mMinusOneFrameIntervalMillis = 0;
679     // VRR interval between the previous and the frame before
680     private int mMinusTwoFrameIntervalMillis = 0;
681     // VRR has the invalidation idle message been posted?
682     private boolean mInvalidationIdleMessagePosted = false;
683     // VRR: List of all Views that are animating with the threaded render
684     private ArrayList<View> mThreadedRendererViews = new ArrayList();
685 
686     /**
687      * Update the Choreographer's FrameInfo object with the timing information for the current
688      * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next
689      * frame.
690      * @return the updated FrameInfo object
691      */
getUpdatedFrameInfo()692     protected @NonNull FrameInfo getUpdatedFrameInfo() {
693         // Since Choreographer is a thread-local singleton while we can have multiple
694         // ViewRootImpl's, populate the frame information from the current viewRootImpl before
695         // starting the draw
696         FrameInfo frameInfo = mChoreographer.mFrameInfo;
697         mViewFrameInfo.populateFrameInfo(frameInfo);
698         mViewFrameInfo.reset();
699         mInputEventAssigner.notifyFrameProcessed();
700         return frameInfo;
701     }
702 
703     // used in relayout to get SurfaceControl size
704     // for BLAST adapter surface setup
705     private final Point mSurfaceSize = new Point();
706     private final Point mLastSurfaceSize = new Point();
707 
708     private final Rect mVisRect = new Rect(); // used to retrieve visible rect of focused view.
709     private final Rect mTempRect = new Rect();
710 
711     private final WindowLayout mWindowLayout;
712 
713     // This is used to reduce the race between window focus changes being dispatched from
714     // the window manager and input events coming through the input system.
715     @GuardedBy("this")
716     boolean mWindowFocusChanged;
717     @GuardedBy("this")
718     boolean mUpcomingWindowFocus;
719     @GuardedBy("this")
720     boolean mUpcomingInTouchMode;
721     /**
722      * Compatibility {@link OnBackInvokedCallback} for windowless window, to forward the back
723      * key event host app.
724      */
725     private Predicate<KeyEvent> mWindowlessBackKeyCallback;
726 
727     public boolean mTraversalScheduled;
728     int mTraversalBarrier;
729     boolean mWillDrawSoon;
730     /** Set to true while in performTraversals for detecting when die(true) is called from internal
731      * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
732     boolean mIsInTraversal;
733     boolean mApplyInsetsRequested;
734     boolean mLayoutRequested;
735     boolean mFirst;
736 
737     @Nullable
738     int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
739     boolean mPerformContentCapture;
740 
741     boolean mReportNextDraw;
742     /** Set only while mReportNextDraw=true, indicating the last reason that was triggered */
743     String mLastReportNextDrawReason;
744     /** The reaason the last call to performDraw() returned false */
745     String mLastPerformDrawSkippedReason;
746     /** The reason the last call to performTraversals() returned without drawing */
747     String mLastPerformTraversalsSkipDrawReason;
748     /** The state of the WMS requested sync, if one is in progress. Can be one of the states
749      * below. */
750     int mWmsRequestSyncGroupState;
751 
752     // The possible states of the WMS requested sync, see createSyncIfNeeded()
753     private static final int WMS_SYNC_NONE = 0;
754     private static final int WMS_SYNC_PENDING = 1;
755     private static final int WMS_SYNC_RETURNED = 2;
756     private static final int WMS_SYNC_MERGED = 3;
757 
758     /**
759      * Set whether the requested SurfaceSyncGroup should sync the buffer. When set to true, VRI will
760      * create a sync transaction with BBQ and send the resulting buffer back to the
761      * SurfaceSyncGroup. If false, VRI will not try to sync a buffer in BBQ, but still report when a
762      * draw occurred.
763      */
764     private boolean mSyncBuffer = false;
765 
766     /**
767      * Flag to determine whether the client needs to check with WMS if it can draw. WMS will notify
768      * the client that it can't draw if we're still in the middle of a sync set that includes this
769      * window. Once the sync is complete, the window can resume drawing. This is to ensure we don't
770      * deadlock the client by trying to request draws when there may not be any buffers available.
771      */
772     private boolean mCheckIfCanDraw = false;
773 
774     private boolean mWasLastDrawCanceled;
775     private boolean mLastTraversalWasVisible = true;
776     private boolean mLastDrawScreenOff;
777 
778     private boolean mDrewOnceForSync = false;
779 
780     int mSyncSeqId = 0;
781     int mLastSyncSeqId = 0;
782 
783     private boolean mUpdateSurfaceNeeded;
784     boolean mFullRedrawNeeded;
785     boolean mNewSurfaceNeeded;
786     boolean mForceNextWindowRelayout;
787     CountDownLatch mWindowDrawCountDown;
788 
789     /**
790      * Value to indicate whether someone has called {@link #applyTransactionOnDraw}before the
791      * traversal. This is used to determine whether a RT frame callback needs to be registered to
792      * merge the transaction with the next frame. The value is cleared after the VRI has run a
793      * traversal pass.
794      */
795     boolean mHasPendingTransactions;
796     /**
797      * The combined transactions passed in from {@link #applyTransactionOnDraw}
798      */
799     private Transaction mPendingTransaction = new Transaction();
800 
801 
802     boolean mIsDrawing;
803     int mLastSystemUiVisibility;
804     int mClientWindowLayoutFlags;
805 
806     // Pool of queued input events.
807     private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
808     private QueuedInputEvent mQueuedInputEventPool;
809     private int mQueuedInputEventPoolSize;
810 
811     /* Input event queue.
812      * Pending input events are input events waiting to be delivered to the input stages
813      * and handled by the application.
814      */
815     QueuedInputEvent mPendingInputEventHead;
816     QueuedInputEvent mPendingInputEventTail;
817     int mPendingInputEventCount;
818     boolean mProcessInputEventsScheduled;
819     boolean mUnbufferedInputDispatch;
820     @InputSourceClass
821     int mUnbufferedInputSource = SOURCE_CLASS_NONE;
822 
823     String mPendingInputEventQueueLengthCounterName = "pq";
824 
825     InputStage mFirstInputStage;
826     InputStage mFirstPostImeInputStage;
827     InputStage mSyntheticInputStage;
828 
829     private final UnhandledKeyManager mUnhandledKeyManager = new UnhandledKeyManager();
830 
831     boolean mWindowAttributesChanged = false;
832 
833     // These can be accessed by any thread, must be protected with a lock.
834     // Surface can never be reassigned or cleared (use Surface.clear()).
835     @UnsupportedAppUsage
836     public final Surface mSurface = new Surface();
837     private final SurfaceControl mSurfaceControl = new SurfaceControl();
838 
839     private BLASTBufferQueue mBlastBufferQueue;
840     private IBinder mBbqApplyToken = new Binder();
841 
842     private final HdrRenderState mHdrRenderState = new HdrRenderState(this);
843 
844     /**
845      * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to
846      * the surface insets. This surface is created only if a client requests it via
847      * {@link #updateAndGetBoundsLayer(Transaction)}. By parenting to this bounds surface, child
848      * surfaces can ensure they do not draw into the surface inset region set by the parent window.
849      */
850     private SurfaceControl mBoundsLayer;
851     private final Transaction mTransaction = new Transaction();
852     private final Transaction mFrameRateTransaction = new Transaction();
853 
854     @UnsupportedAppUsage
855     boolean mAdded;
856     boolean mAddedTouchMode;
857 
858     /**
859      * It usually keeps the latest layout result from {@link IWindow#resized} or
860      * {@link IWindowSession#relayout}.
861      */
862     private final ClientWindowFrames mTmpFrames = new ClientWindowFrames();
863 
864     // These are accessed by multiple threads.
865     final Rect mWinFrame; // frame given by window manager.
866     private final Rect mLastLayoutFrame;
867     Rect mOverrideInsetsFrame;
868 
869     final Rect mPendingBackDropFrame = new Rect();
870 
871     boolean mPendingAlwaysConsumeSystemBars;
872     private int mRelayoutSeq;
873     private final Rect mWinFrameInScreen = new Rect();
874     private final InsetsState mTempInsets = new InsetsState();
875     private final InsetsSourceControl.Array mTempControls = new InsetsSourceControl.Array();
876     private final WindowConfiguration mTempWinConfig = new WindowConfiguration();
877     private float mInvCompatScale = 1f;
878     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
879             = new ViewTreeObserver.InternalInsetsInfo();
880 
881     private WindowInsets mLastWindowInsets;
882 
883     // Insets types hidden by legacy window flags or system UI flags.
884     private @InsetsType int mTypesHiddenByFlags = 0;
885 
886     /** Last applied configuration obtained from resources. */
887     private final Configuration mLastConfigurationFromResources = new Configuration();
888     /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */
889     private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration();
890     /** Configurations waiting to be applied. */
891     private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration();
892 
893     /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */
894     @Nullable
895     private ActivityWindowInfo mPendingActivityWindowInfo;
896     /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */
897     @Nullable
898     private ActivityWindowInfo mLastReportedActivityWindowInfo;
899     private final ClientWindowFrames mLastReportedFrames = new ClientWindowFrames();
900     private int mLastReportedInsetsStateSeq = getInitSeq();
901     private int mLastReportedActiveControlsSeq = getInitSeq();
902 
903     boolean mScrollMayChange;
904     @SoftInputModeFlags
905     int mSoftInputMode;
906     @UnsupportedAppUsage
907     WeakReference<View> mLastScrolledFocus;
908     int mScrollY;
909     int mCurScrollY;
910     Scroller mScroller;
911     static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
912     private ArrayList<LayoutTransition> mPendingTransitions;
913 
914     final ViewConfiguration mViewConfiguration;
915 
916     /* Drag/drop */
917     ClipDescription mDragDescription;
918     View mCurrentDragView;
919     View mStartedDragViewForA11y;
920     volatile Object mLocalDragState;
921     final PointF mDragPoint = new PointF();
922     final PointF mLastTouchPoint = new PointF();
923     int mLastTouchSource;
924     int mLastTouchDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
925     int mLastTouchPointerId;
926     /** Tracks last {@link MotionEvent#getToolType(int)} with {@link MotionEvent#ACTION_UP}. **/
927     private int mLastClickToolType;
928 
929     private boolean mProfileRendering;
930     private Choreographer.FrameCallback mRenderProfiler;
931     private boolean mRenderProfilingEnabled;
932 
933     // Variables to track frames per second, enabled via DEBUG_FPS flag
934     private long mFpsStartTime = -1;
935     private long mFpsPrevTime = -1;
936     private int mFpsNumFrames;
937 
938     private boolean mInsetsAnimationRunning;
939 
940     private long mPreviousFrameDrawnTime = -1;
941     // The largest view size percentage to the display size. Used on trace to collect metric.
942     private float mLargestChildPercentage = 0.0f;
943     // The reason the category was changed.
944     private int mFrameRateCategoryChangeReason = 0;
945     private String mFrameRateCategoryView;
946 
947     /**
948      * The resolved pointer icon requested by this window.
949      * A null value indicates the resolved pointer icon has not yet been calculated.
950      */
951     @Nullable
952     private PointerIcon mResolvedPointerIcon = null;
953 
954     /**
955      * see {@link #playSoundEffect(int)}
956      */
957     AudioManager mAudioManager;
958 
959     /**
960      * see {@link #performHapticFeedback(int, int, int)}
961      */
962     Vibrator mVibrator;
963 
964     final AccessibilityManager mAccessibilityManager;
965 
966     AccessibilityInteractionController mAccessibilityInteractionController;
967 
968     Paint mRoundDisplayAccessibilityHighlightPaint;
969 
970     final AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager =
971             new AccessibilityInteractionConnectionManager();
972     final HighContrastTextManager mHighContrastTextManager;
973 
974     SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
975 
976     HashSet<View> mTempHashSet;
977 
978     private final int mDensity;
979     private final int mNoncompatDensity;
980 
981     private boolean mInLayout = false;
982     ArrayList<View> mLayoutRequesters = new ArrayList<View>();
983     boolean mHandlingLayoutInLayoutRequest = false;
984 
985     private int mViewLayoutDirectionInitial;
986 
987     /** Set to true once doDie() has been called. */
988     private boolean mRemoved;
989 
990     private boolean mNeedsRendererSetup;
991 
992     private final InputEventCompatProcessor mInputCompatProcessor;
993 
994     /**
995      * Consistency verifier for debugging purposes.
996      */
997     protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
998             InputEventConsistencyVerifier.isInstrumentationEnabled() ?
999                     new InputEventConsistencyVerifier(this, 0) : null;
1000 
1001     private final InsetsController mInsetsController;
1002     private final ImeBackAnimationController mImeBackAnimationController;
1003     private final ImeFocusController mImeFocusController;
1004 
1005     private boolean mIsSurfaceOpaque;
1006 
1007     private final BackgroundBlurDrawable.Aggregator mBlurRegionAggregator =
1008             new BackgroundBlurDrawable.Aggregator(this);
1009 
1010     /**
1011      * @return {@link ImeFocusController} for this instance.
1012      */
1013     @NonNull
getImeFocusController()1014     public ImeFocusController getImeFocusController() {
1015         return mImeFocusController;
1016     }
1017 
1018     private final ViewRootRectTracker mGestureExclusionTracker =
1019             new ViewRootRectTracker(v -> v.getSystemGestureExclusionRects());
1020     private final ViewRootRectTracker mKeepClearRectsTracker =
1021             new ViewRootRectTracker(v -> v.collectPreferKeepClearRects());
1022     private final ViewRootRectTracker mUnrestrictedKeepClearRectsTracker =
1023             new ViewRootRectTracker(v -> v.collectUnrestrictedPreferKeepClearRects());
1024     private boolean mHasPendingKeepClearAreaChange;
1025     private Rect mKeepClearAccessibilityFocusRect;
1026 
1027     private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
1028 
1029     private final ISensitiveContentProtectionManager mSensitiveContentProtectionService;
1030 
1031     static final class SystemUiVisibilityInfo {
1032         int globalVisibility;
1033         int localValue;
1034         int localChanges;
1035     }
1036 
1037     private final HandwritingInitiator mHandwritingInitiator;
1038 
1039     /**
1040      * Used by InputMethodManager.
1041      * @hide
1042      */
1043     @NonNull
getHandwritingInitiator()1044     public HandwritingInitiator getHandwritingInitiator() {
1045         return mHandwritingInitiator;
1046     }
1047 
1048     /**
1049      * A SurfaceSyncGroup that is created when WMS requested to sync the buffer
1050      */
1051     private SurfaceSyncGroup mWmsRequestSyncGroup;
1052 
1053     /**
1054      * The SurfaceSyncGroup that represents the active VRI SurfaceSyncGroup. This is non null if
1055      * anyone requested the SurfaceSyncGroup for this VRI to ensure that anyone trying to sync with
1056      * this VRI are collected together. The SurfaceSyncGroup is cleared when the VRI draws since
1057      * that is the stop point where all changes are have been applied. A new SurfaceSyncGroup is
1058      * created after that point when something wants to sync VRI again.
1059      */
1060     private SurfaceSyncGroup mActiveSurfaceSyncGroup;
1061 
1062 
1063     private final Object mPreviousSyncSafeguardLock = new Object();
1064 
1065     /**
1066      * Wraps the TransactionCommitted callback for the previous SSG so it can be added to the next
1067      * SSG if started before previous has completed.
1068      */
1069     @GuardedBy("mPreviousSyncSafeguardLock")
1070     private SurfaceSyncGroup mPreviousSyncSafeguard;
1071 
1072     private static final Object sSyncProgressLock = new Object();
1073     // The count needs to be static since it's used to enable or disable RT animations which is
1074     // done at a global level per process. If any VRI syncs are in progress, we can't enable RT
1075     // animations until all are done.
1076     private static int sNumSyncsInProgress = 0;
1077 
1078     private int mNumPausedForSync = 0;
1079 
1080     private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
1081 
1082     private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
1083 
1084     /**
1085      * Increment this value when the surface has been replaced.
1086      */
1087     private int mSurfaceSequenceId = 0;
1088 
1089     private boolean mRelayoutRequested;
1090 
1091     /**
1092      * Whether sandboxing of {@link android.view.View#getBoundsOnScreen},
1093      * {@link android.view.View#getLocationOnScreen(int[])},
1094      * {@link android.view.View#getWindowDisplayFrame} and
1095      * {@link android.view.View#getWindowVisibleDisplayFrame}
1096      * within Activity bounds is enabled for the current application.
1097      */
1098     private final boolean mViewBoundsSandboxingEnabled;
1099 
1100     private AccessibilityWindowAttributes mAccessibilityWindowAttributes;
1101 
1102     /*
1103      * for Variable Refresh Rate project
1104      */
1105 
1106     // The preferred frame rate category of the view that
1107     // could be updated on a frame-by-frame basis.
1108     private int mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT;
1109     // The preferred frame rate category of the last frame that
1110     // could be used to lower frame rate after touch boost
1111     private int mLastPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT;
1112     // The preferred frame rate of the view that is mainly used for
1113     // touch boosting, view velocity handling, and TextureView.
1114     private float mPreferredFrameRate = 0;
1115     // The last preferred frame rate of the view that is mainly used to
1116     // track the difference between the current preferred frame rate and the previous value.
1117     private float mLastPreferredFrameRate = 0;
1118     // Used to check if it is in the frame rate boosting period.
1119     private boolean mIsFrameRateBoosting = false;
1120     // Used to check if it is in touch boosting period.
1121     private boolean mIsTouchBoosting = false;
1122     // Used to track if an ongoing press gesture is occurring.
1123     private boolean mIsPressedGesture = false;
1124     private boolean mDrawnThisFrame = false;
1125     // Used to check if there is a conflict between different frame rate voting.
1126     // Take 24 and 30 as an example, 24 is not a divisor of 30.
1127     // We consider there is a conflict.
1128     private boolean mIsFrameRateConflicted = false;
1129     // Used to check whether SurfaceControl has been replaced.
1130     private boolean mSurfaceReplaced = false;
1131     // Indicates whether a draw operation occurred during this frame while a touch event was active.
1132     private boolean mTouchAndDrawn = false;
1133     // Used to set frame rate compatibility.
1134     @Surface.FrameRateCompatibility int mFrameRateCompatibility =
1135             FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
1136     // time for initial touch boost period.
1137     private static final int FRAME_RATE_INITIAL_TOUCH_BOOST_TIME = 30;
1138     // time for touch boost period.
1139     private static final int FRAME_RATE_TOUCH_BOOST_TIME = 3000;
1140     // Timeout for the other frame rate boosts other than touch boost.
1141     private static final int FRAME_RATE_BOOST_TIME = 3000;
1142     // time for evaluating the interval between current time and
1143     // the time when frame rate was set previously.
1144     private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100;
1145     // timeout for surface replaced.
1146     private static final int FRAME_RATE_SURFACE_REPLACED_TIME = 3000;
1147 
1148     /*
1149      * The variables below are used to update frame rate category
1150      */
1151     private static final int FRAME_RATE_CATEGORY_COUNT = 5;
1152     private int mFrameRateCategoryHighCount = 0;
1153     private int mFrameRateCategoryHighHintCount = 0;
1154     private int mFrameRateCategoryNormalCount = 0;
1155     private int mFrameRateCategoryLowCount = 0;
1156 
1157     /*
1158      * the variables below are used to determine whther a dVRR feature should be enabled
1159      */
1160 
1161     /**
1162      * Object for relayoutWindow to return the latest window info, including the SyncSeqId
1163      * system. The SyncSeqId system was designed to work without synchronous relayout
1164      * window, and actually synchronous relayout window presents a problem.  We could have
1165      * a sequence like this:
1166      *    1. We send MSG_RESIZED to the client with a new syncSeqId to begin a new sync
1167      *    2. Due to scheduling the client executes performTraversals before calling MSG_RESIZED
1168      *    3. Coincidentally for some random reason it also calls relayout
1169      *    4. It observes the new state from relayout, and so the next frame will contain the state
1170      * However it hasn't received the seqId yet, and so under the designed operation of
1171      * seqId flowing through MSG_RESIZED, the next frame wouldn't be synced. Since it
1172      * contains our target sync state, we need to sync it! This problem won't come up once
1173      * we get rid of synchronous relayout, until then, we use this bundle to channel the
1174      * integer back over relayout.
1175      */
1176     private final WindowRelayoutResult mRelayoutResult = new WindowRelayoutResult(
1177             mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets, mTempControls);
1178 
1179     private static volatile boolean sAnrReported = false;
1180     static BLASTBufferQueue.TransactionHangCallback sTransactionHangCallback =
1181         new BLASTBufferQueue.TransactionHangCallback() {
1182             @Override
1183             public void onTransactionHang(String reason) {
1184                 if (sAnrReported) {
1185                     return;
1186                 }
1187 
1188                 sAnrReported = true;
1189                 // If we're making an in-process call to ActivityManagerService
1190                 // and the previous binder call on this thread was oneway, the
1191                 // calling PID will be 0. Clearing the calling identity fixes
1192                 // this and ensures ActivityManager gets the correct calling
1193                 // pid.
1194                 final long identityToken = Binder.clearCallingIdentity();
1195                 try {
1196                     ActivityManager.getService().appNotResponding(reason);
1197                 } catch (RemoteException e) {
1198                     // We asked the system to crash us, but the system
1199                     // already crashed. Unfortunately things may be
1200                     // out of control.
1201                 } finally {
1202                     Binder.restoreCallingIdentity(identityToken);
1203                 }
1204             }
1205         };
1206     private final Rect mChildBoundingInsets = new Rect();
1207     private boolean mChildBoundingInsetsChanged = false;
1208 
1209     private final boolean mDisableDrawWakeLock;
1210 
1211     private String mTag = TAG;
1212     private String mFpsTraceName;
1213     private String mLargestViewTraceName;
1214 
1215     private final boolean mAppStartInfoTimestampsFlagValue;
1216     private AtomicBoolean mAppStartTimestampsSent = new AtomicBoolean(false);
1217     private boolean mAppStartTrackingStarted = false;
1218     private long mRenderThreadDrawStartTimeNs = -1;
1219     private long mFirstFramePresentedTimeNs = -1;
1220 
1221     private final boolean mSendPerfHintOnTouch;
1222 
1223     private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
1224     private static boolean sToolkitFrameRateFunctionEnablingReadOnlyFlagValue;
1225     private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
1226     private static boolean sToolkitFrameRateTypingReadOnlyFlagValue;
1227     private static final boolean sToolkitFrameRateViewEnablingReadOnlyFlagValue;
1228     private static boolean sToolkitFrameRateVelocityMappingReadOnlyFlagValue =
1229             toolkitFrameRateVelocityMappingReadOnly();
1230     private static boolean sToolkitEnableInvalidateCheckThreadFlagValue =
1231             Flags.enableInvalidateCheckThread();
1232     private static boolean sSurfaceFlingerBugfixFlagValue =
1233             com.android.graphics.surfaceflinger.flags.Flags.vrrBugfix24q4();
1234     private static final boolean sEnableVrr = ViewProperties.vrr_enabled().orElse(true);
1235     private static final boolean sToolkitInitialTouchBoostFlagValue = toolkitInitialTouchBoost();
1236     private static boolean sToolkitFrameRateDebugFlagValue =  toolkitFrameRateDebug();
1237 
1238     static {
1239         sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
1240         sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision();
1241         sToolkitFrameRateTypingReadOnlyFlagValue = toolkitFrameRateTypingReadOnly();
1242         sToolkitFrameRateFunctionEnablingReadOnlyFlagValue =
1243                 toolkitFrameRateFunctionEnablingReadOnly();
1244         sToolkitFrameRateViewEnablingReadOnlyFlagValue =
1245                 toolkitFrameRateViewEnablingReadOnly();
1246     }
1247 
1248     // The latest input event from the gesture that was used to resolve the pointer icon.
1249     private MotionEvent mPointerIconEvent = null;
1250     private @ActivityInfo.ColorMode int mCurrentColorMode = ActivityInfo.COLOR_MODE_DEFAULT;
1251     private long mColorModeLastSetMillis = -1;
1252 
1253     private final boolean mIsSubscribeGranularDisplayEventsEnabled;
1254 
ViewRootImpl(Context context, Display display)1255     public ViewRootImpl(Context context, Display display) {
1256         this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout());
1257     }
1258 
ViewRootImpl(@iContext Context context, Display display, IWindowSession session, WindowLayout windowLayout)1259     public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
1260             WindowLayout windowLayout) {
1261         mContext = context;
1262         mWindowSession = session;
1263         mWindowLayout = windowLayout;
1264         mDisplay = display;
1265         mBasePackageName = context.getBasePackageName();
1266         final String name = DisplayProperties.debug_vri_package().orElse(null);
1267         mExtraDisplayListenerLogging = !TextUtils.isEmpty(name) && name.equals(mBasePackageName);
1268         mThread = Thread.currentThread();
1269         mLocation = new WindowLeaked(null);
1270         mWidth = -1;
1271         mHeight = -1;
1272         mDirty = new Rect();
1273         mWinFrame = new Rect();
1274         mLastLayoutFrame = new Rect();
1275         mWindow = new W(this);
1276         mLeashToken = new Binder();
1277         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
1278         mViewVisibility = View.GONE;
1279         mTransparentRegion = new Region();
1280         mPreviousTransparentRegion = new Region();
1281         mFirst = true; // true for the first time the view is added
1282         mPerformContentCapture = true; // also true for the first time the view is added
1283         mAdded = false;
1284         mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
1285                 context);
1286         mCompatibleVisibilityInfo = new SystemUiVisibilityInfo();
1287         mAccessibilityManager = AccessibilityManager.getInstance(context);
1288         mHighContrastTextManager = new HighContrastTextManager();
1289         mViewConfiguration = ViewConfiguration.get(context);
1290         mDensity = context.getResources().getDisplayMetrics().densityDpi;
1291         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
1292         mFallbackEventHandler = new PhoneFallbackEventHandler(context);
1293         mChoreographer = Choreographer.getInstance();
1294         mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));
1295         mImeBackAnimationController = new ImeBackAnimationController(this, mInsetsController);
1296         mHandwritingInitiator = new HandwritingInitiator(
1297                 mViewConfiguration,
1298                 mContext.getSystemService(InputMethodManager.class));
1299 
1300         mViewBoundsSandboxingEnabled = getViewBoundsSandboxingEnabled();
1301         mIsStylusPointerIconEnabled =
1302                 InputSettings.isStylusPointerIconEnabled(mContext);
1303 
1304         initializeProtoLogInProcess();
1305 
1306         String processorOverrideName = context.getResources().getString(
1307                                     R.string.config_inputEventCompatProcessorOverrideClassName);
1308         if (processorOverrideName.isEmpty()) {
1309             // No compatibility processor override, using default.
1310             mInputCompatProcessor = new InputEventCompatProcessor(context, mHandler);
1311         } else {
1312             InputEventCompatProcessor compatProcessor = null;
1313             try {
1314                 final Class<? extends InputEventCompatProcessor> klass =
1315                         (Class<? extends InputEventCompatProcessor>) Class.forName(
1316                                 processorOverrideName);
1317                 compatProcessor = klass.getConstructor(Context.class).newInstance(context);
1318             } catch (Exception e) {
1319                 Log.e(TAG, "Unable to create the InputEventCompatProcessor. ", e);
1320             } finally {
1321                 mInputCompatProcessor = compatProcessor;
1322             }
1323         }
1324 
1325         if (!sCompatibilityDone) {
1326             sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
1327 
1328             sCompatibilityDone = true;
1329         }
1330 
1331         loadSystemProperties();
1332         mImeFocusController = new ImeFocusController(this);
1333 
1334         mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
1335         mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context, Looper.myLooper());
1336         if (sensitiveContentAppProtection()) {
1337             mSensitiveContentProtectionService =
1338                     ISensitiveContentProtectionManager.Stub.asInterface(
1339                         ServiceManager.getService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE));
1340             if (mSensitiveContentProtectionService == null) {
1341                 Log.e(TAG, "SensitiveContentProtectionService shouldn't be null");
1342             }
1343         } else {
1344             mSensitiveContentProtectionService = null;
1345         }
1346 
1347         mAppStartInfoTimestampsFlagValue = android.app.Flags.appStartInfoTimestamps();
1348 
1349         // Disable DRAW_WAKE_LOCK starting U.
1350         mDisableDrawWakeLock =
1351                 CompatChanges.isChangeEnabled(DISABLE_DRAW_WAKE_LOCK) && disableDrawWakeLock();
1352         mIsSubscribeGranularDisplayEventsEnabled =
1353                 com.android.server.display.feature.flags.Flags.subscribeGranularDisplayEvents();
1354 
1355         mSendPerfHintOnTouch = adpfViewrootimplActionDownBoost();
1356 
1357         if (!sPreInitializedBufferAllocator) {
1358             preInitBufferAllocator();
1359             sPreInitializedBufferAllocator = true;
1360         }
1361     }
1362 
1363     public static void addFirstDrawHandler(Runnable callback) {
1364         synchronized (sFirstDrawHandlers) {
1365             if (!sFirstDrawComplete) {
1366                 sFirstDrawHandlers.add(callback);
1367             }
1368         }
1369     }
1370 
1371     /** Add static config callback to be notified about global config changes. */
1372     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1373     public static void addConfigCallback(ConfigChangedCallback callback) {
1374         synchronized (sConfigCallbacks) {
1375             sConfigCallbacks.add(callback);
1376         }
1377     }
1378 
1379     /** Remove a static config callback. */
1380     public static void removeConfigCallback(ConfigChangedCallback callback) {
1381         synchronized (sConfigCallbacks) {
1382             sConfigCallbacks.remove(callback);
1383         }
1384     }
1385 
1386     /**
1387      * Add activity config callback to be notified about override config changes and camera
1388      * compat control state updates.
1389      */
1390     public void setActivityConfigCallback(@Nullable ActivityConfigCallback callback) {
1391         mActivityConfigCallback = callback;
1392         if (callback == null) {
1393             mPendingActivityWindowInfo = null;
1394             mLastReportedActivityWindowInfo = null;
1395         } else {
1396             mPendingActivityWindowInfo = new ActivityWindowInfo();
1397             mLastReportedActivityWindowInfo = new ActivityWindowInfo();
1398         }
1399     }
1400 
1401     public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
1402         mAttachInfo.mContentOnApplyWindowInsetsListener = listener;
1403 
1404         // System windows will be fitted on first traversal, so no reason to request additional
1405         // (possibly getting executed after the first traversal).
1406         if (!mFirst) {
1407             requestFitSystemWindows();
1408         }
1409     }
1410 
1411     public void addWindowCallbacks(WindowCallbacks callback) {
1412         mWindowCallbacks.add(callback);
1413     }
1414 
1415     public void removeWindowCallbacks(WindowCallbacks callback) {
1416         mWindowCallbacks.remove(callback);
1417     }
1418 
1419     public void reportDrawFinish() {
1420         if (mWindowDrawCountDown != null) {
1421             mWindowDrawCountDown.countDown();
1422         }
1423     }
1424 
1425     // FIXME for perf testing only
1426     private boolean mProfile = false;
1427 
1428     /**
1429      * Call this to profile the next traversal call.
1430      * FIXME for perf testing only. Remove eventually
1431      */
1432     public void profile() {
1433         mProfile = true;
1434     }
1435 
1436     private boolean isInTouchMode() {
1437         if (mAttachInfo == null) {
1438             return mContext.getResources().getBoolean(R.bool.config_defaultInTouchMode);
1439         }
1440         return mAttachInfo.mInTouchMode;
1441     }
1442 
1443     /**
1444      * Notifies us that our child has been rebuilt, following
1445      * a window preservation operation. In these cases we
1446      * keep the same DecorView, but the activity controlling it
1447      * is a different instance, and we need to update our
1448      * callbacks.
1449      *
1450      * @hide
1451      */
1452     public void notifyChildRebuilt() {
1453         if (mView instanceof RootViewSurfaceTaker) {
1454             if (mSurfaceHolderCallback != null) {
1455                 mSurfaceHolder.removeCallback(mSurfaceHolderCallback);
1456             }
1457 
1458             mSurfaceHolderCallback =
1459                 ((RootViewSurfaceTaker)mView).willYouTakeTheSurface();
1460 
1461             if (mSurfaceHolderCallback != null) {
1462                 mSurfaceHolder = new TakenSurfaceHolder();
1463                 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
1464                 mSurfaceHolder.addCallback(mSurfaceHolderCallback);
1465             } else {
1466                 mSurfaceHolder = null;
1467             }
1468 
1469             mInputQueueCallback =
1470                 ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue();
1471             if (mInputQueueCallback != null) {
1472                 mInputQueueCallback.onInputQueueCreated(mInputQueue);
1473             }
1474         }
1475 
1476         // Update the last resource config in case the resource configuration was changed while
1477         // activity relaunched.
1478         updateLastConfigurationFromResources(getConfiguration());
1479         // Make sure to report the completion of draw for relaunch with preserved window.
1480         reportNextDraw("rebuilt");
1481         // Make sure to resume this root view when relaunching its host activity which was stopped.
1482         if (mStopped) {
1483             setWindowStopped(false);
1484         }
1485     }
1486 
1487     private Configuration getConfiguration() {
1488         return mContext.getResources().getConfiguration();
1489     }
1490 
1491     private WindowConfiguration getCompatWindowConfiguration() {
1492         final WindowConfiguration winConfig = getConfiguration().windowConfiguration;
1493         if (mInvCompatScale == 1f) {
1494             return winConfig;
1495         }
1496         mTempWinConfig.setTo(winConfig);
1497         mTempWinConfig.scale(mInvCompatScale);
1498         return mTempWinConfig;
1499     }
1500 
1501     /**
1502      * We have one child
1503      */
1504     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
1505         setView(view, attrs, panelParentView, UserHandle.myUserId());
1506     }
1507 
1508     /**
1509      * We have one child
1510      */
1511     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
1512             int userId) {
1513         synchronized (this) {
1514             if (mView == null) {
1515                 mView = view;
1516 
1517                 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
1518                 mFallbackEventHandler.setView(view);
1519                 mWindowAttributes.copyFrom(attrs);
1520                 if (mWindowAttributes.packageName == null) {
1521                     mWindowAttributes.packageName = mBasePackageName;
1522                 }
1523 
1524                 attrs = mWindowAttributes;
1525                 setTag();
1526                 mFpsTraceName = "FPS of " + getTitle();
1527                 mLargestViewTraceName = "Largest view percentage(per hundred) of " + getTitle();
1528 
1529                 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
1530                         & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
1531                         && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
1532                     Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
1533                 }
1534                 // Keep track of the actual window flags supplied by the client.
1535                 mClientWindowLayoutFlags = attrs.flags;
1536 
1537                 adjustLayoutInDisplayCutoutMode(attrs);
1538                 setAccessibilityFocus(null, null);
1539 
1540                 if (view instanceof RootViewSurfaceTaker) {
1541                     mSurfaceHolderCallback =
1542                             ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
1543                     if (mSurfaceHolderCallback != null) {
1544                         mSurfaceHolder = new TakenSurfaceHolder();
1545                         mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
1546                         mSurfaceHolder.addCallback(mSurfaceHolderCallback);
1547                     }
1548                 }
1549 
1550                 // Compute surface insets required to draw at specified Z value.
1551                 // TODO: Use real shadow insets for a constant max Z.
1552                 if (!attrs.hasManualSurfaceInsets) {
1553                     attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
1554                 }
1555 
1556                 CompatibilityInfo compatibilityInfo =
1557                         mDisplay.getDisplayAdjustments().getCompatibilityInfo();
1558                 mTranslator = compatibilityInfo.getTranslator();
1559 
1560                 // If the application owns the surface, don't enable hardware acceleration
1561                 if (mSurfaceHolder == null) {
1562                     // While this is supposed to enable only, it can effectively disable
1563                     // the acceleration too.
1564                     enableHardwareAcceleration(attrs);
1565                     final boolean useMTRenderer = MT_RENDERER_AVAILABLE
1566                             && mAttachInfo.mThreadedRenderer != null;
1567                     if (mUseMTRenderer != useMTRenderer) {
1568                         // Shouldn't be resizing, as it's done only in window setup,
1569                         // but end just in case.
1570                         endDragResizing();
1571                         mUseMTRenderer = useMTRenderer;
1572                     }
1573                 }
1574 
1575                 boolean restore = false;
1576                 if (mTranslator != null) {
1577                     mSurface.setCompatibilityTranslator(mTranslator);
1578                     restore = true;
1579                     attrs.backup();
1580                     mTranslator.translateWindowLayout(attrs);
1581                 }
1582                 if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
1583 
1584                 mSoftInputMode = attrs.softInputMode;
1585                 mWindowAttributesChanged = true;
1586                 mAttachInfo.mRootView = view;
1587                 mAttachInfo.mScalingRequired = mTranslator != null;
1588                 mAttachInfo.mApplicationScale =
1589                         mTranslator == null ? 1.0f : mTranslator.applicationScale;
1590                 if (panelParentView != null) {
1591                     mAttachInfo.mPanelParentWindowToken
1592                             = panelParentView.getApplicationWindowToken();
1593                 }
1594                 if (!fixViewRootCallTrace()) {
1595                     mAdded = true;
1596                 }
1597                 int res; /* = WindowManagerImpl.ADD_OKAY; */
1598 
1599                 // Schedule the first layout -before- adding to the window
1600                 // manager, to make sure we do the relayout before receiving
1601                 // any other events from the system.
1602                 requestLayout();
1603                 InputChannel inputChannel = null;
1604                 if ((mWindowAttributes.inputFeatures
1605                         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
1606                     inputChannel = new InputChannel();
1607                 }
1608                 mForceDecorViewVisibility = (mWindowAttributes.privateFlags
1609                         & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
1610 
1611                 if (mView instanceof RootViewSurfaceTaker) {
1612                     PendingInsetsController pendingInsetsController =
1613                             ((RootViewSurfaceTaker) mView).providePendingInsetsController();
1614                     if (pendingInsetsController != null) {
1615                         pendingInsetsController.replayAndAttach(mInsetsController);
1616                     }
1617                 }
1618                 if (mView instanceof DecorView) {
1619                     mWindowAttributes.privateFlags |= PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED;
1620                 }
1621 
1622                 try {
1623                     mOrigWindowType = mWindowAttributes.type;
1624                     mAttachInfo.mRecomputeGlobalAttributes = true;
1625                     collectViewAttributes();
1626                     adjustLayoutParamsForCompatibility(mWindowAttributes,
1627                             mInsetsController.getAppearanceControlled(),
1628                             mInsetsController.isBehaviorControlled());
1629                     controlInsetsForCompatibility(mWindowAttributes);
1630 
1631                     Rect attachedFrame = new Rect();
1632                     final float[] compatScale = { 1f };
1633                     res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
1634                             getHostVisibility(), mDisplay.getDisplayId(), userId,
1635                             mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
1636                             mTempControls, attachedFrame, compatScale);
1637                     if (!attachedFrame.isValid()) {
1638                         attachedFrame = null;
1639                     }
1640                     if (mTranslator != null) {
1641                         mTranslator.translateRectInScreenToAppWindow(attachedFrame);
1642                     }
1643                     mTmpFrames.attachedFrame = attachedFrame;
1644                     mTmpFrames.compatScale = compatScale[0];
1645                     mInvCompatScale = 1f / compatScale[0];
1646                 } catch (RemoteException | RuntimeException e) {
1647                     if (!fixViewRootCallTrace()) {
1648                         mAdded = false;
1649                     }
1650                     mView = null;
1651                     mAttachInfo.mRootView = null;
1652                     mFallbackEventHandler.setView(null);
1653                     unscheduleTraversals();
1654                     setAccessibilityFocus(null, null);
1655                     throw new RuntimeException("Adding window failed", e);
1656                 } finally {
1657                     if (restore) {
1658                         attrs.restore();
1659                     }
1660                 }
1661 
1662                 mAttachInfo.mAlwaysConsumeSystemBars =
1663                         (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0;
1664                 mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;
1665                 handleInsetsControlChanged(mTempInsets, mTempControls);
1666                 final InsetsState state = mInsetsController.getState();
1667                 final Rect displayCutoutSafe = mTempRect;
1668                 state.getDisplayCutoutSafe(displayCutoutSafe);
1669                 final WindowConfiguration winConfig = getCompatWindowConfiguration();
1670                 mWindowLayout.computeFrames(mWindowAttributes, state,
1671                         displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
1672                         UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
1673                         mInsetsController.getRequestedVisibleTypes(), 1f /* compactScale */,
1674                         mTmpFrames);
1675                 setFrame(mTmpFrames.frame, true /* withinRelayout */);
1676                 registerBackCallbackOnWindow();
1677                 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
1678                 if (res < WindowManagerGlobal.ADD_OKAY) {
1679                     mAttachInfo.mRootView = null;
1680                     if (!fixViewRootCallTrace()) {
1681                         mAdded = false;
1682                     }
1683                     mFallbackEventHandler.setView(null);
1684                     unscheduleTraversals();
1685                     setAccessibilityFocus(null, null);
1686                     switch (res) {
1687                         case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
1688                         case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
1689                             throw new WindowManager.BadTokenException(
1690                                     "Unable to add window -- token " + attrs.token
1691                                     + " is not valid; is your activity running?");
1692                         case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
1693                             throw new WindowManager.BadTokenException(
1694                                     "Unable to add window -- token " + attrs.token
1695                                     + " is not for an application");
1696                         case WindowManagerGlobal.ADD_APP_EXITING:
1697                             throw new WindowManager.BadTokenException(
1698                                     "Unable to add window -- app for token " + attrs.token
1699                                     + " is exiting");
1700                         case WindowManagerGlobal.ADD_DUPLICATE_ADD:
1701                             throw new WindowManager.BadTokenException(
1702                                     "Unable to add window -- window " + mWindow
1703                                     + " has already been added");
1704                         case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
1705                             // Silently ignore -- we would have just removed it
1706                             // right away, anyway.
1707                             return;
1708                         case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
1709                             throw new WindowManager.BadTokenException("Unable to add window "
1710                                     + mWindow + " -- another window of type "
1711                                     + mWindowAttributes.type + " already exists");
1712                         case WindowManagerGlobal.ADD_PERMISSION_DENIED:
1713                             throw new WindowManager.BadTokenException("Unable to add window "
1714                                     + mWindow + " -- permission denied for window type "
1715                                     + mWindowAttributes.type);
1716                         case WindowManagerGlobal.ADD_INVALID_DISPLAY:
1717                             throw new WindowManager.InvalidDisplayException("Unable to add window "
1718                                     + mWindow + " -- the specified display can not be found");
1719                         case WindowManagerGlobal.ADD_INVALID_TYPE:
1720                             throw new WindowManager.InvalidDisplayException("Unable to add window "
1721                                     + mWindow + " -- the specified window type "
1722                                     + mWindowAttributes.type + " is not valid");
1723                         case WindowManagerGlobal.ADD_INVALID_USER:
1724                             throw new WindowManager.BadTokenException("Unable to add Window "
1725                                     + mWindow + " -- requested userId is not valid");
1726                     }
1727                     throw new RuntimeException(
1728                             "Unable to add window -- unknown error code " + res);
1729                 }
1730 
1731                 registerListeners();
1732                 // We should update mAttachInfo.mDisplayState after registerDisplayListener
1733                 // because displayState might be changed before registerDisplayListener.
1734                 mAttachInfo.mDisplayState = mDisplay.getState();
1735                 if (mExtraDisplayListenerLogging) {
1736                     Slog.i(mTag, "(" + mBasePackageName + ") Initial DisplayState: "
1737                             + mAttachInfo.mDisplayState, new Throwable());
1738                 }
1739 
1740                 if (view instanceof RootViewSurfaceTaker) {
1741                     mInputQueueCallback =
1742                         ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
1743                 }
1744                 if (inputChannel != null) {
1745                     if (mInputQueueCallback != null) {
1746                         mInputQueue = new InputQueue();
1747                         mInputQueueCallback.onInputQueueCreated(mInputQueue);
1748                     }
1749                     mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
1750                             Looper.myLooper());
1751 
1752                     if (ENABLE_INPUT_LATENCY_TRACKING && mAttachInfo.mThreadedRenderer != null) {
1753                         InputMetricsListener listener = new InputMetricsListener();
1754                         mHardwareRendererObserver = new HardwareRendererObserver(
1755                                 listener, listener.data, mHandler, true /*waitForPresentTime*/);
1756                         mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
1757                     }
1758                     // Update unbuffered request when set the root view.
1759                     mUnbufferedInputSource = mView.mUnbufferedInputSource;
1760                 }
1761 
1762                 view.assignParent(this);
1763                 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
1764                 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
1765 
1766                 if (mAccessibilityManager.isEnabled()) {
1767                     mAccessibilityInteractionConnectionManager.ensureConnection();
1768                     setAccessibilityWindowAttributesIfNeeded();
1769                 }
1770 
1771                 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
1772                     view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
1773                 }
1774 
1775                 // Set up the input pipeline.
1776                 CharSequence counterSuffix = attrs.getTitle();
1777                 mSyntheticInputStage = new SyntheticInputStage();
1778                 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
1779                 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
1780                         "aq:native-post-ime:" + counterSuffix);
1781                 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
1782                 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
1783                         "aq:ime:" + counterSuffix);
1784                 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
1785                 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
1786                         "aq:native-pre-ime:" + counterSuffix);
1787 
1788                 mFirstInputStage = nativePreImeStage;
1789                 mFirstPostImeInputStage = earlyPostImeStage;
1790                 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
1791                 if (fixViewRootCallTrace()) {
1792                     mAdded = true;
1793                 }
1794 
1795                 if (!mRemoved || !mAppVisible) {
1796                     AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
1797                 } else if (LOCAL_LOGV) {
1798                     Log.v(mTag, "setView() enabling visibility when removed");
1799                 }
1800             }
1801         }
1802     }
1803 
1804     private void setAccessibilityWindowAttributesIfNeeded() {
1805         final boolean registered = mAttachInfo.mAccessibilityWindowId
1806                 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1807         if (registered) {
1808             final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
1809                     mWindowAttributes, mContext.getResources().getConfiguration().getLocales());
1810             if (!attributes.equals(mAccessibilityWindowAttributes)) {
1811                 mAccessibilityWindowAttributes = attributes;
1812                 mAccessibilityManager.setAccessibilityWindowAttributes(getDisplayId(),
1813                         mAttachInfo.mAccessibilityWindowId, attributes);
1814             }
1815 
1816         }
1817     }
1818 
1819     /**
1820      * Register any kind of listeners if setView was success.
1821      */
1822     private void registerListeners() {
1823         if (mExtraDisplayListenerLogging) {
1824             Slog.i(mTag, "Register listeners: " + mBasePackageName);
1825         }
1826         mAccessibilityManager.addAccessibilityStateChangeListener(
1827                 mAccessibilityInteractionConnectionManager, mHandler);
1828         mAccessibilityManager.addHighContrastTextStateChangeListener(
1829                 mExecutor, mHighContrastTextManager);
1830 
1831 
1832         long eventsToBeRegistered =
1833                 (mIsSubscribeGranularDisplayEventsEnabled)
1834                 ? DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED
1835                         | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_STATE
1836                         | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED
1837                 : DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED
1838                         | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED
1839                         | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE
1840                         | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED;
1841         DisplayManagerGlobal
1842                 .getInstance()
1843                 .registerDisplayListener(
1844                         mDisplayListener,
1845                         mHandler,
1846                         eventsToBeRegistered,
1847                         mBasePackageName);
1848 
1849         // LINT.IfChange(fi_cb)
1850         if (forceInvertColor()) {
1851             if (mForceInvertObserver == null) {
1852                 mForceInvertObserver = new ContentObserver(mHandler) {
1853                     @Override
1854                     public void onChange(boolean selfChange) {
1855                         updateForceDarkMode();
1856                     }
1857                 };
1858                 final Uri[] urisToObserve = {
1859                     Settings.Secure.getUriFor(
1860                         Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED),
1861                     Settings.Secure.getUriFor(Settings.Secure.UI_NIGHT_MODE)
1862                 };
1863                 for (Uri uri : urisToObserve) {
1864                     mContext.getContentResolver().registerContentObserver(
1865                             uri,
1866                             false,
1867                             mForceInvertObserver,
1868                             UserHandle.myUserId());
1869                 }
1870             }
1871         }
1872         // LINT.ThenChange(/services/core/java/com/android/server/UiModeManagerService.java:fi_cb)
1873     }
1874 
1875     /**
1876      * Unregister all listeners while detachedFromWindow.
1877      */
1878     private void unregisterListeners() {
1879         mAccessibilityManager.removeAccessibilityStateChangeListener(
1880                 mAccessibilityInteractionConnectionManager);
1881         mAccessibilityManager.removeHighContrastTextStateChangeListener(
1882                 mHighContrastTextManager);
1883         DisplayManagerGlobal
1884                 .getInstance()
1885                 .unregisterDisplayListener(mDisplayListener);
1886 
1887         if (forceInvertColor()) {
1888             if (mForceInvertObserver != null) {
1889                 mContext.getContentResolver().unregisterContentObserver(mForceInvertObserver);
1890                 mForceInvertObserver = null;
1891             }
1892         }
1893 
1894         if (mExtraDisplayListenerLogging) {
1895             Slog.w(mTag, "Unregister listeners: " + mBasePackageName, new Throwable());
1896         }
1897     }
1898 
1899     private void setTag() {
1900         final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
1901         if (split.length > 0) {
1902             mTag =  "VRI[" + split[split.length - 1] + "]";
1903         }
1904     }
1905 
1906     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1907     public int getWindowFlags() {
1908         return mWindowAttributes.flags;
1909     }
1910 
1911     public int getDisplayId() {
1912         return mDisplay.getDisplayId();
1913     }
1914 
1915     public CharSequence getTitle() {
1916         return mWindowAttributes.getTitle();
1917     }
1918 
1919     /**
1920      * @return the width of the root view. Note that this will return {@code -1} until the first
1921      *         layout traversal, when the width is set.
1922      *
1923      * @hide
1924      */
1925     public int getWidth() {
1926         return mWidth;
1927     }
1928 
1929     /**
1930      * @return the height of the root view. Note that this will return {@code -1} until the first
1931      *         layout traversal, when the height is set.
1932      *
1933      * @hide
1934      */
1935     public int getHeight() {
1936         return mHeight;
1937     }
1938 
1939     /**
1940      * Destroys hardware rendering resources for this ViewRootImpl
1941      *
1942      * May be called on any thread
1943      */
1944     @AnyThread
1945     void destroyHardwareResources() {
1946         final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
1947         if (renderer != null) {
1948             // This is called by WindowManagerGlobal which may or may not be on the right thread
1949             if (Looper.myLooper() != mAttachInfo.mHandler.getLooper()) {
1950                 mAttachInfo.mHandler.postAtFrontOfQueue(this::destroyHardwareResources);
1951                 return;
1952             }
1953             renderer.destroyHardwareResources(mView);
1954             renderer.destroy();
1955         }
1956     }
1957 
1958     /**
1959      * Does nothing; Here only because of @UnsupportedAppUsage
1960      */
1961     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
1962             publicAlternatives = "Use {@link android.webkit.WebView} instead")
1963     public void detachFunctor(long functor) { }
1964 
1965     /**
1966      * Does nothing; Here only because of @UnsupportedAppUsage
1967      */
1968     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
1969             publicAlternatives = "Use {@link android.webkit.WebView} instead")
1970     public static void invokeFunctor(long functor, boolean waitForCompletion) { }
1971 
1972     /**
1973      * @param animator animator to register with the hardware renderer
1974      */
1975     public void registerAnimatingRenderNode(RenderNode animator) {
1976         if (mAttachInfo.mThreadedRenderer != null) {
1977             mAttachInfo.mThreadedRenderer.registerAnimatingRenderNode(animator);
1978         } else {
1979             if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
1980                 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
1981             }
1982             mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
1983         }
1984     }
1985 
1986     /**
1987      * @param animator animator to register with the hardware renderer
1988      */
1989     public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) {
1990         if (mAttachInfo.mThreadedRenderer != null) {
1991             mAttachInfo.mThreadedRenderer.registerVectorDrawableAnimator(animator);
1992         }
1993     }
1994 
1995     /**
1996      * Registers a callback to be executed when the next frame is being drawn on RenderThread. This
1997      * callback will be executed on a RenderThread worker thread, and only used for the next frame
1998      * and thus it will only fire once.
1999      *
2000      * @param callback The callback to register.
2001      */
2002     public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) {
2003         if (mAttachInfo.mThreadedRenderer != null) {
2004             mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
2005                 @Override
2006                 public void onFrameDraw(long frame) {
2007                 }
2008 
2009                 @Override
2010                 public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult,
2011                         long frame) {
2012                     try {
2013                         return callback.onFrameDraw(syncResult, frame);
2014                     } catch (Exception e) {
2015                         Log.e(TAG, "Exception while executing onFrameDraw", e);
2016                     }
2017                     return null;
2018                 }
2019             });
2020         }
2021     }
2022 
2023     @UnsupportedAppUsage
2024     private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
2025         mAttachInfo.mHardwareAccelerated = false;
2026         mAttachInfo.mHardwareAccelerationRequested = false;
2027 
2028         // Don't enable hardware acceleration when the application is in compatibility mode
2029         if (mTranslator != null) return;
2030 
2031         // Try to enable hardware acceleration if requested
2032         final boolean hardwareAccelerated =
2033                 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
2034 
2035         if (hardwareAccelerated) {
2036             // Persistent processes (including the system) should not do
2037             // accelerated rendering on low-end devices.  In that case,
2038             // sRendererDisabled will be set.  In addition, the system process
2039             // itself should never do accelerated rendering.  In that case, both
2040             // sRendererDisabled and sSystemRendererDisabled are set.  When
2041             // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
2042             // can be used by code on the system process to escape that and enable
2043             // HW accelerated drawing.  (This is basically for the lock screen.)
2044 
2045             final boolean forceHwAccelerated = (attrs.privateFlags &
2046                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
2047 
2048             if (ThreadedRenderer.sRendererEnabled || forceHwAccelerated) {
2049                 if (mAttachInfo.mThreadedRenderer != null) {
2050                     mAttachInfo.mThreadedRenderer.destroy();
2051                 }
2052 
2053                 final Rect insets = attrs.surfaceInsets;
2054                 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
2055                         || insets.top != 0 || insets.bottom != 0;
2056                 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
2057                 final ThreadedRenderer renderer = ThreadedRenderer.create(mContext, translucent,
2058                         attrs.getTitle().toString());
2059                 mAttachInfo.mThreadedRenderer = renderer;
2060                 renderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
2061                 updateColorModeIfNeeded(attrs.getColorMode(), attrs.getDesiredHdrHeadroom());
2062                 mHdrRenderState.forceUpdateHdrSdrRatio();
2063                 updateForceDarkMode();
2064                 mAttachInfo.mHardwareAccelerated = true;
2065                 mAttachInfo.mHardwareAccelerationRequested = true;
2066                 if (mHardwareRendererObserver != null) {
2067                     renderer.addObserver(mHardwareRendererObserver);
2068                 }
2069             }
2070         }
2071     }
2072 
2073     private int getNightMode() {
2074         return getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
2075     }
2076 
2077     /**
2078      * Determines the type of force dark to apply, considering force inversion, system night mode,
2079      * and app-specific settings (including developer opt-outs).
2080      *
2081      * @return A {@link ForceDarkType.ForceDarkTypeDef} constant indicating the force dark type.
2082      */
2083     @VisibleForTesting
2084     public @ForceDarkType.ForceDarkTypeDef int determineForceDarkType() {
2085         TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
2086         try {
2087             if (forceInvertColor()) {
2088                 // Force invert ignores all developer opt-outs.
2089                 // We also ignore dark theme, since the app developer can override the user's
2090                 // preference for dark mode in configuration.uiMode. Instead, we assume that both
2091                 // force invert and the system's dark theme are enabled.
2092                 if (shouldApplyForceInvertDark()) {
2093                     // TODO: b/368725782 - Use hwui color area detection instead of / in
2094                     //  addition to these heuristics.
2095                     final boolean isLightTheme =
2096                             a.getBoolean(R.styleable.Theme_isLightTheme, false);
2097                     final boolean isBackgroundColorLight;
2098                     if (mView != null && mView.getBackground()
2099                             instanceof ColorDrawable colorDrawable) {
2100                         isBackgroundColorLight =
2101                                 !ContrastColorUtil.isColorDarkLab(colorDrawable.getColor());
2102                     } else {
2103                         // Treat unknown as light, so that only isLightTheme is used to determine
2104                         // force dark treatment.
2105                         isBackgroundColorLight = true;
2106                     }
2107                     if (isLightTheme && isBackgroundColorLight) {
2108                         return ForceDarkType.FORCE_INVERT_COLOR_DARK;
2109                     } else {
2110                         return ForceDarkType.NONE;
2111                     }
2112                 }
2113             }
2114 
2115             boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
2116             if (useAutoDark) {
2117                 boolean forceDarkAllowedDefault =
2118                         SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);
2119                 useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
2120                         && a.getBoolean(R.styleable.Theme_forceDarkAllowed,
2121                             forceDarkAllowedDefault);
2122             }
2123             return useAutoDark ? ForceDarkType.FORCE_DARK : ForceDarkType.NONE;
2124         } finally {
2125             a.recycle();
2126         }
2127     }
2128 
2129     private boolean shouldApplyForceInvertDark() {
2130         final UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
2131         if (uiModeManager == null) {
2132             return false;
2133         }
2134         return uiModeManager.getForceInvertState() == UiModeManager.FORCE_INVERT_TYPE_DARK;
2135     }
2136 
2137     private void updateForceDarkMode() {
2138         if (mAttachInfo.mThreadedRenderer == null) return;
2139         if (mAttachInfo.mThreadedRenderer.setForceDark(determineForceDarkType())) {
2140             // TODO: Don't require regenerating all display lists to apply this setting
2141             if (forceInvertColor()) {
2142                 destroyAndInvalidate();
2143             } else {
2144                 invalidateWorld(mView);
2145             }
2146         }
2147     }
2148 
2149     @UnsupportedAppUsage
2150     public View getView() {
2151         return mView;
2152     }
2153 
2154     final WindowLeaked getLocation() {
2155         return mLocation;
2156     }
2157 
2158     @VisibleForTesting
2159     public void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
2160         synchronized (this) {
2161             final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
2162             final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
2163             final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
2164             final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
2165             final int oldSoftInputMode = mWindowAttributes.softInputMode;
2166             final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
2167 
2168             if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
2169                     & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
2170                     && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
2171                 Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!");
2172             }
2173 
2174             // Keep track of the actual window flags supplied by the client.
2175             mClientWindowLayoutFlags = attrs.flags;
2176 
2177             // Preserve system UI visibility.
2178             final int systemUiVisibility = mWindowAttributes.systemUiVisibility;
2179             final int subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
2180 
2181             // Preserve appearance and behavior.
2182             final int appearance = mWindowAttributes.insetsFlags.appearance;
2183             final int behavior = mWindowAttributes.insetsFlags.behavior;
2184 
2185             // Calling this before copying prevents redundant LAYOUT_CHANGED.
2186             final int layoutInDisplayCutoutModeFromCaller = adjustLayoutInDisplayCutoutMode(attrs);
2187 
2188             final int changes = mWindowAttributes.copyFrom(attrs);
2189             if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
2190                 // Recompute system ui visibility.
2191                 mAttachInfo.mRecomputeGlobalAttributes = true;
2192             }
2193             if ((changes & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
2194                 // Request to update light center.
2195                 mAttachInfo.mNeedsUpdateLightCenter = true;
2196             }
2197             if ((changes & WindowManager.LayoutParams.COLOR_MODE_CHANGED) != 0) {
2198                 invalidate();
2199             }
2200             if (mWindowAttributes.packageName == null) {
2201                 mWindowAttributes.packageName = mBasePackageName;
2202             }
2203 
2204             // Restore the layoutInDisplayCutoutMode of the caller;
2205             attrs.layoutInDisplayCutoutMode = layoutInDisplayCutoutModeFromCaller;
2206 
2207             // Restore preserved flags.
2208             mWindowAttributes.systemUiVisibility = systemUiVisibility;
2209             mWindowAttributes.subtreeSystemUiVisibility = subtreeSystemUiVisibility;
2210             mWindowAttributes.insetsFlags.appearance = appearance;
2211             mWindowAttributes.insetsFlags.behavior = behavior;
2212 
2213             if (mWindowAttributes.preservePreviousSurfaceInsets) {
2214                 // Restore old surface insets.
2215                 mWindowAttributes.surfaceInsets.set(
2216                         oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
2217                 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
2218             } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft
2219                     || mWindowAttributes.surfaceInsets.top != oldInsetTop
2220                     || mWindowAttributes.surfaceInsets.right != oldInsetRight
2221                     || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) {
2222                 mNeedsRendererSetup = true;
2223             }
2224 
2225             applyKeepScreenOnFlag(mWindowAttributes);
2226 
2227             if (newView) {
2228                 mSoftInputMode = attrs.softInputMode;
2229                 requestLayout();
2230             }
2231 
2232             // Don't lose the mode we last auto-computed.
2233             if ((attrs.softInputMode & SOFT_INPUT_MASK_ADJUST)
2234                     == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
2235                 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
2236                         & ~SOFT_INPUT_MASK_ADJUST) | (oldSoftInputMode & SOFT_INPUT_MASK_ADJUST);
2237             }
2238 
2239             if (mWindowAttributes.softInputMode != oldSoftInputMode) {
2240                 requestFitSystemWindows();
2241             }
2242 
2243             mWindowAttributesChanged = true;
2244             scheduleTraversals();
2245             setAccessibilityWindowAttributesIfNeeded();
2246         }
2247     }
2248 
2249     private int adjustLayoutInDisplayCutoutMode(WindowManager.LayoutParams attrs) {
2250         final int originalMode = attrs.layoutInDisplayCutoutMode;
2251         if ((attrs.privateFlags & (PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED
2252                 | PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE)) != 0
2253                 && attrs.isFullscreen()
2254                 && attrs.getFitInsetsTypes() == 0
2255                 && attrs.getFitInsetsSides() == 0) {
2256             if (originalMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
2257                 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
2258             }
2259         }
2260         return originalMode;
2261     }
2262 
2263     void handleAppVisibility(boolean visible) {
2264         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
2265             Trace.instant(Trace.TRACE_TAG_VIEW, TextUtils.formatSimple(
2266                     "%s visibilityChanged oldVisibility=%b newVisibility=%b", mTag,
2267                     mAppVisible, visible));
2268         }
2269         if (mAppVisible != visible) {
2270             final boolean previousVisible = getHostVisibility() == View.VISIBLE;
2271             mAppVisible = visible;
2272             final boolean currentVisible = getHostVisibility() == View.VISIBLE;
2273             // Root view only cares about whether it is visible or not.
2274             if (previousVisible != currentVisible) {
2275                 Log.d(mTag, "visibilityChanged oldVisibility=" + previousVisible + " newVisibility="
2276                         + currentVisible);
2277                 mAppVisibilityChanged = true;
2278                 scheduleTraversals();
2279             }
2280             // Only enable if the window is not already removed (via earlier call to doDie())
2281             if (!mRemoved || !mAppVisible) {
2282                 AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
2283             } else if (LOCAL_LOGV) {
2284                 Log.v(mTag, "handleAppVisibility() enabling visibility when removed");
2285             }
2286         }
2287     }
2288 
2289     void handleGetNewSurface() {
2290         mNewSurfaceNeeded = true;
2291         mFullRedrawNeeded = true;
2292         scheduleTraversals();
2293     }
2294 
2295     /** Handles messages {@link #MSG_RESIZED} and {@link #MSG_RESIZED_REPORT}. */
2296     private void handleResized(ClientWindowFrames frames, boolean reportDraw,
2297             MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
2298             boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing,
2299             @Nullable ActivityWindowInfo activityWindowInfo) {
2300         if (!mAdded) {
2301             return;
2302         }
2303 
2304         onClientWindowFramesChanged(frames);
2305 
2306         CompatibilityInfo.applyOverrideIfNeeded(mergedConfiguration);
2307         final Rect frame = frames.frame;
2308         final Rect displayFrame = frames.displayFrame;
2309         final Rect attachedFrame = frames.attachedFrame;
2310         if (mTranslator != null) {
2311             mTranslator.translateRectInScreenToAppWindow(frame);
2312             mTranslator.translateRectInScreenToAppWindow(displayFrame);
2313             mTranslator.translateRectInScreenToAppWindow(attachedFrame);
2314         }
2315         onInsetsStateChanged(insetsState);
2316         final float compatScale = frames.compatScale;
2317         final boolean frameChanged = !mWinFrame.equals(frame);
2318         final boolean shouldReportActivityWindowInfoChanged =
2319                 // Can be null if callbacks is not set
2320                 mLastReportedActivityWindowInfo != null
2321                         // Can be null if not activity window
2322                         && activityWindowInfo != null
2323                         && !mLastReportedActivityWindowInfo.equals(activityWindowInfo);
2324         final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration)
2325                 || shouldReportActivityWindowInfoChanged;
2326         final boolean attachedFrameChanged =
2327                 !Objects.equals(mTmpFrames.attachedFrame, attachedFrame);
2328         final boolean displayChanged = mDisplay.getDisplayId() != displayId;
2329         final boolean compatScaleChanged = mTmpFrames.compatScale != compatScale;
2330         final boolean dragResizingChanged = mPendingDragResizing != dragResizing;
2331         if (!reportDraw && !frameChanged && !configChanged && !attachedFrameChanged
2332                 && !displayChanged && !forceLayout
2333                 && !compatScaleChanged && !dragResizingChanged) {
2334             return;
2335         }
2336 
2337         mPendingDragResizing = dragResizing;
2338         mTmpFrames.compatScale = compatScale;
2339         mInvCompatScale = 1f / compatScale;
2340 
2341         if (configChanged) {
2342             // If configuration changed - notify about that and, maybe, about move to display.
2343             performConfigurationChange(mergedConfiguration, false /* force */,
2344                     displayChanged ? displayId : INVALID_DISPLAY /* same display */,
2345                     activityWindowInfo);
2346         } else if (displayChanged) {
2347             // Moved to display without config change - report last applied one.
2348             onMovedToDisplay(displayId, mLastConfigurationFromResources);
2349         }
2350 
2351         setFrame(frame, false /* withinRelayout */);
2352         mTmpFrames.displayFrame.set(displayFrame);
2353         if (mTmpFrames.attachedFrame != null && attachedFrame != null) {
2354             mTmpFrames.attachedFrame.set(attachedFrame);
2355         }
2356 
2357         if (mDragResizing && mUseMTRenderer) {
2358             boolean fullscreen = frame.equals(mPendingBackDropFrame);
2359             for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
2360                 mWindowCallbacks.get(i).onWindowSizeIsChanging(mPendingBackDropFrame, fullscreen,
2361                         mAttachInfo.mVisibleInsets, mAttachInfo.mStableInsets);
2362             }
2363         }
2364 
2365         mForceNextWindowRelayout |= forceLayout;
2366         mPendingAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
2367         mSyncSeqId = syncSeqId > mSyncSeqId ? syncSeqId : mSyncSeqId;
2368 
2369         if (reportDraw) {
2370             reportNextDraw("resized");
2371         }
2372 
2373         if (mView != null && (frameChanged || configChanged)) {
2374             forceLayout(mView);
2375         }
2376         requestLayout();
2377     }
2378 
2379     /** Handles messages {@link #MSG_INSETS_CONTROL_CHANGED}. */
2380     @VisibleForTesting
handleInsetsControlChanged(@onNull InsetsState insetsState, @NonNull InsetsSourceControl.Array activeControls)2381     public void handleInsetsControlChanged(@NonNull InsetsState insetsState,
2382             @NonNull InsetsSourceControl.Array activeControls) {
2383         // Deliver state change before control change, such that:
2384         // a) When gaining control, controller can compare with server state to evaluate
2385         // whether it needs to run animation.
2386         // b) When loosing control, controller can restore server state by taking last
2387         // dispatched state as truth.
2388         onInsetsStateChanged(insetsState);
2389         onActiveControlsChanged(activeControls);
2390     }
2391 
onClientWindowFramesChanged(@onNull ClientWindowFrames inOutFrames)2392     private void onClientWindowFramesChanged(@NonNull ClientWindowFrames inOutFrames) {
2393         if (isIncomingSeqStale(mLastReportedFrames.seq, inOutFrames.seq)) {
2394             // If the incoming is stale, use the last reported instead.
2395             inOutFrames.setTo(mLastReportedFrames);
2396         } else {
2397             // Keep track of the latest.
2398             mLastReportedFrames.setTo(inOutFrames);
2399         }
2400     }
2401 
onInsetsStateChanged(@onNull InsetsState insetsState)2402     private void onInsetsStateChanged(@NonNull InsetsState insetsState) {
2403         if (isIncomingSeqStale(mLastReportedInsetsStateSeq, insetsState.getSeq())) {
2404             // The incoming is stale. Skip.
2405             return;
2406         }
2407         // Keep track of the latest.
2408         mLastReportedInsetsStateSeq = insetsState.getSeq();
2409 
2410         if (mTranslator != null) {
2411             mTranslator.translateInsetsStateInScreenToAppWindow(insetsState);
2412         }
2413         mInsetsController.onStateChanged(insetsState);
2414     }
2415 
onActiveControlsChanged(@onNull InsetsSourceControl.Array activeControls)2416     private void onActiveControlsChanged(@NonNull InsetsSourceControl.Array activeControls) {
2417         if (!mAdded) {
2418             // Do not update the last report if window is not added yet.
2419             activeControls.release();
2420             return;
2421         }
2422 
2423         if (isIncomingSeqStale(mLastReportedActiveControlsSeq, activeControls.getSeq())) {
2424             // The incoming is stale. Skip.
2425             activeControls.release();
2426             return;
2427         }
2428         // Keep track of the latest.
2429         mLastReportedActiveControlsSeq = activeControls.getSeq();
2430 
2431         final InsetsSourceControl[] controls = activeControls.get();
2432         if (mTranslator != null) {
2433             mTranslator.translateSourceControlsInScreenToAppWindow(controls);
2434         }
2435         mInsetsController.onControlsChanged(controls);
2436     }
2437 
2438     private final DisplayListener mDisplayListener = new DisplayListener() {
2439         @Override
2440         public void onDisplayChanged(int displayId) {
2441             if (mExtraDisplayListenerLogging) {
2442                 Slog.i(mTag, "Received onDisplayChanged - " + mView);
2443             }
2444             if (mView != null && mDisplay.getDisplayId() == displayId) {
2445                 final int oldDisplayState = mAttachInfo.mDisplayState;
2446                 final int newDisplayState = mDisplay.getState();
2447                 if (mExtraDisplayListenerLogging) {
2448                     Slog.i(mTag, "DisplayState - old: " + oldDisplayState
2449                             + ", new: " + newDisplayState);
2450                 }
2451                 if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
2452                     Trace.traceCounter(Trace.TRACE_TAG_WINDOW_MANAGER,
2453                             "vri#screenState[" + mTag + "] state=", newDisplayState);
2454                 }
2455                 if (oldDisplayState != newDisplayState) {
2456                     mAttachInfo.mDisplayState = newDisplayState;
2457                     pokeDrawLockIfNeeded();
2458                     if (oldDisplayState != Display.STATE_UNKNOWN) {
2459                         final int oldScreenState = toViewScreenState(oldDisplayState);
2460                         final int newScreenState = toViewScreenState(newDisplayState);
2461                         if (oldScreenState != newScreenState) {
2462                             mView.dispatchScreenStateChanged(newScreenState);
2463                         }
2464                         if (oldDisplayState == Display.STATE_OFF) {
2465                             // Draw was suppressed so we need to for it to happen here.
2466                             mFullRedrawNeeded = true;
2467                             scheduleTraversals();
2468                         }
2469                     }
2470                 }
2471             }
2472         }
2473 
2474         @Override
2475         public void onDisplayRemoved(int displayId) {
2476         }
2477 
2478         @Override
2479         public void onDisplayAdded(int displayId) {
2480         }
2481 
2482         private int toViewScreenState(int displayState) {
2483             return displayState == Display.STATE_OFF ?
2484                     View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
2485         }
2486     };
2487 
2488     /**
2489      * Notify about move to a different display.
2490      * @param displayId The id of the display where this view root is moved to.
2491      * @param config Configuration of the resources on new display after move.
2492      *
2493      * @hide
2494      */
onMovedToDisplay(int displayId, Configuration config)2495     public void onMovedToDisplay(int displayId, Configuration config) {
2496         if (mDisplay.getDisplayId() == displayId) {
2497             return;
2498         }
2499 
2500         // Get new instance of display based on current display adjustments. It may be updated later
2501         // if moving between the displays also involved a configuration change.
2502         updateInternalDisplay(displayId, mView.getResources());
2503         mImeFocusController.onMovedToDisplay();
2504         mAttachInfo.mDisplayState = mDisplay.getState();
2505         // Internal state updated, now notify the view hierarchy.
2506         mView.dispatchMovedToDisplay(mDisplay, config);
2507     }
2508 
2509     /**
2510      * Updates {@link #mDisplay} to the display object corresponding to {@param displayId}.
2511      * Uses DEFAULT_DISPLAY if there isn't a display object in the system corresponding
2512      * to {@param displayId}.
2513      */
updateInternalDisplay(int displayId, Resources resources)2514     private void updateInternalDisplay(int displayId, Resources resources) {
2515         final Display preferredDisplay =
2516                 ResourcesManager.getInstance().getAdjustedDisplay(displayId, resources);
2517         mHdrRenderState.stopListening();
2518         if (preferredDisplay == null) {
2519             // Fallback to use default display.
2520             Slog.w(TAG, "Cannot get desired display with Id: " + displayId);
2521             mDisplay = ResourcesManager.getInstance()
2522                     .getAdjustedDisplay(DEFAULT_DISPLAY, resources);
2523         } else {
2524             mDisplay = preferredDisplay;
2525         }
2526         mHdrRenderState.startListening();
2527         mContext.updateDisplay(mDisplay.getDisplayId());
2528     }
2529 
pokeDrawLockIfNeeded()2530     void pokeDrawLockIfNeeded() {
2531         // Disable DRAW_WAKE_LOCK starting U. Otherwise, only need to acquire it for DOZE state.
2532         if (mDisableDrawWakeLock || mAttachInfo.mDisplayState != Display.STATE_DOZE) {
2533             // In DOZE_SUSPEND, Android shouldn't control the display; therefore we only poke the
2534             // draw wake lock when display state is DOZE. Noted that Display#isDozeState includes
2535             // DOZE_SUSPEND as well, so, it's not feasible here.
2536             return;
2537         }
2538         if (mWindowAttributes.type != WindowManager.LayoutParams.TYPE_BASE_APPLICATION) {
2539             // Non-activity windows should be responsible to hold wake lock by themself, because
2540             // usually they are system windows.
2541             return;
2542         }
2543         if (mAdded && mTraversalScheduled && mAttachInfo.mHasWindowFocus) {
2544             try {
2545                 mWindowSession.pokeDrawLock(mWindow);
2546             } catch (RemoteException ex) {
2547                 // System server died, oh well.
2548             }
2549         }
2550     }
2551 
2552     @Override
requestFitSystemWindows()2553     public void requestFitSystemWindows() {
2554         checkThread();
2555         mApplyInsetsRequested = true;
2556         scheduleTraversals();
2557     }
2558 
notifyInsetsChanged()2559     void notifyInsetsChanged() {
2560         mApplyInsetsRequested = true;
2561         requestLayout();
2562 
2563         // See comment for View.sForceLayoutWhenInsetsChanged
2564         if (View.sForceLayoutWhenInsetsChanged && mView != null
2565                 && (mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST)
2566                         == SOFT_INPUT_ADJUST_RESIZE) {
2567             forceLayout(mView);
2568         }
2569 
2570         // If this changes during traversal, no need to schedule another one as it will dispatch it
2571         // during the current traversal.
2572         if (!mIsInTraversal) {
2573             scheduleTraversals();
2574         }
2575     }
2576 
2577     /**
2578      * Notify the when the animating insets types have changed.
2579      *
2580      * @hide
2581      */
updateAnimatingTypes(@nsetsType int animatingTypes, @Nullable ImeTracker.Token statsToken)2582     public void updateAnimatingTypes(@InsetsType int animatingTypes,
2583             @Nullable ImeTracker.Token statsToken) {
2584         if (sToolkitSetFrameRateReadOnlyFlagValue) {
2585             boolean running = animatingTypes != 0;
2586             if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
2587                 Trace.instant(Trace.TRACE_TAG_VIEW,
2588                         TextUtils.formatSimple("notifyInsetsAnimationRunningStateChanged(%s)",
2589                         Boolean.toString(running)));
2590             }
2591             mInsetsAnimationRunning = running;
2592             try {
2593                 mWindowSession.updateAnimatingTypes(mWindow, animatingTypes, statsToken);
2594             } catch (RemoteException e) {
2595             }
2596         }
2597     }
2598 
2599     @Override
requestLayout()2600     public void requestLayout() {
2601         if (!mHandlingLayoutInLayoutRequest) {
2602             checkThread();
2603             mLayoutRequested = true;
2604             scheduleTraversals();
2605         }
2606     }
2607 
2608     @Override
isLayoutRequested()2609     public boolean isLayoutRequested() {
2610         return mLayoutRequested;
2611     }
2612 
2613     @Override
onDescendantInvalidated(@onNull View child, @NonNull View descendant)2614     public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) {
2615         if (sToolkitEnableInvalidateCheckThreadFlagValue) {
2616             checkThread();
2617         }
2618         if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
2619             mIsAnimating = true;
2620         }
2621         invalidate();
2622     }
2623 
2624     @UnsupportedAppUsage
invalidate()2625     void invalidate() {
2626         mDirty.set(0, 0, mWidth, mHeight);
2627         if (!mWillDrawSoon) {
2628             scheduleTraversals();
2629         }
2630     }
2631 
invalidateWorld(View view)2632     void invalidateWorld(View view) {
2633         view.invalidate();
2634         if (view instanceof ViewGroup) {
2635             ViewGroup parent = (ViewGroup) view;
2636             for (int i = 0; i < parent.getChildCount(); i++) {
2637                 invalidateWorld(parent.getChildAt(i));
2638             }
2639         }
2640     }
2641 
2642     @Override
invalidateChild(View child, Rect dirty)2643     public void invalidateChild(View child, Rect dirty) {
2644         invalidateChildInParent(null, dirty);
2645     }
2646 
2647     @Override
invalidateChildInParent(int[] location, Rect dirty)2648     public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
2649         checkThread();
2650         if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
2651 
2652         if (dirty == null) {
2653             invalidate();
2654             return null;
2655         } else if (dirty.isEmpty() && !mIsAnimating) {
2656             return null;
2657         }
2658 
2659         if (mCurScrollY != 0 || mTranslator != null) {
2660             mTempRect.set(dirty);
2661             dirty = mTempRect;
2662             if (mCurScrollY != 0) {
2663                 dirty.offset(0, -mCurScrollY);
2664             }
2665             if (mTranslator != null) {
2666                 mTranslator.translateRectInAppWindowToScreen(dirty);
2667             }
2668             if (mAttachInfo.mScalingRequired) {
2669                 dirty.inset(-1, -1);
2670             }
2671         }
2672 
2673         invalidateRectOnScreen(dirty);
2674 
2675         return null;
2676     }
2677 
invalidateRectOnScreen(Rect dirty)2678     private void invalidateRectOnScreen(Rect dirty) {
2679         if (DEBUG_DRAW) Log.v(mTag, "invalidateRectOnScreen: " + dirty);
2680         final Rect localDirty = mDirty;
2681 
2682         // Add the new dirty rect to the current one
2683         localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
2684         // Intersect with the bounds of the window to skip
2685         // updates that lie outside of the visible region
2686         final float appScale = mAttachInfo.mApplicationScale;
2687         final boolean intersected = localDirty.intersect(0, 0,
2688                 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
2689         if (!intersected) {
2690             localDirty.setEmpty();
2691         }
2692         if (!mWillDrawSoon && (intersected || mIsAnimating)) {
2693             scheduleTraversals();
2694         }
2695     }
2696 
setIsAmbientMode(boolean ambient)2697     public void setIsAmbientMode(boolean ambient) {
2698         mIsAmbientMode = ambient;
2699     }
2700 
setWindowStopped(boolean stopped)2701     void setWindowStopped(boolean stopped) {
2702         checkThread();
2703         if (mStopped != stopped) {
2704             mStopped = stopped;
2705             final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
2706             if (renderer != null) {
2707                 if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
2708                 renderer.setStopped(mStopped);
2709             }
2710             if (!mStopped) {
2711                 // Make sure that relayoutWindow will be called to get valid surface because
2712                 // the previous surface may have been released.
2713                 mAppVisibilityChanged = true;
2714                 scheduleTraversals();
2715             } else {
2716                 if (renderer != null) {
2717                     renderer.destroyHardwareResources(mView);
2718                 }
2719 
2720                 if (mSurface.isValid()) {
2721                     if (mSurfaceHolder != null) {
2722                         notifyHolderSurfaceDestroyed();
2723                     }
2724                     notifySurfaceDestroyed();
2725                 }
2726                 destroySurface();
2727 
2728                 // Reset so they can be sent again for warm starts.
2729                 mAppStartTimestampsSent.set(false);
2730                 mAppStartTrackingStarted = false;
2731                 mRenderThreadDrawStartTimeNs = -1;
2732                 mFirstFramePresentedTimeNs = -1;
2733             }
2734         }
2735         logColorMode(mCurrentColorMode, true);
2736     }
2737 
2738 
2739     /** Register callbacks to be notified when the ViewRootImpl surface changes. */
2740     public interface SurfaceChangedCallback {
surfaceCreated(Transaction t)2741         void surfaceCreated(Transaction t);
surfaceReplaced(Transaction t)2742         void surfaceReplaced(Transaction t);
surfaceDestroyed()2743         void surfaceDestroyed();
vriDrawStarted(boolean isWmSync)2744         default void vriDrawStarted(boolean isWmSync) {};
2745     }
2746 
2747     private final ArrayList<SurfaceChangedCallback> mSurfaceChangedCallbacks = new ArrayList<>();
addSurfaceChangedCallback(SurfaceChangedCallback c)2748     public void addSurfaceChangedCallback(SurfaceChangedCallback c) {
2749         mSurfaceChangedCallbacks.add(c);
2750     }
2751 
removeSurfaceChangedCallback(SurfaceChangedCallback c)2752     public void removeSurfaceChangedCallback(SurfaceChangedCallback c) {
2753         mSurfaceChangedCallbacks.remove(c);
2754     }
2755 
notifySurfaceCreated(Transaction t)2756     private void notifySurfaceCreated(Transaction t) {
2757         for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2758             mSurfaceChangedCallbacks.get(i).surfaceCreated(t);
2759         }
2760     }
2761 
2762     /**
2763      * Notify listeners when the ViewRootImpl surface has been replaced. This callback will not be
2764      * called if a new surface is created, only if the valid surface has been replaced with another
2765      * valid surface.
2766      */
notifySurfaceReplaced(Transaction t)2767     private void notifySurfaceReplaced(Transaction t) {
2768         for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2769             mSurfaceChangedCallbacks.get(i).surfaceReplaced(t);
2770         }
2771     }
2772 
notifySurfaceDestroyed()2773     private void notifySurfaceDestroyed() {
2774         for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2775             mSurfaceChangedCallbacks.get(i).surfaceDestroyed();
2776         }
2777     }
2778 
notifyDrawStarted(boolean isWmSync)2779     private void notifyDrawStarted(boolean isWmSync) {
2780         for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2781             mSurfaceChangedCallbacks.get(i).vriDrawStarted(isWmSync);
2782         }
2783     }
2784 
2785     /**
2786      * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the
2787      * surface insets. If the layer does not exist, it is created.
2788      *
2789      * <p>Parenting to this layer will ensure that its children are cropped by the view's surface
2790      * insets.
2791      */
updateAndGetBoundsLayer(Transaction t)2792     public SurfaceControl updateAndGetBoundsLayer(Transaction t) {
2793         if (mBoundsLayer == null) {
2794             mBoundsLayer = new SurfaceControl.Builder()
2795                     .setContainerLayer()
2796                     .setName("Bounds for - " + getTitle().toString())
2797                     .setParent(getSurfaceControl())
2798                     .setCallsite("ViewRootImpl.getBoundsLayer")
2799                     .build();
2800             setBoundsLayerCrop(t);
2801             t.show(mBoundsLayer);
2802         }
2803        return mBoundsLayer;
2804     }
2805 
updateBlastSurfaceIfNeeded()2806     void updateBlastSurfaceIfNeeded() {
2807         if (!mSurfaceControl.isValid()) {
2808             return;
2809         }
2810 
2811         if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
2812             mBlastBufferQueue.update(mSurfaceControl,
2813                 mSurfaceSize.x, mSurfaceSize.y,
2814                 mWindowAttributes.format);
2815             return;
2816         }
2817 
2818         // If the SurfaceControl has been updated, destroy and recreate the BBQ to reset the BQ and
2819         // BBQ states.
2820         if (mBlastBufferQueue != null) {
2821             mBlastBufferQueue.destroy();
2822         }
2823         mBlastBufferQueue = new BLASTBufferQueue(mTag, true /* updateDestinationFrame */);
2824         // If we create and destroy BBQ without recreating the SurfaceControl, we can end up
2825         // queuing buffers on multiple apply tokens causing out of order buffer submissions. We
2826         // fix this by setting the same apply token on all BBQs created by this VRI.
2827         mBlastBufferQueue.setApplyToken(mBbqApplyToken);
2828         mBlastBufferQueue.update(mSurfaceControl,  mSurfaceSize.x, mSurfaceSize.y,
2829                 mWindowAttributes.format);
2830         mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
2831         mBlastBufferQueue.setWaitForBufferReleaseCallback(mChoreographer::onWaitForBufferRelease);
2832         Surface blastSurface;
2833         if (addSchandleToVriSurface()) {
2834             blastSurface = mBlastBufferQueue.createSurfaceWithHandle();
2835         } else {
2836             blastSurface = mBlastBufferQueue.createSurface();
2837         }
2838         // Only call transferFrom if the surface has changed to prevent inc the generation ID and
2839         // causing EGL resources to be recreated.
2840         mSurface.transferFrom(blastSurface);
2841 
2842         // Since the SurfaceControl is a VRI, indicate that it can recover from buffer stuffing.
2843         mTransaction.setRecoverableFromBufferStuffing(mSurfaceControl).applyAsyncUnsafe();
2844     }
2845 
setBoundsLayerCrop(Transaction t)2846     private void setBoundsLayerCrop(Transaction t) {
2847         // Adjust of insets and update the bounds layer so child surfaces do not draw into
2848         // the surface inset region.
2849         mTempRect.set(0, 0, mSurfaceSize.x, mSurfaceSize.y);
2850         mTempRect.inset(mWindowAttributes.surfaceInsets.left,
2851                 mWindowAttributes.surfaceInsets.top,
2852                 mWindowAttributes.surfaceInsets.right, mWindowAttributes.surfaceInsets.bottom);
2853         mTempRect.inset(mChildBoundingInsets.left, mChildBoundingInsets.top,
2854             mChildBoundingInsets.right, mChildBoundingInsets.bottom);
2855         t.setWindowCrop(mBoundsLayer, mTempRect);
2856     }
2857 
2858     /**
2859      * Called after window layout to update the bounds surface. If the surface insets have changed
2860      * or the surface has resized, update the bounds surface.
2861      */
updateBoundsLayer(SurfaceControl.Transaction t)2862     private boolean updateBoundsLayer(SurfaceControl.Transaction t) {
2863         if (mBoundsLayer != null) {
2864             setBoundsLayerCrop(t);
2865             return true;
2866         }
2867         return false;
2868     }
2869 
prepareSurfaces()2870     private void prepareSurfaces() {
2871         final SurfaceControl.Transaction t = mTransaction;
2872         final SurfaceControl sc = getSurfaceControl();
2873         if (!sc.isValid()) return;
2874 
2875         if (updateBoundsLayer(t)) {
2876             applyTransactionOnDraw(t);
2877         }
2878 
2879         // Set the frame rate selection strategy to FRAME_RATE_SELECTION_STRATEGY_SELF
2880         // This strategy ensures that the frame rate specifications do not cascade down to
2881         // the descendant layers. This is particularly important for applications like Chrome,
2882         // where child surfaces should adhere to default behavior instead of no preference.
2883         // This issue only happens when ViewRootImpl calls setFrameRateCategory. This is
2884         // no longer needed if the dVRR feature is disabled.
2885         if (shouldEnableDvrr()) {
2886             try {
2887                 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) {
2888                     mFrameRateTransaction.setFrameRateSelectionStrategy(sc,
2889                         sc.FRAME_RATE_SELECTION_STRATEGY_SELF).applyAsyncUnsafe();
2890                 }
2891             } catch (Exception e) {
2892                 Log.e(mTag, "Unable to set frame rate selection strategy ", e);
2893             }
2894         }
2895     }
2896 
destroySurface()2897     private void destroySurface() {
2898         if (mBoundsLayer != null) {
2899             mBoundsLayer.release();
2900             mBoundsLayer = null;
2901         }
2902         mSurface.release();
2903         mSurfaceControl.release();
2904 
2905         if (mBlastBufferQueue != null) {
2906             mBlastBufferQueue.destroy();
2907             mBlastBufferQueue = null;
2908         }
2909 
2910         if (mAttachInfo.mThreadedRenderer != null) {
2911             mAttachInfo.mThreadedRenderer.setSurfaceControl(null, null);
2912         }
2913 
2914         // Also reset the VRR relevant values.
2915         mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT;
2916         mLastPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT;
2917         mPreferredFrameRate = 0;
2918         mLastPreferredFrameRate = 0;
2919     }
2920 
2921     /**
2922      * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
2923      * through to allow quick reversal of the Activity Transition.
2924      *
2925      * @param paused true to pause, false to resume.
2926      */
setPausedForTransition(boolean paused)2927     public void setPausedForTransition(boolean paused) {
2928         mPausedForTransition = paused;
2929     }
2930 
2931     @Override
getParent()2932     public ViewParent getParent() {
2933         return null;
2934     }
2935 
2936     @Override
getChildVisibleRect(View child, Rect r, android.graphics.Point offset)2937     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
2938         if (child != mView) {
2939             throw new RuntimeException("child is not mine, honest!");
2940         }
2941         // Note: don't apply scroll offset, because we want to know its
2942         // visibility in the virtual canvas being given to the view hierarchy.
2943         return r.intersect(0, 0, mWidth, mHeight);
2944     }
2945 
2946     @Override
getChildLocalHitRegion(@onNull View child, @NonNull Region region, @NonNull Matrix matrix, boolean isHover)2947     public boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region,
2948             @NonNull Matrix matrix, boolean isHover) {
2949         if (child != mView) {
2950             throw new IllegalArgumentException("child " + child + " is not the root view "
2951                     + mView + " managed by this ViewRootImpl");
2952         }
2953 
2954         RectF rectF = new RectF(0, 0, mWidth, mHeight);
2955         matrix.mapRect(rectF);
2956         // Note: don't apply scroll offset, because we want to know its
2957         // visibility in the virtual canvas being given to the view hierarchy.
2958         return region.op(Math.round(rectF.left), Math.round(rectF.top),
2959                 Math.round(rectF.right), Math.round(rectF.bottom), Region.Op.INTERSECT);
2960     }
2961 
2962     @Override
bringChildToFront(View child)2963     public void bringChildToFront(View child) {
2964     }
2965 
2966     // keep in sync with getHostVisibilityReason
getHostVisibility()2967     int getHostVisibility() {
2968         return mView != null && (mAppVisible || mForceDecorViewVisibility)
2969                 ? mView.getVisibility() : View.GONE;
2970     }
2971 
getHostVisibilityReason()2972     String getHostVisibilityReason() {
2973         if (mView == null) {
2974             return "mView is null";
2975         }
2976         if (!mAppVisible && !mForceDecorViewVisibility) {
2977             return "!mAppVisible && !mForceDecorViewVisibility";
2978         }
2979         switch (mView.getVisibility()) {
2980             case View.VISIBLE: return "View.VISIBLE";
2981             case View.GONE: return "View.GONE";
2982             case View.INVISIBLE: return "View.INVISIBLE";
2983             default: return "";
2984         }
2985     }
2986 
2987     /**
2988      * Add LayoutTransition to the list of transitions to be started in the next traversal.
2989      * This list will be cleared after the transitions on the list are start()'ed. These
2990      * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
2991      * happens during the layout phase of traversal, which we want to complete before any of the
2992      * animations are started (because those animations may side-effect properties that layout
2993      * depends upon, like the bounding rectangles of the affected views). So we add the transition
2994      * to the list and it is started just prior to starting the drawing phase of traversal.
2995      *
2996      * @param transition The LayoutTransition to be started on the next traversal.
2997      *
2998      * @hide
2999      */
requestTransitionStart(LayoutTransition transition)3000     public void requestTransitionStart(LayoutTransition transition) {
3001         if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
3002             if (mPendingTransitions == null) {
3003                  mPendingTransitions = new ArrayList<LayoutTransition>();
3004             }
3005             mPendingTransitions.add(transition);
3006         }
3007     }
3008 
3009     /**
3010      * Notifies the HardwareRenderer that a new frame will be coming soon.
3011      * Currently only {@link ThreadedRenderer} cares about this, and uses
3012      * this knowledge to adjust the scheduling of off-thread animations
3013      */
notifyRendererOfFramePending()3014     void notifyRendererOfFramePending() {
3015         if (mAttachInfo.mThreadedRenderer != null) {
3016             mAttachInfo.mThreadedRenderer.notifyFramePending();
3017         }
3018     }
3019 
3020     /**
3021      * Notifies the HardwareRenderer of an expensive upcoming frame, to
3022      * allow better handling of power and scheduling requirements.
3023      *
3024      * @hide
3025      */
notifyRendererOfExpensiveFrame()3026     public void notifyRendererOfExpensiveFrame() {
3027         if (mAttachInfo.mThreadedRenderer != null) {
3028             mAttachInfo.mThreadedRenderer.notifyExpensiveFrame();
3029         }
3030     }
3031 
3032     /**
3033      * Same as notifyRendererOfExpensiveFrame(), but adding {@code reason} for tracing.
3034      *
3035      * @hide
3036      */
notifyRendererOfExpensiveFrame(String reason)3037     public void notifyRendererOfExpensiveFrame(String reason) {
3038         Trace.traceBegin(Trace.TRACE_TAG_VIEW, reason);
3039         try {
3040             notifyRendererOfExpensiveFrame();
3041         } finally {
3042             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
3043         }
3044     }
3045 
3046     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
scheduleTraversals()3047     void scheduleTraversals() {
3048         if (!mTraversalScheduled) {
3049             mTraversalScheduled = true;
3050             mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
3051             mChoreographer.postCallback(
3052                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
3053             notifyRendererOfFramePending();
3054             pokeDrawLockIfNeeded();
3055         }
3056     }
3057 
unscheduleTraversals()3058     void unscheduleTraversals() {
3059         if (mTraversalScheduled) {
3060             mTraversalScheduled = false;
3061             mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
3062             mChoreographer.removeCallbacks(
3063                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
3064         }
3065     }
3066 
doTraversal()3067     void doTraversal() {
3068         if (mTraversalScheduled) {
3069             mTraversalScheduled = false;
3070             mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
3071 
3072             if (mProfile) {
3073                 Debug.startMethodTracing("ViewAncestor");
3074             }
3075 
3076             performTraversals();
3077 
3078             if (mProfile) {
3079                 Debug.stopMethodTracing();
3080                 mProfile = false;
3081             }
3082         }
3083     }
3084 
applyKeepScreenOnFlag(WindowManager.LayoutParams params)3085     private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
3086         // Update window's global keep screen on flag: if a view has requested
3087         // that the screen be kept on, then it is always set; otherwise, it is
3088         // set to whatever the client last requested for the global state.
3089         if (mAttachInfo.mKeepScreenOn) {
3090             params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
3091         } else {
3092             params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
3093                     | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
3094         }
3095     }
3096 
collectViewAttributes()3097     private boolean collectViewAttributes() {
3098         if (mAttachInfo.mRecomputeGlobalAttributes) {
3099             //Log.i(mTag, "Computing view hierarchy attributes!");
3100             mAttachInfo.mRecomputeGlobalAttributes = false;
3101             boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
3102             mAttachInfo.mKeepScreenOn = false;
3103             mAttachInfo.mSystemUiVisibility = 0;
3104             mAttachInfo.mHasSystemUiListeners = false;
3105             mView.dispatchCollectViewAttributes(mAttachInfo, 0);
3106             mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
3107             WindowManager.LayoutParams params = mWindowAttributes;
3108             mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
3109             mCompatibleVisibilityInfo.globalVisibility =
3110                     (mCompatibleVisibilityInfo.globalVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE)
3111                             | (mAttachInfo.mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
3112             dispatchDispatchSystemUiVisibilityChanged();
3113             if (mAttachInfo.mKeepScreenOn != oldScreenOn
3114                     || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
3115                     || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
3116                 applyKeepScreenOnFlag(params);
3117                 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
3118                 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
3119                 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
3120                 return true;
3121             }
3122         }
3123         return false;
3124     }
3125 
getImpliedSystemUiVisibility(WindowManager.LayoutParams params)3126     private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
3127         int vis = 0;
3128         // Translucent decor window flags imply stable system ui visibility.
3129         if ((params.flags & FLAG_TRANSLUCENT_STATUS) != 0) {
3130             vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
3131         }
3132         if ((params.flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) {
3133             vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
3134         }
3135         return vis;
3136     }
3137 
3138     /**
3139      * Update the compatible system UI visibility for dispatching it to the legacy app.
3140      */
updateCompatSysUiVisibility(@nsetsType int visibleTypes, @InsetsType int requestedVisibleTypes, @InsetsType int controllableTypes)3141     void updateCompatSysUiVisibility(@InsetsType int visibleTypes,
3142             @InsetsType int requestedVisibleTypes, @InsetsType int controllableTypes) {
3143         // If a type is controllable, the visibility is overridden by the requested visibility.
3144         visibleTypes =
3145                 (requestedVisibleTypes & controllableTypes) | (visibleTypes & ~controllableTypes);
3146 
3147         updateCompatSystemUiVisibilityInfo(SYSTEM_UI_FLAG_FULLSCREEN, Type.statusBars(),
3148                 visibleTypes, controllableTypes);
3149         updateCompatSystemUiVisibilityInfo(SYSTEM_UI_FLAG_HIDE_NAVIGATION, Type.navigationBars(),
3150                 visibleTypes, controllableTypes);
3151         dispatchDispatchSystemUiVisibilityChanged();
3152     }
3153 
updateCompatSystemUiVisibilityInfo(int systemUiFlag, @InsetsType int insetsType, @InsetsType int visibleTypes, @InsetsType int controllableTypes)3154     private void updateCompatSystemUiVisibilityInfo(int systemUiFlag, @InsetsType int insetsType,
3155             @InsetsType int visibleTypes, @InsetsType int controllableTypes) {
3156         final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
3157         final boolean willBeVisible = (visibleTypes & insetsType) != 0;
3158         final boolean hasControl = (controllableTypes & insetsType) != 0;
3159         final boolean wasInvisible = (mAttachInfo.mSystemUiVisibility & systemUiFlag) != 0;
3160         if (willBeVisible) {
3161             info.globalVisibility &= ~systemUiFlag;
3162             if (hasControl && wasInvisible) {
3163                 // The local system UI visibility can only be cleared while we have the control.
3164                 info.localChanges |= systemUiFlag;
3165             }
3166         } else {
3167             info.globalVisibility |= systemUiFlag;
3168             info.localChanges &= ~systemUiFlag;
3169         }
3170     }
3171 
3172     /**
3173      * If the system is forcing showing any system bar, the legacy low profile flag should be
3174      * cleared for compatibility.
3175      *
3176      * @param showTypes {@link InsetsType types} shown by the system.
3177      * @param fromIme {@code true} if the invocation is from IME.
3178      */
clearLowProfileModeIfNeeded(@nsetsType int showTypes, boolean fromIme)3179     private void clearLowProfileModeIfNeeded(@InsetsType int showTypes, boolean fromIme) {
3180         final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
3181         if ((showTypes & Type.systemBars()) != 0 && !fromIme
3182                 && (info.globalVisibility & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
3183             info.globalVisibility &= ~SYSTEM_UI_FLAG_LOW_PROFILE;
3184             info.localChanges |= SYSTEM_UI_FLAG_LOW_PROFILE;
3185             dispatchDispatchSystemUiVisibilityChanged();
3186         }
3187     }
3188 
dispatchDispatchSystemUiVisibilityChanged()3189     private void dispatchDispatchSystemUiVisibilityChanged() {
3190         if (mDispatchedSystemUiVisibility != mCompatibleVisibilityInfo.globalVisibility) {
3191             mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY);
3192             mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY));
3193         }
3194     }
3195 
handleDispatchSystemUiVisibilityChanged()3196     private void handleDispatchSystemUiVisibilityChanged() {
3197         if (mView == null) {
3198             return;
3199         }
3200         final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
3201         if (info.localChanges != 0) {
3202             mView.updateLocalSystemUiVisibility(info.localValue, info.localChanges);
3203             info.localChanges = 0;
3204         }
3205 
3206         final int visibility = info.globalVisibility & View.SYSTEM_UI_CLEARABLE_FLAGS;
3207         if (mDispatchedSystemUiVisibility != visibility) {
3208             mDispatchedSystemUiVisibility = visibility;
3209             mView.dispatchSystemUiVisibilityChanged(visibility);
3210         }
3211     }
3212 
3213     @VisibleForTesting
adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams, @Appearance int appearanceControlled, boolean behaviorControlled)3214     public static void adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams,
3215             @Appearance int appearanceControlled, boolean behaviorControlled) {
3216         final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility;
3217         final int flags = inOutParams.flags;
3218         final int type = inOutParams.type;
3219         final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST;
3220 
3221         @Appearance int appearance = inOutParams.insetsFlags.appearance;
3222         if ((appearanceControlled & APPEARANCE_LOW_PROFILE_BARS) == 0) {
3223             appearance &= ~APPEARANCE_LOW_PROFILE_BARS;
3224             appearance |= (sysUiVis & SYSTEM_UI_FLAG_LOW_PROFILE) != 0
3225                     ? APPEARANCE_LOW_PROFILE_BARS
3226                     : 0;
3227         }
3228         if ((appearanceControlled & APPEARANCE_LIGHT_STATUS_BARS) == 0) {
3229             appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
3230             appearance |= (sysUiVis & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
3231                     ? APPEARANCE_LIGHT_STATUS_BARS
3232                     : 0;
3233         }
3234         if ((appearanceControlled & APPEARANCE_LIGHT_NAVIGATION_BARS) == 0) {
3235             appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
3236             appearance |= (sysUiVis & SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0
3237                     ? APPEARANCE_LIGHT_NAVIGATION_BARS
3238                     : 0;
3239         }
3240         inOutParams.insetsFlags.appearance = appearance;
3241 
3242         if (!behaviorControlled) {
3243             if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
3244                     || (flags & FLAG_FULLSCREEN) != 0) {
3245                 inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
3246             } else {
3247                 inOutParams.insetsFlags.behavior = BEHAVIOR_DEFAULT;
3248             }
3249         }
3250 
3251         inOutParams.privateFlags &= ~PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
3252 
3253         if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) {
3254             return;
3255         }
3256 
3257         int types = inOutParams.getFitInsetsTypes();
3258         boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility();
3259 
3260         if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0
3261                 || (flags & FLAG_LAYOUT_IN_SCREEN) != 0)
3262                 || (flags & FLAG_TRANSLUCENT_STATUS) != 0) {
3263             types &= ~Type.statusBars();
3264         }
3265         if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
3266                 || (flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) {
3267             types &= ~Type.systemBars();
3268         }
3269         if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
3270             ignoreVis = true;
3271         } else if ((types & Type.systemBars()) == Type.systemBars()) {
3272             if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
3273                 types |= Type.ime();
3274             } else {
3275                 inOutParams.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
3276             }
3277         }
3278         inOutParams.setFitInsetsTypes(types);
3279         inOutParams.setFitInsetsIgnoringVisibility(ignoreVis);
3280 
3281         // The fitting of insets are not really controlled by the clients, so we remove the flag.
3282         inOutParams.privateFlags &= ~PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
3283     }
3284 
3285     /** Updates the {@link InsetsType}s to hide or show based on layout params. */
3286     @VisibleForTesting
controlInsetsForCompatibility(WindowManager.LayoutParams params)3287     public void controlInsetsForCompatibility(WindowManager.LayoutParams params) {
3288         final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility;
3289         final int flags = params.flags;
3290         final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT;
3291         final boolean nonAttachedAppWindow = params.type >= FIRST_APPLICATION_WINDOW
3292                 && params.type <= LAST_APPLICATION_WINDOW;
3293         final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0;
3294         final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0
3295                 || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow);
3296         final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0;
3297         final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3298         final boolean captionWasHiddenByFlags = (mTypesHiddenByFlags & Type.captionBar()) != 0;
3299         final boolean captionIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0
3300                 || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow);
3301 
3302         @InsetsType int typesToHide = 0;
3303         @InsetsType int typesToShow = 0;
3304         if (statusIsHiddenByFlags && !statusWasHiddenByFlags) {
3305             typesToHide |= Type.statusBars();
3306         } else if (!statusIsHiddenByFlags && statusWasHiddenByFlags) {
3307             typesToShow |= Type.statusBars();
3308         }
3309         if (navIsHiddenByFlags && !navWasHiddenByFlags) {
3310             typesToHide |= Type.navigationBars();
3311         } else if (!navIsHiddenByFlags && navWasHiddenByFlags) {
3312             typesToShow |= Type.navigationBars();
3313         }
3314         if (captionIsHiddenByFlags && !captionWasHiddenByFlags
3315                 && ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()) {
3316             typesToHide |= Type.captionBar();
3317         } else if (!captionIsHiddenByFlags && captionWasHiddenByFlags
3318                 && ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()) {
3319             typesToShow |= Type.captionBar();
3320         }
3321         if (typesToHide != 0) {
3322             getInsetsController().hide(typesToHide);
3323         }
3324         if (typesToShow != 0) {
3325             getInsetsController().show(typesToShow);
3326         }
3327         mTypesHiddenByFlags |= typesToHide;
3328         mTypesHiddenByFlags &= ~typesToShow;
3329     }
3330 
measureHierarchy(final View host, final WindowManager.LayoutParams lp, final Resources res, final int desiredWindowWidth, final int desiredWindowHeight, boolean forRootSizeOnly)3331     private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
3332             final Resources res, final int desiredWindowWidth, final int desiredWindowHeight,
3333             boolean forRootSizeOnly) {
3334         int childWidthMeasureSpec;
3335         int childHeightMeasureSpec;
3336         boolean windowSizeMayChange = false;
3337 
3338         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
3339                 "Measuring " + host + " in display " + desiredWindowWidth
3340                 + "x" + desiredWindowHeight + "...");
3341 
3342         boolean goodMeasure = false;
3343         if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
3344             // On large screens, we don't want to allow dialogs to just
3345             // stretch to fill the entire width of the screen to display
3346             // one line of text.  First try doing the layout at a smaller
3347             // size to see if it will fit.
3348             final DisplayMetrics packageMetrics = res.getDisplayMetrics();
3349             res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
3350             int baseSize = 0;
3351             if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
3352                 baseSize = (int)mTmpValue.getDimension(packageMetrics);
3353             }
3354             if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
3355                     + ", desiredWindowWidth=" + desiredWindowWidth);
3356             if (baseSize != 0 && desiredWindowWidth > baseSize) {
3357                 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags);
3358                 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,
3359                         lp.privateFlags);
3360                 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3361                 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
3362                         + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
3363                         + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
3364                         + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
3365                 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
3366                     goodMeasure = true;
3367                 } else {
3368                     // Didn't fit in that size... try expanding a bit.
3369                     baseSize = (baseSize+desiredWindowWidth)/2;
3370                     if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
3371                             + baseSize);
3372                     childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags);
3373                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3374                     if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
3375                             + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
3376                     if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
3377                         if (DEBUG_DIALOG) Log.v(mTag, "Good!");
3378                         goodMeasure = true;
3379                     }
3380                 }
3381             }
3382         }
3383 
3384         if (!goodMeasure) {
3385             childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width,
3386                     lp.privateFlags);
3387             childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,
3388                     lp.privateFlags);
3389             if (!forRootSizeOnly || !setMeasuredRootSizeFromSpec(
3390                     childWidthMeasureSpec, childHeightMeasureSpec)) {
3391                 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3392             } else {
3393                 // We already know how big the window should be before measuring the views.
3394                 // We can measure the views before laying out them. This is to avoid unnecessary
3395                 // measure.
3396                 mViewMeasureDeferred = true;
3397             }
3398             if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
3399                 windowSizeMayChange = true;
3400             }
3401         }
3402 
3403         if (DBG) {
3404             System.out.println("======================================");
3405             System.out.println("performTraversals -- after measure");
3406             host.debug();
3407         }
3408 
3409         return windowSizeMayChange;
3410     }
3411 
3412     /**
3413      * Sets the measured root size for requesting the window frame.
3414      *
3415      * @param widthMeasureSpec contains the size and the mode of the width.
3416      * @param heightMeasureSpec contains the size and the mode of the height.
3417      * @return {@code true} if we actually set the measured size; {@code false} otherwise.
3418      */
setMeasuredRootSizeFromSpec(int widthMeasureSpec, int heightMeasureSpec)3419     private boolean setMeasuredRootSizeFromSpec(int widthMeasureSpec, int heightMeasureSpec) {
3420         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
3421         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
3422         if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
3423             // We don't know the exact size. We need to measure the hierarchy to know that.
3424             return false;
3425         }
3426         mMeasuredWidth = MeasureSpec.getSize(widthMeasureSpec);
3427         mMeasuredHeight = MeasureSpec.getSize(heightMeasureSpec);
3428         return true;
3429     }
3430 
3431     /**
3432      * Modifies the input matrix such that it maps view-local coordinates to
3433      * on-screen coordinates.
3434      *
3435      * @param m input matrix to modify
3436      */
transformMatrixToGlobal(Matrix m)3437     void transformMatrixToGlobal(Matrix m) {
3438         m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
3439     }
3440 
3441     /**
3442      * Modifies the input matrix such that it maps on-screen coordinates to
3443      * view-local coordinates.
3444      *
3445      * @param m input matrix to modify
3446      */
transformMatrixToLocal(Matrix m)3447     void transformMatrixToLocal(Matrix m) {
3448         m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
3449     }
3450 
getWindowInsets(boolean forceConstruct)3451     /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
3452         if (mLastWindowInsets == null || forceConstruct) {
3453             final Configuration config = getConfiguration();
3454             mLastWindowInsets = mInsetsController.calculateInsets(
3455                     config.isScreenRound(), mWindowAttributes.type,
3456                     config.windowConfiguration.getActivityType(), mWindowAttributes.softInputMode,
3457                     mWindowAttributes.flags, (mWindowAttributes.systemUiVisibility
3458                             | mWindowAttributes.subtreeSystemUiVisibility));
3459 
3460             mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect());
3461             mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect());
3462             mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets(
3463                     mWindowAttributes.type, config.windowConfiguration.getActivityType(),
3464                     mWindowAttributes.softInputMode, mWindowAttributes.flags).toRect());
3465         }
3466         return mLastWindowInsets;
3467     }
3468 
dispatchApplyInsets(View host)3469     public void dispatchApplyInsets(View host) {
3470         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchApplyInsets");
3471         mApplyInsetsRequested = false;
3472         WindowInsets insets = getWindowInsets(true /* forceConstruct */);
3473         if (!shouldDispatchCutout()) {
3474             // Window is either not laid out in cutout or the status bar inset takes care of
3475             // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
3476             insets = insets.consumeDisplayCutout();
3477         }
3478         host.dispatchApplyWindowInsets(insets);
3479         mAttachInfo.delayNotifyContentCaptureInsetsEvent(insets.getInsets(Type.all()));
3480         Trace.traceEnd(Trace.TRACE_TAG_VIEW);
3481     }
3482 
shouldDispatchCutout()3483     private boolean shouldDispatchCutout() {
3484         return mWindowAttributes.layoutInDisplayCutoutMode
3485                         == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
3486                 || mWindowAttributes.layoutInDisplayCutoutMode
3487                         == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3488     }
3489 
getInsetsController()3490     public InsetsController getInsetsController() {
3491         return mInsetsController;
3492     }
3493 
shouldUseDisplaySize(final WindowManager.LayoutParams lp)3494     private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
3495         return lp.type == TYPE_STATUS_BAR_ADDITIONAL
3496                 || lp.type == TYPE_INPUT_METHOD
3497                 || lp.type == TYPE_VOLUME_OVERLAY;
3498     }
3499 
3500     /**
3501      * @return {@code true} if we should reduce unnecessary measure for the window.
3502      * TODO(b/260382739): Apply this to all windows.
3503      */
shouldOptimizeMeasure(final WindowManager.LayoutParams lp)3504     private static boolean shouldOptimizeMeasure(final WindowManager.LayoutParams lp) {
3505         if (com.android.window.flags.Flags.reduceUnnecessaryMeasure()) {
3506             return true;
3507         }
3508         return (lp.privateFlags & PRIVATE_FLAG_OPTIMIZE_MEASURE) != 0;
3509     }
3510 
getWindowBoundsInsetSystemBars()3511     private Rect getWindowBoundsInsetSystemBars() {
3512         final Rect bounds = new Rect(
3513                 mContext.getResources().getConfiguration().windowConfiguration.getBounds());
3514         bounds.inset(mInsetsController.getState().calculateInsets(
3515                 bounds, Type.systemBars(), false /* ignoreVisibility */));
3516         return bounds;
3517     }
3518 
dipToPx(int dip)3519     int dipToPx(int dip) {
3520         final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
3521         return (int) (displayMetrics.density * dip + 0.5f);
3522     }
3523 
performTraversals()3524     private void performTraversals() {
3525         mLastPerformTraversalsSkipDrawReason = null;
3526 
3527         // cache mView since it is used so much below...
3528         final View host = mView;
3529         if (DBG) {
3530             System.out.println("======================================");
3531             System.out.println("performTraversals");
3532             host.debug();
3533         }
3534 
3535         if (host == null || !mAdded) {
3536             mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added";
3537             return;
3538         }
3539 
3540         if (mNumPausedForSync > 0) {
3541             if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
3542                 Trace.instant(Trace.TRACE_TAG_VIEW,
3543                         TextUtils.formatSimple("performTraversals#mNumPausedForSync=%d",
3544                                 mNumPausedForSync));
3545             }
3546             if (DEBUG_BLAST) {
3547                 Log.d(mTag, "Skipping traversal due to sync " + mNumPausedForSync);
3548             }
3549             mLastPerformTraversalsSkipDrawReason = "paused_for_sync";
3550             return;
3551         }
3552 
3553         mIsInTraversal = true;
3554         mWillDrawSoon = true;
3555         boolean cancelDraw = false;
3556         String cancelReason = null;
3557         boolean isSyncRequest = false;
3558 
3559         boolean windowSizeMayChange = false;
3560         WindowManager.LayoutParams lp = mWindowAttributes;
3561 
3562         int desiredWindowWidth;
3563         int desiredWindowHeight;
3564 
3565         final int viewVisibility = getHostVisibility();
3566         final String viewVisibilityReason = getHostVisibilityReason();
3567         final boolean viewVisibilityChanged = !mFirst
3568                 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded
3569                 // Also check for possible double visibility update, which will make current
3570                 // viewVisibility value equal to mViewVisibility and we may miss it.
3571                 || mAppVisibilityChanged);
3572         mAppVisibilityChanged = false;
3573         final boolean viewUserVisibilityChanged = !mFirst &&
3574                 ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
3575         final boolean shouldOptimizeMeasure = shouldOptimizeMeasure(lp);
3576 
3577         WindowManager.LayoutParams params = null;
3578         Rect frame = mWinFrame;
3579         if (mFirst) {
3580             mFullRedrawNeeded = true;
3581             mLayoutRequested = true;
3582 
3583             final Configuration config = getConfiguration();
3584             if (shouldUseDisplaySize(lp)) {
3585                 // NOTE -- system code, won't try to do compat mode.
3586                 Point size = new Point();
3587                 mDisplay.getRealSize(size);
3588                 desiredWindowWidth = size.x;
3589                 desiredWindowHeight = size.y;
3590             } else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
3591                     || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
3592                 // For wrap content, we have to remeasure later on anyways. Use size consistent with
3593                 // below so we get best use of the measure cache.
3594                 final Rect bounds = getWindowBoundsInsetSystemBars();
3595                 desiredWindowWidth = bounds.width();
3596                 desiredWindowHeight = bounds.height();
3597             } else {
3598                 // After addToDisplay, the frame contains the frameHint from window manager, which
3599                 // for most windows is going to be the same size as the result of relayoutWindow.
3600                 // Using this here allows us to avoid remeasuring after relayoutWindow
3601                 desiredWindowWidth = frame.width();
3602                 desiredWindowHeight = frame.height();
3603             }
3604 
3605             // We used to use the following condition to choose 32 bits drawing caches:
3606             // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
3607             // However, windows are now always 32 bits by default, so choose 32 bits
3608             mAttachInfo.mUse32BitDrawingCache = true;
3609             mAttachInfo.mWindowVisibility = viewVisibility;
3610             mAttachInfo.mRecomputeGlobalAttributes = false;
3611             mLastConfigurationFromResources.setTo(config);
3612             mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
3613             // Set the layout direction if it has not been set before (inherit is the default)
3614             if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
3615                 host.setLayoutDirection(config.getLayoutDirection());
3616             }
3617             host.dispatchAttachedToWindow(mAttachInfo, 0);
3618             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
3619             dispatchApplyInsets(host);
3620             if (!mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()
3621                     // Don't register compat OnBackInvokedCallback for windowless window.
3622                     // The onBackInvoked event by default should forward to host app, so the
3623                     // host app can decide the behavior.
3624                     && mWindowlessBackKeyCallback == null) {
3625                 // For apps requesting legacy back behavior, we add a compat callback that
3626                 // dispatches {@link KeyEvent#KEYCODE_BACK} to their root views.
3627                 // This way from system point of view, these apps are providing custom
3628                 // {@link OnBackInvokedCallback}s, and will not play system back animations
3629                 // for them.
3630                 registerCompatOnBackInvokedCallback();
3631             }
3632         } else {
3633             desiredWindowWidth = frame.width();
3634             desiredWindowHeight = frame.height();
3635             if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
3636                 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
3637                 mFullRedrawNeeded = true;
3638                 mLayoutRequested = true;
3639                 windowSizeMayChange = true;
3640             }
3641         }
3642 
3643         if (viewVisibilityChanged) {
3644             mAttachInfo.mWindowVisibility = viewVisibility;
3645             host.dispatchWindowVisibilityChanged(viewVisibility);
3646             mAttachInfo.mTreeObserver.dispatchOnWindowVisibilityChange(viewVisibility);
3647             if (viewUserVisibilityChanged) {
3648                 host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
3649             }
3650             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
3651                 endDragResizing();
3652                 destroyHardwareResources();
3653             }
3654 
3655             if (shouldEnableDvrr() && viewVisibility == View.VISIBLE) {
3656                 // Boost frame rate when the viewVisibility becomes true.
3657                 // This is mainly for lanuchers that lanuch new windows.
3658                 boostFrameRate(FRAME_RATE_BOOST_TIME);
3659             }
3660         }
3661 
3662         // Non-visible windows can't hold accessibility focus.
3663         if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
3664             host.clearAccessibilityFocus();
3665         }
3666 
3667         // Execute enqueued actions on every traversal in case a detached view enqueued an action
3668         getRunQueue().executeActions(mAttachInfo.mHandler);
3669 
3670         if (mFirst) {
3671             // make sure touch mode code executes by setting cached value
3672             // to opposite of the added touch mode.
3673             mAttachInfo.mInTouchMode = !mAddedTouchMode;
3674             ensureTouchModeLocally(mAddedTouchMode);
3675         }
3676 
3677         boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
3678         if (layoutRequested) {
3679             if (!mFirst) {
3680                 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
3681                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
3682                     windowSizeMayChange = true;
3683 
3684                     if (shouldUseDisplaySize(lp)) {
3685                         // NOTE -- system code, won't try to do compat mode.
3686                         Point size = new Point();
3687                         mDisplay.getRealSize(size);
3688                         desiredWindowWidth = size.x;
3689                         desiredWindowHeight = size.y;
3690                     } else {
3691                         final Rect bounds = getWindowBoundsInsetSystemBars();
3692                         desiredWindowWidth = bounds.width();
3693                         desiredWindowHeight = bounds.height();
3694                     }
3695                 }
3696             }
3697 
3698             // Ask host how big it wants to be
3699             windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(),
3700                     desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure);
3701         }
3702 
3703         if (collectViewAttributes()) {
3704             params = lp;
3705         }
3706         if (mAttachInfo.mForceReportNewAttributes) {
3707             mAttachInfo.mForceReportNewAttributes = false;
3708             params = lp;
3709         }
3710 
3711         if (mFirst || mAttachInfo.mViewVisibilityChanged) {
3712             mAttachInfo.mViewVisibilityChanged = false;
3713             int resizeMode = mSoftInputMode & SOFT_INPUT_MASK_ADJUST;
3714             // If we are in auto resize mode, then we need to determine
3715             // what mode to use now.
3716             if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
3717                 final int N = mAttachInfo.mScrollContainers.size();
3718                 for (int i=0; i<N; i++) {
3719                     if (mAttachInfo.mScrollContainers.get(i).isShown()) {
3720                         resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
3721                     }
3722                 }
3723                 if (resizeMode == 0) {
3724                     resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
3725                 }
3726                 if ((lp.softInputMode & SOFT_INPUT_MASK_ADJUST) != resizeMode) {
3727                     lp.softInputMode = (lp.softInputMode & ~SOFT_INPUT_MASK_ADJUST) | resizeMode;
3728                     params = lp;
3729                 }
3730             }
3731         }
3732 
3733         if (mApplyInsetsRequested) {
3734             dispatchApplyInsets(host);
3735             if (mLayoutRequested) {
3736                 // Short-circuit catching a new layout request here, so
3737                 // we don't need to go through two layout passes when things
3738                 // change due to fitting system windows, which can happen a lot.
3739                 windowSizeMayChange |= measureHierarchy(host, lp,
3740                         mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight,
3741                         shouldOptimizeMeasure);
3742             }
3743         }
3744 
3745         if (layoutRequested) {
3746             // Clear this now, so that if anything requests a layout in the
3747             // rest of this function we will catch it and re-run a full
3748             // layout pass.
3749             mLayoutRequested = false;
3750         }
3751 
3752         boolean windowShouldResize = layoutRequested && windowSizeMayChange
3753             && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
3754                 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
3755                         frame.width() < desiredWindowWidth && frame.width() != mWidth)
3756                 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
3757                         frame.height() < desiredWindowHeight && frame.height() != mHeight));
3758         windowShouldResize |= mDragResizing && mPendingDragResizing;
3759 
3760         // Determine whether to compute insets.
3761         // If there are no inset listeners remaining then we may still need to compute
3762         // insets in case the old insets were non-empty and must be reset.
3763         final boolean computesInternalInsets =
3764                 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
3765                 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
3766 
3767         boolean insetsPending = false;
3768         int relayoutResult = 0;
3769         boolean updatedConfiguration = false;
3770 
3771         final int surfaceGenerationId = mSurface.getGenerationId();
3772 
3773         final boolean isViewVisible = viewVisibility == View.VISIBLE;
3774         boolean surfaceSizeChanged = false;
3775         boolean surfaceCreated = false;
3776         boolean surfaceDestroyed = false;
3777         // True if surface generation id changes or relayout result is RELAYOUT_RES_SURFACE_CHANGED.
3778         boolean surfaceReplaced = false;
3779 
3780         final boolean windowAttributesChanged = mWindowAttributesChanged;
3781         if (windowAttributesChanged) {
3782             mWindowAttributesChanged = false;
3783             params = lp;
3784         }
3785 
3786         if (params != null) {
3787             if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0
3788                     && !PixelFormat.formatHasAlpha(params.format)) {
3789                 params.format = PixelFormat.TRANSLUCENT;
3790             }
3791             adjustLayoutParamsForCompatibility(params,
3792                     mInsetsController.getAppearanceControlled(),
3793                     mInsetsController.isBehaviorControlled());
3794             controlInsetsForCompatibility(params);
3795             if (mDispatchedSystemBarAppearance != params.insetsFlags.appearance) {
3796                 mDispatchedSystemBarAppearance = params.insetsFlags.appearance;
3797                 mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance);
3798             }
3799         }
3800 
3801         if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
3802                 || mForceNextWindowRelayout) {
3803             if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
3804                 Trace.traceBegin(Trace.TRACE_TAG_VIEW,
3805                         TextUtils.formatSimple("%s-relayoutWindow#"
3806                                         + "first=%b/resize=%b/vis=%b/params=%b/force=%b", mTag,
3807                                 mFirst, windowShouldResize, viewVisibilityChanged, params != null,
3808                                 mForceNextWindowRelayout));
3809             }
3810 
3811             mForceNextWindowRelayout = false;
3812 
3813             // If this window is giving internal insets to the window manager, then we want to first
3814             // make the provided insets unchanged during layout. This avoids it briefly causing
3815             // other windows to resize/move based on the raw frame of the window, waiting until we
3816             // can finish laying out this window and get back to the window manager with the
3817             // ultimately computed insets.
3818             insetsPending = computesInternalInsets
3819                     // If this window provides insets via params, its insets source frame can be
3820                     // updated directly without waiting for WindowSession#setInsets.
3821                     && mWindowAttributes.providedInsets == null;
3822 
3823             if (mSurfaceHolder != null) {
3824                 mSurfaceHolder.mSurfaceLock.lock();
3825                 mDrawingAllowed = true;
3826             }
3827 
3828             boolean hwInitialized = false;
3829             boolean dispatchApplyInsets = false;
3830             boolean hadSurface = mSurface.isValid();
3831 
3832             try {
3833                 if (DEBUG_LAYOUT) {
3834                     Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
3835                             host.getMeasuredHeight() + ", params=" + params);
3836                 }
3837 
3838                 if (mFirst || viewVisibilityChanged) {
3839                     mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
3840                 }
3841                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
3842                 cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW)
3843                         == RELAYOUT_RES_CANCEL_AND_REDRAW;
3844                 cancelReason = "relayout";
3845                 final boolean dragResizing = mPendingDragResizing;
3846                 if (mSyncSeqId > mLastSyncSeqId) {
3847                     mLastSyncSeqId = mSyncSeqId;
3848                     if (DEBUG_BLAST) {
3849                         Log.d(mTag, "Relayout called with blastSync");
3850                     }
3851                     reportNextDraw("relayout");
3852                     mSyncBuffer = true;
3853                     isSyncRequest = true;
3854                     if (!cancelDraw) {
3855                         mDrewOnceForSync = false;
3856                     }
3857                 }
3858 
3859                 final boolean surfaceControlChanged =
3860                         (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
3861                                 == RELAYOUT_RES_SURFACE_CHANGED;
3862 
3863                 if (mSurfaceControl.isValid()) {
3864                     updateOpacity(mWindowAttributes, dragResizing,
3865                             surfaceControlChanged /*forceUpdate */);
3866                     // No need to updateDisplayDecoration if it's a new SurfaceControl and
3867                     // mDisplayDecorationCached is false, since that's the default for a new
3868                     // SurfaceControl.
3869                     if (surfaceControlChanged && mDisplayDecorationCached) {
3870                         updateDisplayDecoration();
3871                     }
3872                     if (surfaceControlChanged
3873                             && mWindowAttributes.type
3874                             == WindowManager.LayoutParams.TYPE_STATUS_BAR) {
3875                         mTransaction.setDefaultFrameRateCompatibility(mSurfaceControl,
3876                             Surface.FRAME_RATE_COMPATIBILITY_NO_VOTE).apply();
3877                     }
3878 
3879                     if (setScPropertiesInClient()) {
3880                         if (surfaceControlChanged || windowAttributesChanged) {
3881                             boolean colorSpaceAgnostic = (lp.privateFlags
3882                                     & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC)
3883                                     != 0;
3884                             mTransaction.setColorSpaceAgnostic(mSurfaceControl, colorSpaceAgnostic)
3885                                     .apply();
3886                         }
3887                     }
3888                 }
3889 
3890                 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
3891                         + " surface=" + mSurface);
3892 
3893                 // If the pending {@link MergedConfiguration} handed back from
3894                 // {@link #relayoutWindow} does not match the one last reported,
3895                 // WindowManagerService has reported back a frame from a configuration not yet
3896                 // handled by the client. In this case, we need to accept the configuration so we
3897                 // do not lay out and draw with the wrong configuration.
3898                 boolean shouldPerformConfigurationUpdate =
3899                         !mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)
3900                                 || !Objects.equals(mPendingActivityWindowInfo,
3901                                 mLastReportedActivityWindowInfo);
3902                 if (mRelayoutRequested && shouldPerformConfigurationUpdate) {
3903                     if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
3904                             + mPendingMergedConfiguration.getMergedConfiguration());
3905                     performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration),
3906                             !mFirst, INVALID_DISPLAY /* same display */,
3907                             mPendingActivityWindowInfo != null
3908                                     ? new ActivityWindowInfo(mPendingActivityWindowInfo)
3909                                     : null);
3910                     updatedConfiguration = true;
3911                 }
3912                 final boolean updateSurfaceNeeded = mUpdateSurfaceNeeded;
3913                 mUpdateSurfaceNeeded = false;
3914 
3915                 surfaceSizeChanged = false;
3916                 if (!mLastSurfaceSize.equals(mSurfaceSize)) {
3917                     surfaceSizeChanged = true;
3918                     mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y);
3919                 }
3920                 final boolean alwaysConsumeSystemBarsChanged =
3921                         mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
3922                 updateColorModeIfNeeded(lp.getColorMode(), lp.getDesiredHdrHeadroom());
3923                 surfaceCreated = !hadSurface && mSurface.isValid();
3924                 surfaceDestroyed = hadSurface && !mSurface.isValid();
3925 
3926                 // When using Blast, the surface generation id may not change when there's a new
3927                 // SurfaceControl. In that case, we also check relayout flag
3928                 // RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
3929                 // SurfaceControl.
3930                 surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()
3931                         || surfaceControlChanged) && mSurface.isValid();
3932                 if (surfaceReplaced) {
3933                     mSurfaceReplaced = true;
3934                     mSurfaceSequenceId++;
3935                     mHandler.removeMessages(MSG_SURFACE_REPLACED_TIMEOUT);
3936                     mHandler.sendEmptyMessageDelayed(MSG_SURFACE_REPLACED_TIMEOUT,
3937                             FRAME_RATE_SURFACE_REPLACED_TIME);
3938                 }
3939                 if (alwaysConsumeSystemBarsChanged) {
3940                     mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars;
3941                     dispatchApplyInsets = true;
3942                 }
3943                 if (dispatchApplyInsets || mLastSystemUiVisibility !=
3944                         mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) {
3945                     mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
3946                     dispatchApplyInsets(host);
3947                     // We applied insets so force contentInsetsChanged to ensure the
3948                     // hierarchy is measured below.
3949                     dispatchApplyInsets = true;
3950                 }
3951 
3952                 if (surfaceCreated) {
3953                     // If we are creating a new surface, then we need to
3954                     // completely redraw it.
3955                     mFullRedrawNeeded = true;
3956                     mPreviousTransparentRegion.setEmpty();
3957 
3958                     // Only initialize up-front if transparent regions are not
3959                     // requested, otherwise defer to see if the entire window
3960                     // will be transparent
3961                     if (mAttachInfo.mThreadedRenderer != null) {
3962                         try {
3963                             hwInitialized = mAttachInfo.mThreadedRenderer.initialize(mSurface);
3964                             if (hwInitialized && (host.mPrivateFlags
3965                                             & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
3966                                 // Don't pre-allocate if transparent regions
3967                                 // are requested as they may not be needed
3968                                 mAttachInfo.mThreadedRenderer.allocateBuffers();
3969                             }
3970                         } catch (OutOfResourcesException e) {
3971                             handleOutOfResourcesException(e);
3972                             mLastPerformTraversalsSkipDrawReason = "oom_initialize_renderer";
3973                             return;
3974                         }
3975                     }
3976                 } else if (surfaceDestroyed) {
3977                     // If the surface has been removed, then reset the scroll
3978                     // positions.
3979                     if (mLastScrolledFocus != null) {
3980                         mLastScrolledFocus.clear();
3981                     }
3982                     mScrollY = mCurScrollY = 0;
3983                     if (mView instanceof RootViewSurfaceTaker) {
3984                         ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
3985                     }
3986                     if (mScroller != null) {
3987                         mScroller.abortAnimation();
3988                     }
3989                     // Our surface is gone
3990                     if (isHardwareEnabled()) {
3991                         mAttachInfo.mThreadedRenderer.destroy();
3992                     }
3993                 } else if ((surfaceReplaced || surfaceSizeChanged || updateSurfaceNeeded)
3994                         && mSurfaceHolder == null
3995                         && mAttachInfo.mThreadedRenderer != null
3996                         && mSurface.isValid()) {
3997                     mFullRedrawNeeded = true;
3998                     try {
3999                         // Need to do updateSurface (which leads to CanvasContext::setSurface and
4000                         // re-create the EGLSurface) if either the Surface changed (as indicated by
4001                         // generation id), or WindowManager changed the surface size. The latter is
4002                         // because on some chips, changing the consumer side's BufferQueue size may
4003                         // not take effect immediately unless we create a new EGLSurface.
4004                         // Note that frame size change doesn't always imply surface size change (eg.
4005                         // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
4006                         // flag from WindowManager.
4007                         mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
4008                     } catch (OutOfResourcesException e) {
4009                         handleOutOfResourcesException(e);
4010                         mLastPerformTraversalsSkipDrawReason = "oom_update_surface";
4011                         return;
4012                     }
4013                 }
4014 
4015                 if (mDragResizing != dragResizing) {
4016                     if (dragResizing) {
4017                         final boolean backdropSizeMatchesFrame =
4018                                 mWinFrame.width() == mPendingBackDropFrame.width()
4019                                         && mWinFrame.height() == mPendingBackDropFrame.height();
4020                         // TODO: Need cutout?
4021                         startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame,
4022                                 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets);
4023                     } else {
4024                         // We shouldn't come here, but if we come we should end the resize.
4025                         endDragResizing();
4026                     }
4027                 }
4028                 if (!mUseMTRenderer) {
4029                     if (dragResizing) {
4030                         mCanvasOffsetX = mWinFrame.left;
4031                         mCanvasOffsetY = mWinFrame.top;
4032                     } else {
4033                         mCanvasOffsetX = mCanvasOffsetY = 0;
4034                     }
4035                 }
4036             } catch (RemoteException e) {
4037             } finally {
4038                 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
4039                     Trace.traceEnd(Trace.TRACE_TAG_VIEW);
4040                 }
4041             }
4042 
4043             if (DEBUG_ORIENTATION) Log.v(
4044                     TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
4045 
4046             mAttachInfo.mWindowLeft = frame.left;
4047             mAttachInfo.mWindowTop = frame.top;
4048 
4049             // !!FIXME!! This next section handles the case where we did not get the
4050             // window size we asked for. We should avoid this by getting a maximum size from
4051             // the window session beforehand.
4052             if (mWidth != frame.width() || mHeight != frame.height()) {
4053                 mWidth = frame.width();
4054                 mHeight = frame.height();
4055             }
4056 
4057             if (mSurfaceHolder != null) {
4058                 // The app owns the surface; tell it about what is going on.
4059                 if (mSurface.isValid()) {
4060                     // XXX .copyFrom() doesn't work!
4061                     //mSurfaceHolder.mSurface.copyFrom(mSurface);
4062                     mSurfaceHolder.mSurface = mSurface;
4063                 }
4064                 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
4065                 mSurfaceHolder.mSurfaceLock.unlock();
4066                 if (surfaceCreated) {
4067                     mSurfaceHolder.ungetCallbacks();
4068 
4069                     mIsCreating = true;
4070                     SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
4071                     if (callbacks != null) {
4072                         for (SurfaceHolder.Callback c : callbacks) {
4073                             c.surfaceCreated(mSurfaceHolder);
4074                         }
4075                     }
4076                 }
4077 
4078                 if ((surfaceCreated || surfaceReplaced || surfaceSizeChanged
4079                         || windowAttributesChanged) && mSurface.isValid()) {
4080                     SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
4081                     if (callbacks != null) {
4082                         for (SurfaceHolder.Callback c : callbacks) {
4083                             c.surfaceChanged(mSurfaceHolder, lp.format,
4084                                     mWidth, mHeight);
4085                         }
4086                     }
4087                     mIsCreating = false;
4088                 }
4089 
4090                 if (surfaceDestroyed) {
4091                     notifyHolderSurfaceDestroyed();
4092                     mSurfaceHolder.mSurfaceLock.lock();
4093                     try {
4094                         mSurfaceHolder.mSurface = new Surface();
4095                     } finally {
4096                         mSurfaceHolder.mSurfaceLock.unlock();
4097                     }
4098                 }
4099             }
4100 
4101             final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer;
4102             if (threadedRenderer != null && threadedRenderer.isEnabled()) {
4103                 if (hwInitialized
4104                         || mWidth != threadedRenderer.getWidth()
4105                         || mHeight != threadedRenderer.getHeight()
4106                         || mNeedsRendererSetup) {
4107                     threadedRenderer.setup(mWidth, mHeight, mAttachInfo,
4108                             mWindowAttributes.surfaceInsets);
4109                     mNeedsRendererSetup = false;
4110                 }
4111             }
4112 
4113             // TODO: In the CL "ViewRootImpl: Fix issue with early draw report in
4114             // seamless rotation". We moved processing of RELAYOUT_RES_BLAST_SYNC
4115             // earlier in the function, potentially triggering a call to
4116             // reportNextDraw(). That same CL changed this and the next reference
4117             // to wasReportNextDraw, such that this logic would remain undisturbed
4118             // (it continues to operate as if the code was never moved). This was
4119             // done to achieve a more hermetic fix for S, but it's entirely
4120             // possible that checking the most recent value is actually more
4121             // correct here.
4122             if (!mStopped || mReportNextDraw) {
4123                 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
4124                         || dispatchApplyInsets || updatedConfiguration) {
4125                     int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
4126                             lp.privateFlags);
4127                     int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
4128                             lp.privateFlags);
4129 
4130                     if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed!  mWidth="
4131                             + mWidth + " measuredWidth=" + host.getMeasuredWidth()
4132                             + " mHeight=" + mHeight
4133                             + " measuredHeight=" + host.getMeasuredHeight()
4134                             + " dispatchApplyInsets=" + dispatchApplyInsets);
4135 
4136                      // Ask host how big it wants to be
4137                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
4138 
4139                     // Implementation of weights from WindowManager.LayoutParams
4140                     // We just grow the dimensions as needed and re-measure if
4141                     // needs be
4142                     int width = host.getMeasuredWidth();
4143                     int height = host.getMeasuredHeight();
4144                     boolean measureAgain = false;
4145 
4146                     if (lp.horizontalWeight > 0.0f) {
4147                         width += (int) ((mWidth - width) * lp.horizontalWeight);
4148                         childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
4149                                 MeasureSpec.EXACTLY);
4150                         measureAgain = true;
4151                     }
4152                     if (lp.verticalWeight > 0.0f) {
4153                         height += (int) ((mHeight - height) * lp.verticalWeight);
4154                         childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
4155                                 MeasureSpec.EXACTLY);
4156                         measureAgain = true;
4157                     }
4158 
4159                     if (measureAgain) {
4160                         if (DEBUG_LAYOUT) Log.v(mTag,
4161                                 "And hey let's measure once more: width=" + width
4162                                 + " height=" + height);
4163                         performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
4164                     }
4165 
4166                     layoutRequested = true;
4167                 }
4168             }
4169         } else {
4170             // Not the first pass and no window/insets/visibility change but the window
4171             // may have moved and we need check that and if so to update the left and right
4172             // in the attach info. We translate only the window frame since on window move
4173             // the window manager tells us only for the new frame but the insets are the
4174             // same and we do not want to translate them more than once.
4175             maybeHandleWindowMove(frame);
4176         }
4177 
4178         if (mViewMeasureDeferred) {
4179             // It's time to measure the views since we are going to layout them.
4180             performMeasure(
4181                     MeasureSpec.makeMeasureSpec(frame.width(), MeasureSpec.EXACTLY),
4182                     MeasureSpec.makeMeasureSpec(frame.height(), MeasureSpec.EXACTLY));
4183         }
4184 
4185         if (!mRelayoutRequested && mCheckIfCanDraw) {
4186             // We had a sync previously, but we didn't call IWindowSession#relayout in this
4187             // traversal. So we don't know if the sync is complete that we can continue to draw.
4188             // Here invokes cancelDraw to obtain the information.
4189             try {
4190                 cancelDraw = mWindowSession.cancelDraw(mWindow);
4191                 cancelReason = "wm_sync";
4192                 if (DEBUG_BLAST) {
4193                     Log.d(mTag, "cancelDraw returned " + cancelDraw);
4194                 }
4195             } catch (RemoteException e) {
4196             }
4197         }
4198 
4199         if (surfaceSizeChanged || surfaceReplaced || surfaceCreated ||
4200             windowAttributesChanged || mChildBoundingInsetsChanged) {
4201             // If the surface has been replaced, there's a chance the bounds layer is not parented
4202             // to the new layer. When updating bounds layer, also reparent to the main VRI
4203             // SurfaceControl to ensure it's correctly placed in the hierarchy.
4204             //
4205             // This needs to be done on the client side since WMS won't reparent the children to the
4206             // new surface if it thinks the app is closing. WMS gets the signal that the app is
4207             // stopping, but on the client side it doesn't get stopped since it's restarted quick
4208             // enough. WMS doesn't want to keep around old children since they will leak when the
4209             // client creates new children.
4210             prepareSurfaces();
4211             mChildBoundingInsetsChanged = false;
4212         }
4213 
4214         final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
4215         boolean triggerGlobalLayoutListener = didLayout
4216                 || mAttachInfo.mRecomputeGlobalAttributes;
4217         if (didLayout) {
4218             performLayout(lp, mWidth, mHeight);
4219 
4220             // By this point all views have been sized and positioned
4221             // We can compute the transparent area
4222 
4223             if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
4224                 // start out transparent
4225                 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
4226                 host.getLocationInWindow(mTmpLocation);
4227                 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
4228                         mTmpLocation[0] + host.mRight - host.mLeft,
4229                         mTmpLocation[1] + host.mBottom - host.mTop);
4230 
4231                 host.gatherTransparentRegion(mTransparentRegion);
4232                 final Rect bounds = mAttachInfo.mTmpInvalRect;
4233                 if (getAccessibilityFocusedRect(bounds)) {
4234                   host.applyDrawableToTransparentRegion(getAccessibilityFocusedDrawable(),
4235                       mTransparentRegion);
4236                 }
4237                 if (mTranslator != null) {
4238                     mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
4239                 }
4240 
4241                 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
4242                     mPreviousTransparentRegion.set(mTransparentRegion);
4243                     mFullRedrawNeeded = true;
4244                     // TODO: Ideally we would do this in prepareSurfaces,
4245                     // but prepareSurfaces is currently working under
4246                     // the assumption that we paused the render thread
4247                     // via the WM relayout code path. We probably eventually
4248                     // want to synchronize transparent region hint changes
4249                     // with draws.
4250                     SurfaceControl sc = getSurfaceControl();
4251                     if (sc.isValid()) {
4252                         mTransaction.setTransparentRegionHint(sc, mTransparentRegion).apply();
4253                     }
4254                 }
4255             }
4256 
4257             if (DBG) {
4258                 System.out.println("======================================");
4259                 System.out.println("performTraversals -- after setFrame");
4260                 host.debug();
4261             }
4262         }
4263 
4264         boolean didUseTransaction = false;
4265         // These callbacks will trigger SurfaceView SurfaceHolder.Callbacks and must be invoked
4266         // after the measure pass. If its invoked before the measure pass and the app modifies
4267         // the view hierarchy in the callbacks, we could leave the views in a broken state.
4268         if (surfaceCreated) {
4269             notifySurfaceCreated(mTransaction);
4270             didUseTransaction = true;
4271         } else if (surfaceReplaced) {
4272             notifySurfaceReplaced(mTransaction);
4273             didUseTransaction = true;
4274         } else if (surfaceDestroyed)  {
4275             notifySurfaceDestroyed();
4276         }
4277 
4278         if (didUseTransaction) {
4279             applyTransactionOnDraw(mTransaction);
4280         }
4281 
4282         if (triggerGlobalLayoutListener) {
4283             mAttachInfo.mRecomputeGlobalAttributes = false;
4284             mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
4285         }
4286 
4287         Rect contentInsets = null;
4288         Rect visibleInsets = null;
4289         Region touchableRegion = null;
4290         int touchableInsetMode = TOUCHABLE_INSETS_REGION;
4291         boolean computedInternalInsets = false;
4292         if (computesInternalInsets) {
4293             final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
4294 
4295             // Clear the original insets.
4296             insets.reset();
4297 
4298             // Compute new insets in place.
4299             mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
4300             mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
4301 
4302             // Tell the window manager.
4303             if (insetsPending || !mLastGivenInsets.equals(insets)) {
4304                 mLastGivenInsets.set(insets);
4305 
4306                 // Translate insets to screen coordinates if needed.
4307                 if (mTranslator != null) {
4308                     contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
4309                     visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
4310                     touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
4311                 } else {
4312                     contentInsets = insets.contentInsets;
4313                     visibleInsets = insets.visibleInsets;
4314                     touchableRegion = insets.touchableRegion;
4315                 }
4316                 computedInternalInsets = true;
4317             }
4318             touchableInsetMode = insets.mTouchableInsets;
4319         }
4320         boolean needsSetInsets = computedInternalInsets;
4321         needsSetInsets |= !Objects.equals(mPreviousTouchableRegion, mTouchableRegion) &&
4322             (mTouchableRegion != null);
4323         if (needsSetInsets) {
4324             if (mTouchableRegion != null) {
4325                 if (mPreviousTouchableRegion == null) {
4326                     mPreviousTouchableRegion = new Region();
4327                 }
4328                 mPreviousTouchableRegion.set(mTouchableRegion);
4329                 if (touchableInsetMode != TOUCHABLE_INSETS_REGION) {
4330                     Log.e(mTag, "Setting touchableInsetMode to non TOUCHABLE_INSETS_REGION" +
4331                           " from OnComputeInternalInsets, while also using setTouchableRegion" +
4332                           " causes setTouchableRegion to be ignored");
4333                 }
4334             } else {
4335                 mPreviousTouchableRegion = null;
4336             }
4337             if (contentInsets == null) contentInsets = new Rect(0,0,0,0);
4338             if (visibleInsets == null) visibleInsets = new Rect(0,0,0,0);
4339             if (touchableRegion == null) {
4340                 touchableRegion = mTouchableRegion;
4341             } else if (touchableRegion != null && mTouchableRegion != null) {
4342                 touchableRegion.op(touchableRegion, mTouchableRegion, Region.Op.UNION);
4343             }
4344             try {
4345                 mWindowSession.setInsets(mWindow, touchableInsetMode,
4346                                          contentInsets, visibleInsets, touchableRegion);
4347             } catch (RemoteException e) {
4348                 throw e.rethrowFromSystemServer();
4349             }
4350         } else if (mTouchableRegion == null && mPreviousTouchableRegion != null) {
4351             mPreviousTouchableRegion = null;
4352             try {
4353                 mWindowSession.clearTouchableRegion(mWindow);
4354             } catch (RemoteException e) {
4355                 throw e.rethrowFromSystemServer();
4356             }
4357         }
4358 
4359         if (mFirst) {
4360             if (sAlwaysAssignFocus || !isInTouchMode()) {
4361                 // handle first focus request
4362                 if (DEBUG_INPUT_RESIZE) {
4363                     Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus());
4364                 }
4365                 if (mView != null) {
4366                     if (!mView.hasFocus()) {
4367                         mView.restoreDefaultFocus();
4368                         if (DEBUG_INPUT_RESIZE) {
4369                             Log.v(mTag, "First: requested focused view=" + mView.findFocus());
4370                         }
4371                     } else {
4372                         if (DEBUG_INPUT_RESIZE) {
4373                             Log.v(mTag, "First: existing focused view=" + mView.findFocus());
4374                         }
4375                     }
4376                 }
4377             } else {
4378                 // Some views (like ScrollView) won't hand focus to descendants that aren't within
4379                 // their viewport. Before layout, there's a good change these views are size 0
4380                 // which means no children can get focus. After layout, this view now has size, but
4381                 // is not guaranteed to hand-off focus to a focusable child (specifically, the edge-
4382                 // case where the child has a size prior to layout and thus won't trigger
4383                 // focusableViewAvailable).
4384                 View focused = mView.findFocus();
4385                 if (focused instanceof ViewGroup
4386                         && ((ViewGroup) focused).getDescendantFocusability()
4387                                 == ViewGroup.FOCUS_AFTER_DESCENDANTS) {
4388                     focused.restoreDefaultFocus();
4389                 }
4390             }
4391 
4392             if (shouldEnableDvrr()) {
4393                 // Boost the frame rate when the ViewRootImpl first becomes available.
4394                 boostFrameRate(FRAME_RATE_BOOST_TIME);
4395             }
4396         }
4397 
4398         final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
4399         if (changedVisibility) {
4400             maybeFireAccessibilityWindowStateChangedEvent();
4401         }
4402 
4403         mFirst = false;
4404         mWillDrawSoon = false;
4405         mNewSurfaceNeeded = false;
4406         mViewVisibility = viewVisibility;
4407 
4408         final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
4409         mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
4410 
4411         if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
4412             reportNextDraw("first_relayout");
4413         }
4414 
4415         mCheckIfCanDraw = isSyncRequest || cancelDraw;
4416 
4417         boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
4418         boolean cancelAndRedraw = cancelDueToPreDrawListener
4419                  || (cancelDraw && mDrewOnceForSync);
4420 
4421         if (!cancelAndRedraw) {
4422             // A sync was already requested before the WMS requested sync. This means we need to
4423             // sync the buffer, regardless if WMS wants to sync the buffer.
4424             if (mActiveSurfaceSyncGroup != null) {
4425                 mSyncBuffer = true;
4426             }
4427 
4428             createSyncIfNeeded();
4429             notifyDrawStarted(isInWMSRequestedSync());
4430             mDrewOnceForSync = true;
4431 
4432             // If the active SSG is also requesting to sync a buffer, the following needs to happen
4433             // 1. Ensure we keep track of the number of active syncs to know when to disable RT
4434             //    RT animations that conflict with syncing a buffer.
4435             // 2. Add a safeguard SSG to prevent multiple SSG that sync buffers from being submitted
4436             //    out of order.
4437             if (mActiveSurfaceSyncGroup != null && mSyncBuffer) {
4438                 updateSyncInProgressCount(mActiveSurfaceSyncGroup);
4439                 safeguardOverlappingSyncs(mActiveSurfaceSyncGroup);
4440             }
4441         }
4442 
4443         if (!isViewVisible) {
4444             if (mLastTraversalWasVisible) {
4445                 logAndTrace("Not drawing due to not visible. Reason=" + viewVisibilityReason);
4446             }
4447             mLastPerformTraversalsSkipDrawReason = "view_not_visible";
4448             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
4449                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
4450                     mPendingTransitions.get(i).endChangingAnimations();
4451                 }
4452                 mPendingTransitions.clear();
4453             }
4454 
4455             handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
4456                     mPendingTransaction, "view not visible");
4457             mHasPendingTransactions = false;
4458         } else if (cancelAndRedraw) {
4459             if (!mWasLastDrawCanceled) {
4460                 logAndTrace("Canceling draw."
4461                         + " cancelDueToPreDrawListener=" + cancelDueToPreDrawListener
4462                         + " cancelDueToSync=" + (cancelDraw && mDrewOnceForSync));
4463             }
4464             mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
4465                 ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
4466                 : "cancel_" + cancelReason;
4467             // Try again
4468             scheduleTraversals();
4469         } else {
4470             if (mWasLastDrawCanceled) {
4471                 logAndTrace("Draw frame after cancel");
4472             }
4473             if (!mLastTraversalWasVisible) {
4474                 logAndTrace("Start draw after previous draw not visible");
4475             }
4476             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
4477                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
4478                     mPendingTransitions.get(i).startChangingAnimations();
4479                 }
4480                 mPendingTransitions.clear();
4481             }
4482             if (!performDraw(mActiveSurfaceSyncGroup)) {
4483                 handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
4484                         mPendingTransaction, mLastPerformDrawSkippedReason);
4485                 mHasPendingTransactions = false;
4486             }
4487         }
4488         mWasLastDrawCanceled = cancelAndRedraw;
4489         mLastTraversalWasVisible = isViewVisible;
4490 
4491         if (mAttachInfo.mContentCaptureEvents != null) {
4492             notifyContentCaptureEvents();
4493         }
4494 
4495         mIsInTraversal = false;
4496         mRelayoutRequested = false;
4497 
4498         if (!cancelAndRedraw) {
4499             mReportNextDraw = false;
4500             mLastReportNextDrawReason = null;
4501             mActiveSurfaceSyncGroup = null;
4502             if (mHasPendingTransactions) {
4503                 // TODO: We shouldn't ever actually hit this, it means mPendingTransaction wasn't
4504                 // merged with a sync group or BLASTBufferQueue before making it to this point
4505                 // But better a one or two frame flicker than steady-state broken from dropping
4506                 // whatever is in this transaction
4507                 // apply immediately with bbq apply token
4508                 mergeWithNextTransaction(mPendingTransaction, 0);
4509                 mHasPendingTransactions = false;
4510             }
4511             mSyncBuffer = false;
4512             if (isInWMSRequestedSync()) {
4513                 mWmsRequestSyncGroup.markSyncReady();
4514                 mWmsRequestSyncGroup = null;
4515                 mWmsRequestSyncGroupState = WMS_SYNC_NONE;
4516             }
4517         }
4518 
4519         // For the variable refresh rate project.
4520         // We set the preferred frame rate and frame rate category at the end of performTraversals
4521         // when the values are applicable.
4522         if (mDrawnThisFrame) {
4523             if (sToolkitInitialTouchBoostFlagValue && mIsTouchBoosting) {
4524                 mTouchAndDrawn = true;
4525             }
4526 
4527             mDrawnThisFrame = false;
4528             if (!mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) {
4529                 mInvalidationIdleMessagePosted = true;
4530                 mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS);
4531             }
4532             setCategoryFromCategoryCounts();
4533             updateInfrequentCount();
4534             updateFrameRateFromThreadedRendererViews();
4535             setPreferredFrameRate(mPreferredFrameRate);
4536             setPreferredFrameRateCategory(mPreferredFrameRateCategory);
4537             if (mPreferredFrameRate > 0
4538                     || (mLastPreferredFrameRate != 0 && mPreferredFrameRate == 0)
4539             ) {
4540                 mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
4541                 mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING,
4542                         FRAME_RATE_SETTING_REEVALUATE_TIME);
4543             }
4544             mFrameRateCategoryHighCount = mFrameRateCategoryHighCount > 0
4545                     ? mFrameRateCategoryHighCount - 1 : mFrameRateCategoryHighCount;
4546             mFrameRateCategoryHighHintCount = mFrameRateCategoryHighHintCount > 0
4547                     ? mFrameRateCategoryHighHintCount - 1 : mFrameRateCategoryHighHintCount;
4548             mFrameRateCategoryNormalCount = mFrameRateCategoryNormalCount > 0
4549                     ? mFrameRateCategoryNormalCount - 1 : mFrameRateCategoryNormalCount;
4550             mFrameRateCategoryLowCount = mFrameRateCategoryLowCount > 0
4551                     ? mFrameRateCategoryLowCount - 1 : mFrameRateCategoryLowCount;
4552             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT;
4553             mPreferredFrameRate = -1;
4554             mIsFrameRateConflicted = false;
4555             mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_UNKNOWN;
4556             mSurfaceReplaced = false;
4557         } else if (mPreferredFrameRate == 0) {
4558             // From MSG_FRAME_RATE_SETTING, where mPreferredFrameRate is set to 0
4559             setPreferredFrameRate(0);
4560             mPreferredFrameRate = -1;
4561         }
4562     }
4563 
createSyncIfNeeded()4564     private void createSyncIfNeeded() {
4565         // WMS requested sync already started or there's nothing needing to sync
4566         if (isInWMSRequestedSync() || !mReportNextDraw) {
4567             return;
4568         }
4569 
4570         final int seqId = mSyncSeqId;
4571         mWmsRequestSyncGroupState = WMS_SYNC_PENDING;
4572         mWmsRequestSyncGroup = new SurfaceSyncGroup("wmsSync-" + mTag, t -> {
4573             mWmsRequestSyncGroupState = WMS_SYNC_MERGED;
4574             // See b/286355097. If the current process is not system, then invoking finishDraw on
4575             // any thread is fine since once it calls into system process, finishDrawing will run
4576             // on a different thread. However, when the current process is system, the finishDraw in
4577             // system server will be run on the current thread, which could result in a deadlock.
4578             if (mWindowSession instanceof Binder) {
4579                 // The transaction should be copied to a local reference when posting onto a new
4580                 // thread because up until now the SSG is holding a lock on the transaction. Once
4581                 // the call jumps onto a new thread, the lock is no longer held and the transaction
4582                 // send back may be modified or used again.
4583                 Transaction transactionCopy = new Transaction();
4584                 transactionCopy.merge(t);
4585                 mHandler.postAtFrontOfQueue(() -> reportDrawFinished(transactionCopy, seqId));
4586             } else {
4587                 reportDrawFinished(t, seqId);
4588             }
4589         });
4590 
4591         // Only trigger once per {@link ViewRootImpl} instance, so don't add listener if
4592         // {link mTransactionCompletedTimeNs} has already been set.
4593         if (mAppStartInfoTimestampsFlagValue && !mAppStartTrackingStarted) {
4594             mAppStartTrackingStarted = true;
4595             Transaction transaction = new Transaction();
4596             transaction.addTransactionCompletedListener(mSimpleExecutor,
4597                     new Consumer<TransactionStats>() {
4598                         @Override
4599                         public void accept(TransactionStats transactionStats) {
4600                             SyncFence presentFence = transactionStats.getPresentFence();
4601                             if (presentFence.awaitForever()) {
4602                                 if (mFirstFramePresentedTimeNs == -1) {
4603                                     // Only trigger once per {@link ViewRootImpl} instance.
4604                                     mFirstFramePresentedTimeNs = presentFence.getSignalTime();
4605                                     maybeSendAppStartTimes();
4606                                 }
4607                             }
4608                             presentFence.close();
4609                         }
4610                     });
4611             applyTransactionOnDraw(transaction);
4612         }
4613 
4614         if (DEBUG_BLAST) {
4615             Log.d(mTag, "Setup new sync=" + mWmsRequestSyncGroup.getName());
4616         }
4617 
4618         mWmsRequestSyncGroup.add(this, null /* runnable */);
4619     }
4620 
maybeSendAppStartTimes()4621     private void maybeSendAppStartTimes() {
4622         if (mAppStartTimestampsSent.get()) {
4623             // Don't send timestamps more than once.
4624             return;
4625         }
4626 
4627         // Post to main thread
4628         mHandler.post(new Runnable() {
4629             @Override
4630             public void run() {
4631                 if (mRenderThreadDrawStartTimeNs == -1) {
4632                     return;
4633                 }
4634 
4635                 try {
4636                     ActivityManager.getService().reportStartInfoViewTimestamps(
4637                             mRenderThreadDrawStartTimeNs, mFirstFramePresentedTimeNs);
4638                     mAppStartTimestampsSent.set(true);
4639                 } catch (RemoteException e) {
4640                     // Ignore, timestamps may be lost.
4641                     if (DBG) Log.d(TAG, "Exception attempting to report start timestamps.", e);
4642                 }
4643             }
4644         });
4645     }
4646 
4647     /**
4648      * Helper used to notify the service to block projection when a sensitive
4649      * view (the view displays sensitive content) is attached to the window.
4650      * The window manager service is also notified to unblock projection when
4651      * no attached view (to the window) displays sensitive content.
4652      *
4653      * <ol>
4654      *   <li>It should only notify service to block projection when first sensitive view is
4655      *   attached to the window.
4656      *   <li>It should only notify service to unblock projection when all sensitive view are
4657      *   removed from the window.
4658      * </ol>
4659      *
4660      * @param enableProtection if true, the protection is enabled for this window.
4661      *                         if false, the protection is removed for this window.
4662      */
applySensitiveContentAppProtection(boolean enableProtection)4663     private void applySensitiveContentAppProtection(boolean enableProtection) {
4664         try {
4665             if (mSensitiveContentProtectionService == null) {
4666                 return;
4667             }
4668             if (DEBUG_SENSITIVE_CONTENT) {
4669                 Log.d(TAG, "Notify sensitive content, package=" + mContext.getPackageName()
4670                         + ", token=" + getWindowToken() + ", flag=" + enableProtection);
4671             }
4672             // The window would be blocked during screen share if it shows sensitive content.
4673             mSensitiveContentProtectionService.setSensitiveContentProtection(
4674                     getWindowToken(), mContext.getPackageName(), enableProtection);
4675         } catch (RemoteException ex) {
4676             Log.e(TAG, "Unable to protect sensitive content during screen share", ex);
4677         }
4678     }
4679 
4680     /**
4681      * Add sensitive content protection, when there are one or more visible sensitive views.
4682      */
addSensitiveContentAppProtection()4683     void addSensitiveContentAppProtection() {
4684         applySensitiveContentAppProtection(true);
4685     }
4686 
4687     /**
4688      * Remove sensitive content protection, when there is no visible sensitive view.
4689      */
removeSensitiveContentAppProtection()4690     void removeSensitiveContentAppProtection() {
4691         if (!sensitiveContentPrematureProtectionRemovedFix()) {
4692             applySensitiveContentAppProtection(false);
4693             return;
4694         }
4695         if (DEBUG_SENSITIVE_CONTENT) {
4696             Log.d(TAG, "Add transaction to remove sensitive content protection, package="
4697                     + mContext.getPackageName() + ", token=" + getWindowToken());
4698         }
4699         Transaction t = new Transaction();
4700         t.addTransactionCommittedListener(mExecutor, () -> {
4701             if (mAttachInfo.mSensitiveViewsCount == 0) {
4702                 applySensitiveContentAppProtection(false);
4703             }
4704         });
4705         applyTransactionOnDraw(t);
4706     }
4707 
notifyContentCaptureEvents()4708     private void notifyContentCaptureEvents() {
4709         if (!isContentCaptureEnabled()) {
4710             if (DEBUG_CONTENT_CAPTURE) {
4711                 Log.d(mTag, "notifyContentCaptureEvents while disabled");
4712             }
4713             mAttachInfo.mContentCaptureEvents = null;
4714             return;
4715         }
4716 
4717         final ContentCaptureManager manager = mAttachInfo.mContentCaptureManager;
4718         if (manager != null && mAttachInfo.mContentCaptureEvents != null) {
4719             final ContentCaptureSession session = manager.getMainContentCaptureSession();
4720             session.notifyContentCaptureEvents(mAttachInfo.mContentCaptureEvents);
4721         }
4722         mAttachInfo.mContentCaptureEvents = null;
4723     }
4724 
notifyHolderSurfaceDestroyed()4725     private void notifyHolderSurfaceDestroyed() {
4726         mSurfaceHolder.ungetCallbacks();
4727         SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
4728         if (callbacks != null) {
4729             for (SurfaceHolder.Callback c : callbacks) {
4730                 c.surfaceDestroyed(mSurfaceHolder);
4731             }
4732         }
4733     }
4734 
maybeHandleWindowMove(Rect frame)4735     private void maybeHandleWindowMove(Rect frame) {
4736         // TODO: Well, we are checking whether the frame has changed similarly
4737         // to how this is done for the insets. This is however incorrect since
4738         // the insets and the frame are translated. For example, the old frame
4739         // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
4740         // reported frame is (2, 2 - 2, 2) which implies no change but this is not
4741         // true since we are comparing a not translated value to a translated one.
4742         // This scenario is rare but we may want to fix that.
4743 
4744         final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left
4745                 || mAttachInfo.mWindowTop != frame.top;
4746         if (windowMoved) {
4747             mAttachInfo.mWindowLeft = frame.left;
4748             mAttachInfo.mWindowTop = frame.top;
4749         }
4750         if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) {
4751             // Update the light position for the new offsets.
4752             if (mAttachInfo.mThreadedRenderer != null) {
4753                 mAttachInfo.mThreadedRenderer.setLightCenter(mAttachInfo);
4754             }
4755             mAttachInfo.mNeedsUpdateLightCenter = false;
4756         }
4757     }
4758 
handleWindowFocusChanged()4759     private void handleWindowFocusChanged() {
4760         final boolean hasWindowFocus;
4761         synchronized (this) {
4762             if (!mWindowFocusChanged) {
4763                 return;
4764             }
4765             mWindowFocusChanged = false;
4766             hasWindowFocus = mUpcomingWindowFocus;
4767         }
4768         if (hasWindowFocus) {
4769             mInsetsController.onWindowFocusGained(
4770                     getFocusedViewOrNull() != null /* hasViewFocused */);
4771         } else {
4772             mInsetsController.onWindowFocusLost();
4773         }
4774 
4775         if (mAdded) {
4776             dispatchFocusEvent(hasWindowFocus, false /* fakeFocus */);
4777             // Note: must be done after the focus change callbacks,
4778             // so all of the view state is set up correctly.
4779             mImeFocusController.onPostWindowFocus(
4780                     getFocusedViewOrNull(), hasWindowFocus, mWindowAttributes);
4781 
4782             if (hasWindowFocus) {
4783                 // Clear the forward bit.  We can just do this directly, since
4784                 // the window manager doesn't care about it.
4785                 mWindowAttributes.softInputMode &=
4786                         ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
4787                 ((WindowManager.LayoutParams) mView.getLayoutParams())
4788                         .softInputMode &=
4789                         ~WindowManager.LayoutParams
4790                                 .SOFT_INPUT_IS_FORWARD_NAVIGATION;
4791 
4792                 maybeFireAccessibilityWindowStateChangedEvent();
4793 
4794                 // Refocusing a window that has a focused view should fire a
4795                 // focus event for the view since the global focused view changed.
4796                 fireAccessibilityFocusEventIfHasFocusedNode();
4797             } else {
4798                 if (mPointerCapture) {
4799                     handlePointerCaptureChanged(false);
4800                 }
4801             }
4802         }
4803         mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
4804 
4805         // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus
4806         // is lost, so we don't need to to force a flush - there might be other events such as
4807         // text changes, but these should be flushed independently.
4808         if (hasWindowFocus) {
4809             handleContentCaptureFlush();
4810         }
4811     }
4812 
4813     /**
4814      * Send a fake focus event for unfocused apps in split screen as some game engines wait to
4815      * get focus before drawing the content of the app. This will be used so that apps do not get
4816      * blacked out when they are resumed and do not have focus yet.
4817      *
4818      * {@hide}
4819      */
4820     // TODO(b/263094829): Investigate dispatching this for onPause as well
dispatchCompatFakeFocus()4821     public void dispatchCompatFakeFocus() {
4822         boolean aboutToHaveFocus = false;
4823         synchronized (this) {
4824             aboutToHaveFocus = mWindowFocusChanged && mUpcomingWindowFocus;
4825         }
4826         final boolean alreadyHaveFocus = mAttachInfo.mHasWindowFocus;
4827         if (aboutToHaveFocus || alreadyHaveFocus) {
4828             // Do not need to toggle focus if app doesn't need it, or has focus.
4829             return;
4830         }
4831         EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
4832                 "Giving fake focus to " + mBasePackageName, "reason=unity bug workaround");
4833         dispatchFocusEvent(true /* hasWindowFocus */, true /* fakeFocus */);
4834         EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
4835                 "Removing fake focus from " + mBasePackageName, "reason=timeout callback");
4836         dispatchFocusEvent(false /* hasWindowFocus */, true /* fakeFocus */);
4837     }
4838 
dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus)4839     private void dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus) {
4840         profileRendering(hasWindowFocus);
4841         if (hasWindowFocus && mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
4842             mFullRedrawNeeded = true;
4843             try {
4844                 final Rect surfaceInsets = mWindowAttributes.surfaceInsets;
4845                 mAttachInfo.mThreadedRenderer.initializeIfNeeded(
4846                         mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
4847             } catch (OutOfResourcesException e) {
4848                 Log.e(mTag, "OutOfResourcesException locking surface", e);
4849                 try {
4850                     if (!mWindowSession.outOfMemory(mWindow)) {
4851                         Slog.w(mTag, "No processes killed for memory;"
4852                                 + " killing self");
4853                         Process.killProcess(Process.myPid());
4854                     }
4855                 } catch (RemoteException ex) {
4856                 }
4857                 // Retry in a bit.
4858                 mHandler.sendMessageDelayed(mHandler.obtainMessage(
4859                         MSG_WINDOW_FOCUS_CHANGED), 500);
4860                 return;
4861             }
4862         }
4863 
4864         mAttachInfo.mHasWindowFocus = hasWindowFocus;
4865 
4866         if (!fakeFocus) {
4867             mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes);
4868         }
4869 
4870         if (mView != null) {
4871             mAttachInfo.mKeyDispatchState.reset();
4872             mView.dispatchWindowFocusChanged(hasWindowFocus);
4873             mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
4874             if (mAttachInfo.mTooltipHost != null) {
4875                 mAttachInfo.mTooltipHost.hideTooltip();
4876             }
4877         }
4878     }
4879 
handleWindowTouchModeChanged()4880     private void handleWindowTouchModeChanged() {
4881         final boolean inTouchMode;
4882         synchronized (this) {
4883             inTouchMode = mUpcomingInTouchMode;
4884         }
4885         ensureTouchModeLocally(inTouchMode);
4886     }
4887 
maybeFireAccessibilityWindowStateChangedEvent()4888     private void maybeFireAccessibilityWindowStateChangedEvent() {
4889         // Toasts are presented as notifications - don't present them as windows as well.
4890         boolean isToast = mWindowAttributes != null && (mWindowAttributes.type == TYPE_TOAST);
4891         if (!isToast && mView != null) {
4892             mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
4893         }
4894     }
4895 
fireAccessibilityFocusEventIfHasFocusedNode()4896     private void fireAccessibilityFocusEventIfHasFocusedNode() {
4897         if (!mAccessibilityManager.isEnabled()) {
4898             return;
4899         }
4900         final View focusedView = mView.findFocus();
4901         if (focusedView == null) {
4902             return;
4903         }
4904         final AccessibilityNodeProvider provider = focusedView.getAccessibilityNodeProvider();
4905         if (provider == null) {
4906             focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
4907         } else {
4908             final AccessibilityNodeInfo focusedNode = findFocusedVirtualNode(provider);
4909             if (focusedNode != null) {
4910                 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
4911                         focusedNode.getSourceNodeId());
4912                 // This is a best effort since clearing and setting the focus via the
4913                 // provider APIs could have side effects. We don't have a provider API
4914                 // similar to that on View to ask a given event to be fired.
4915                 final AccessibilityEvent event = AccessibilityEvent.obtain(
4916                         AccessibilityEvent.TYPE_VIEW_FOCUSED);
4917                 event.setSource(focusedView, virtualId);
4918                 event.setPackageName(focusedNode.getPackageName());
4919                 event.setChecked(focusedNode.isChecked());
4920                 event.setContentDescription(focusedNode.getContentDescription());
4921                 event.setPassword(focusedNode.isPassword());
4922                 event.getText().add(focusedNode.getText());
4923                 event.setEnabled(focusedNode.isEnabled());
4924                 focusedView.getParent().requestSendAccessibilityEvent(focusedView, event);
4925                 focusedNode.recycle();
4926             }
4927         }
4928     }
4929 
findFocusedVirtualNode(AccessibilityNodeProvider provider)4930     private AccessibilityNodeInfo findFocusedVirtualNode(AccessibilityNodeProvider provider) {
4931         AccessibilityNodeInfo focusedNode = provider.findFocus(
4932                 AccessibilityNodeInfo.FOCUS_INPUT);
4933         if (focusedNode != null) {
4934             return focusedNode;
4935         }
4936 
4937         if (!mContext.isAutofillCompatibilityEnabled()) {
4938             return null;
4939         }
4940 
4941         // Unfortunately some provider implementations don't properly
4942         // implement AccessibilityNodeProvider#findFocus
4943         AccessibilityNodeInfo current = provider.createAccessibilityNodeInfo(
4944                 AccessibilityNodeProvider.HOST_VIEW_ID);
4945         if (current == null) {
4946             return null;
4947         }
4948         if (current.isFocused()) {
4949             return current;
4950         }
4951 
4952         final Queue<AccessibilityNodeInfo> fringe = new ArrayDeque<>();
4953         fringe.offer(current);
4954 
4955         while (!fringe.isEmpty()) {
4956             current = fringe.poll();
4957             final LongArray childNodeIds = current.getChildNodeIds();
4958             if (childNodeIds== null || childNodeIds.size() <= 0) {
4959                 continue;
4960             }
4961             final int childCount = childNodeIds.size();
4962             for (int i = 0; i < childCount; i++) {
4963                 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
4964                         childNodeIds.get(i));
4965                 final AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(virtualId);
4966                 if (child != null) {
4967                     if (child.isFocused()) {
4968                         return child;
4969                     }
4970                     fringe.offer(child);
4971                 }
4972             }
4973             current.recycle();
4974         }
4975 
4976         return null;
4977     }
4978 
handleOutOfResourcesException(Surface.OutOfResourcesException e)4979     private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
4980         Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
4981         try {
4982             if (!mWindowSession.outOfMemory(mWindow) &&
4983                     Process.myUid() != Process.SYSTEM_UID) {
4984                 Slog.w(mTag, "No processes killed for memory; killing self");
4985                 Process.killProcess(Process.myPid());
4986             }
4987         } catch (RemoteException ex) {
4988         }
4989         mLayoutRequested = true;    // ask wm for a new surface next time.
4990     }
4991 
performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec)4992     private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
4993         if (mView == null) {
4994             return;
4995         }
4996         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
4997         try {
4998             mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4999         } finally {
5000             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
5001         }
5002         mMeasuredWidth = mView.getMeasuredWidth();
5003         mMeasuredHeight = mView.getMeasuredHeight();
5004         mViewMeasureDeferred = false;
5005     }
5006 
5007     /**
5008      * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
5009      * is currently undergoing a layout pass.
5010      *
5011      * @return whether the view hierarchy is currently undergoing a layout pass
5012      */
isInLayout()5013     boolean isInLayout() {
5014         return mInLayout;
5015     }
5016 
5017     /**
5018      * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
5019      * undergoing a layout pass. requestLayout() should not generally be called during layout,
5020      * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
5021      * all children in that container hierarchy are measured and laid out at the end of the layout
5022      * pass for that container). If requestLayout() is called anyway, we handle it correctly
5023      * by registering all requesters during a frame as it proceeds. At the end of the frame,
5024      * we check all of those views to see if any still have pending layout requests, which
5025      * indicates that they were not correctly handled by their container hierarchy. If that is
5026      * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
5027      * to blank containers, and force a second request/measure/layout pass in this frame. If
5028      * more requestLayout() calls are received during that second layout pass, we post those
5029      * requests to the next frame to avoid possible infinite loops.
5030      *
5031      * <p>The return value from this method indicates whether the request should proceed
5032      * (if it is a request during the first layout pass) or should be skipped and posted to the
5033      * next frame (if it is a request during the second layout pass).</p>
5034      *
5035      * @param view the view that requested the layout.
5036      *
5037      * @return true if request should proceed, false otherwise.
5038      */
requestLayoutDuringLayout(final View view)5039     boolean requestLayoutDuringLayout(final View view) {
5040         if (view.mParent == null || view.mAttachInfo == null) {
5041             // Would not normally trigger another layout, so just let it pass through as usual
5042             return true;
5043         }
5044         if (!mLayoutRequesters.contains(view)) {
5045             mLayoutRequesters.add(view);
5046         }
5047         if (!mHandlingLayoutInLayoutRequest) {
5048             // Let the request proceed normally; it will be processed in a second layout pass
5049             // if necessary
5050             return true;
5051         } else {
5052             // Don't let the request proceed during the second layout pass.
5053             // It will post to the next frame instead.
5054             return false;
5055         }
5056     }
5057 
performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight)5058     private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
5059             int desiredWindowHeight) {
5060         mScrollMayChange = true;
5061         mInLayout = true;
5062 
5063         final View host = mView;
5064         if (host == null) {
5065             return;
5066         }
5067         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
5068             Log.v(mTag, "Laying out " + host + " to (" +
5069                     host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
5070         }
5071 
5072         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
5073         try {
5074             host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
5075 
5076             mInLayout = false;
5077             int numViewsRequestingLayout = mLayoutRequesters.size();
5078             if (numViewsRequestingLayout > 0) {
5079                 // requestLayout() was called during layout.
5080                 // If no layout-request flags are set on the requesting views, there is no problem.
5081                 // If some requests are still pending, then we need to clear those flags and do
5082                 // a full request/measure/layout pass to handle this situation.
5083                 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
5084                         false);
5085                 if (validLayoutRequesters != null) {
5086                     // Set this flag to indicate that any further requests are happening during
5087                     // the second pass, which may result in posting those requests to the next
5088                     // frame instead
5089                     mHandlingLayoutInLayoutRequest = true;
5090 
5091                     // Process fresh layout requests, then measure and layout
5092                     int numValidRequests = validLayoutRequesters.size();
5093                     for (int i = 0; i < numValidRequests; ++i) {
5094                         final View view = validLayoutRequesters.get(i);
5095                         Log.w("View", "requestLayout() improperly called by " + view +
5096                                 " during layout: running second layout pass");
5097                         view.requestLayout();
5098                     }
5099                     measureHierarchy(host, lp, mView.getContext().getResources(),
5100                             desiredWindowWidth, desiredWindowHeight, false /* forRootSizeOnly */);
5101                     mInLayout = true;
5102                     host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
5103 
5104                     mHandlingLayoutInLayoutRequest = false;
5105 
5106                     // Check the valid requests again, this time without checking/clearing the
5107                     // layout flags, since requests happening during the second pass get noop'd
5108                     validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
5109                     if (validLayoutRequesters != null) {
5110                         final ArrayList<View> finalRequesters = validLayoutRequesters;
5111                         // Post second-pass requests to the next frame
5112                         getRunQueue().post(new Runnable() {
5113                             @Override
5114                             public void run() {
5115                                 int numValidRequests = finalRequesters.size();
5116                                 for (int i = 0; i < numValidRequests; ++i) {
5117                                     final View view = finalRequesters.get(i);
5118                                     Log.w("View", "requestLayout() improperly called by " + view +
5119                                             " during second layout pass: posting in next frame");
5120                                     view.requestLayout();
5121                                 }
5122                             }
5123                         });
5124                     }
5125                 }
5126 
5127             }
5128         } finally {
5129             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
5130         }
5131         mInLayout = false;
5132     }
5133 
5134     /**
5135      * This method is called during layout when there have been calls to requestLayout() during
5136      * layout. It walks through the list of views that requested layout to determine which ones
5137      * still need it, based on visibility in the hierarchy and whether they have already been
5138      * handled (as is usually the case with ListView children).
5139      *
5140      * @param layoutRequesters The list of views that requested layout during layout
5141      * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
5142      * If so, the FORCE_LAYOUT flag was not set on requesters.
5143      * @return A list of the actual views that still need to be laid out.
5144      */
getValidLayoutRequesters(ArrayList<View> layoutRequesters, boolean secondLayoutRequests)5145     private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
5146             boolean secondLayoutRequests) {
5147 
5148         int numViewsRequestingLayout = layoutRequesters.size();
5149         ArrayList<View> validLayoutRequesters = null;
5150         for (int i = 0; i < numViewsRequestingLayout; ++i) {
5151             View view = layoutRequesters.get(i);
5152             if (view != null && view.mAttachInfo != null && view.mParent != null &&
5153                     (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
5154                             View.PFLAG_FORCE_LAYOUT)) {
5155                 boolean gone = false;
5156                 View parent = view;
5157                 // Only trigger new requests for views in a non-GONE hierarchy
5158                 while (parent != null) {
5159                     if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
5160                         gone = true;
5161                         break;
5162                     }
5163                     if (parent.mParent instanceof View) {
5164                         parent = (View) parent.mParent;
5165                     } else {
5166                         parent = null;
5167                     }
5168                 }
5169                 if (!gone) {
5170                     if (validLayoutRequesters == null) {
5171                         validLayoutRequesters = new ArrayList<View>();
5172                     }
5173                     validLayoutRequesters.add(view);
5174                 }
5175             }
5176         }
5177         if (!secondLayoutRequests) {
5178             // If we're checking the layout flags, then we need to clean them up also
5179             for (int i = 0; i < numViewsRequestingLayout; ++i) {
5180                 View view = layoutRequesters.get(i);
5181                 while (view != null &&
5182                         (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
5183                     view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
5184                     if (view.mParent instanceof View) {
5185                         view = (View) view.mParent;
5186                     } else {
5187                         view = null;
5188                     }
5189                 }
5190             }
5191         }
5192         layoutRequesters.clear();
5193         return validLayoutRequesters;
5194     }
5195 
5196     @Override
requestTransparentRegion(View child)5197     public void requestTransparentRegion(View child) {
5198         // the test below should not fail unless someone is messing with us
5199         checkThread();
5200         if (mView != child) {
5201             return;
5202         }
5203 
5204         if ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
5205             mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
5206             // Need to make sure we re-evaluate the window attributes next
5207             // time around, to ensure the window has the correct format.
5208             mWindowAttributesChanged = true;
5209         }
5210 
5211         // Always request layout to apply the latest transparent region.
5212         requestLayout();
5213     }
5214 
5215     /**
5216      * Figures out the measure spec for the root view in a window based on it's
5217      * layout params.
5218      *
5219      * @param windowSize The available width or height of the window.
5220      * @param measurement The layout width or height requested in the layout params.
5221      * @param privateFlags The private flags in the layout params of the window.
5222      * @return The measure spec to use to measure the root view.
5223      */
getRootMeasureSpec(int windowSize, int measurement, int privateFlags)5224     private static int getRootMeasureSpec(int windowSize, int measurement, int privateFlags) {
5225         int measureSpec;
5226         final int rootDimension = (privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0
5227                 ? MATCH_PARENT : measurement;
5228         switch (rootDimension) {
5229             case ViewGroup.LayoutParams.MATCH_PARENT:
5230                 // Window can't resize. Force root view to be windowSize.
5231                 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
5232                 break;
5233             case ViewGroup.LayoutParams.WRAP_CONTENT:
5234                 // Window can resize. Set max size for root view.
5235                 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
5236                 break;
5237             default:
5238                 // Window wants to be an exact size. Force root view to be that size.
5239                 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
5240                 break;
5241         }
5242         return measureSpec;
5243     }
5244 
5245     int mHardwareXOffset;
5246     int mHardwareYOffset;
5247 
5248     @Override
onPreDraw(RecordingCanvas canvas)5249     public void onPreDraw(RecordingCanvas canvas) {
5250         // If mCurScrollY is not 0 then this influences the hardwareYOffset. The end result is we
5251         // can apply offsets that are not handled by anything else, resulting in underdraw as
5252         // the View is shifted (thus shifting the window background) exposing unpainted
5253         // content. To handle this with minimal glitches we just clear to BLACK if the window
5254         // is opaque. If it's not opaque then HWUI already internally does a glClear to
5255         // transparent, so there's no risk of underdraw on non-opaque surfaces.
5256         if (mCurScrollY != 0 && mHardwareYOffset != 0 && mAttachInfo.mThreadedRenderer.isOpaque()) {
5257             canvas.drawColor(Color.BLACK);
5258         }
5259         canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
5260     }
5261 
5262     @Override
onPostDraw(RecordingCanvas canvas)5263     public void onPostDraw(RecordingCanvas canvas) {
5264         drawAccessibilityFocusedDrawableIfNeeded(canvas);
5265         if (mUseMTRenderer) {
5266             for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
5267                 mWindowCallbacks.get(i).onPostDraw(canvas);
5268             }
5269         }
5270     }
5271 
5272     /**
5273      * @hide
5274      */
outputDisplayList(View view)5275     void outputDisplayList(View view) {
5276         view.mRenderNode.output();
5277     }
5278 
5279     /**
5280      * @see #PROPERTY_PROFILE_RENDERING
5281      */
profileRendering(boolean enabled)5282     private void profileRendering(boolean enabled) {
5283         if (mProfileRendering) {
5284             mRenderProfilingEnabled = enabled;
5285 
5286             if (mRenderProfiler != null) {
5287                 mChoreographer.removeFrameCallback(mRenderProfiler);
5288             }
5289             if (mRenderProfilingEnabled) {
5290                 if (mRenderProfiler == null) {
5291                     mRenderProfiler = new Choreographer.FrameCallback() {
5292                         @Override
5293                         public void doFrame(long frameTimeNanos) {
5294                             mDirty.set(0, 0, mWidth, mHeight);
5295                             scheduleTraversals();
5296                             if (mRenderProfilingEnabled) {
5297                                 mChoreographer.postFrameCallback(mRenderProfiler);
5298                             }
5299                         }
5300                     };
5301                 }
5302                 mChoreographer.postFrameCallback(mRenderProfiler);
5303             } else {
5304                 mRenderProfiler = null;
5305             }
5306         }
5307     }
5308 
5309     /**
5310      * Called from draw() when DEBUG_FPS is enabled
5311      */
trackFPS()5312     private void trackFPS() {
5313         // Tracks frames per second drawn. First value in a series of draws may be bogus
5314         // because it down not account for the intervening idle time
5315         long nowTime = System.currentTimeMillis();
5316         if (mFpsStartTime < 0) {
5317             mFpsStartTime = mFpsPrevTime = nowTime;
5318             mFpsNumFrames = 0;
5319         } else {
5320             ++mFpsNumFrames;
5321             String thisHash = Integer.toHexString(System.identityHashCode(this));
5322             long frameTime = nowTime - mFpsPrevTime;
5323             long totalTime = nowTime - mFpsStartTime;
5324             Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
5325             mFpsPrevTime = nowTime;
5326             if (totalTime > 1000) {
5327                 float fps = (float) mFpsNumFrames * 1000 / totalTime;
5328                 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
5329                 mFpsStartTime = nowTime;
5330                 mFpsNumFrames = 0;
5331             }
5332         }
5333     }
5334 
5335     /**
5336      * Called from draw() to collect metrics for frame rate decision.
5337      */
collectFrameRateDecisionMetrics()5338     private void collectFrameRateDecisionMetrics() {
5339         if (!Trace.isEnabled()) {
5340             if (mPreviousFrameDrawnTime > 0) mPreviousFrameDrawnTime = -1;
5341             return;
5342         }
5343 
5344         if (mPreviousFrameDrawnTime < 0) {
5345             mPreviousFrameDrawnTime = mChoreographer.getExpectedPresentationTimeNanos();
5346             return;
5347         }
5348 
5349         long expectedDrawnTime = mChoreographer.getExpectedPresentationTimeNanos();
5350         long timeDiff = expectedDrawnTime - mPreviousFrameDrawnTime;
5351         if (timeDiff <= 0) {
5352             return;
5353         }
5354 
5355         long fps = NANOS_PER_SEC / timeDiff;
5356         Trace.setCounter(mFpsTraceName, fps);
5357         mPreviousFrameDrawnTime = expectedDrawnTime;
5358 
5359         long percentage = (long) (mLargestChildPercentage * 100);
5360         Trace.setCounter(mLargestViewTraceName, percentage);
5361         mLargestChildPercentage = 0.0f;
5362     }
5363 
reportDrawFinished(@ullable Transaction t, int seqId)5364     private void reportDrawFinished(@Nullable Transaction t, int seqId) {
5365         logAndTrace("reportDrawFinished seqId=" + seqId);
5366         try {
5367             mWindowSession.finishDrawing(mWindow, t, seqId);
5368         } catch (RemoteException e) {
5369             Log.e(mTag, "Unable to report draw finished", e);
5370             if (t != null) {
5371                 t.apply();
5372             }
5373         } finally {
5374             if (t != null) {
5375                 t.clear();
5376             }
5377         }
5378     }
5379 
5380     /**
5381      * @hide
5382      */
isHardwareEnabled()5383     public boolean isHardwareEnabled() {
5384         return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled();
5385     }
5386 
5387     /**
5388      * This VRI is currently in the middle of a sync request that was initiated by WMS.
5389      */
isInWMSRequestedSync()5390     public boolean isInWMSRequestedSync() {
5391         return mWmsRequestSyncGroup != null;
5392     }
5393 
addFrameCommitCallbackIfNeeded()5394     private void addFrameCommitCallbackIfNeeded() {
5395         if (!isHardwareEnabled()) {
5396             return;
5397         }
5398 
5399         ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
5400                 .captureFrameCommitCallbacks();
5401         final boolean needFrameCommitCallback =
5402                 (commitCallbacks != null && commitCallbacks.size() > 0);
5403         if (!needFrameCommitCallback) {
5404             return;
5405         }
5406 
5407         if (DEBUG_DRAW) {
5408             Log.d(mTag, "Creating frameCommitCallback"
5409                     + " commitCallbacks size=" + commitCallbacks.size());
5410         }
5411         mAttachInfo.mThreadedRenderer.setFrameCommitCallback(didProduceBuffer -> {
5412             if (DEBUG_DRAW) {
5413                 Log.d(mTag, "Received frameCommitCallback didProduceBuffer=" + didProduceBuffer);
5414             }
5415 
5416             mHandler.postAtFrontOfQueue(() -> {
5417                 for (int i = 0; i < commitCallbacks.size(); i++) {
5418                     commitCallbacks.get(i).run();
5419                 }
5420             });
5421         });
5422     }
5423 
5424     /**
5425      * These callbacks check if the draw failed for any reason and apply
5426      * those transactions directly so they don't get stuck forever.
5427      */
registerCallbackForPendingTransactions()5428     private void registerCallbackForPendingTransactions() {
5429         Transaction t = new Transaction();
5430         t.merge(mPendingTransaction);
5431         mHasPendingTransactions = false;
5432 
5433         registerRtFrameCallback(new FrameDrawingCallback() {
5434             @Override
5435             public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
5436                 mergeWithNextTransaction(t, frame);
5437                 if ((syncResult
5438                         & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
5439                     mBlastBufferQueue.applyPendingTransactions(frame);
5440                     return null;
5441                 }
5442 
5443                 return didProduceBuffer -> {
5444                     if (!didProduceBuffer) {
5445                         logAndTrace("Transaction not synced due to no frame drawn");
5446                         mBlastBufferQueue.applyPendingTransactions(frame);
5447                     }
5448                 };
5449 
5450             }
5451 
5452             @Override
5453             public void onFrameDraw(long frame) {
5454             }
5455         });
5456     }
5457 
performDraw(@ullable SurfaceSyncGroup surfaceSyncGroup)5458     private boolean performDraw(@Nullable SurfaceSyncGroup surfaceSyncGroup) {
5459         mLastPerformDrawSkippedReason = null;
5460         if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
5461             mLastPerformDrawSkippedReason = "screen_off";
5462             if (!mLastDrawScreenOff) {
5463                 logAndTrace("Not drawing due to screen off");
5464             }
5465             mLastDrawScreenOff = true;
5466             return false;
5467         } else if (mView == null) {
5468             mLastPerformDrawSkippedReason = "no_root_view";
5469             return false;
5470         }
5471 
5472         if (mLastDrawScreenOff) {
5473             logAndTrace("Resumed drawing after screen turned on");
5474             mLastDrawScreenOff = false;
5475         }
5476 
5477         final boolean fullRedrawNeeded = mFullRedrawNeeded || surfaceSyncGroup != null;
5478         mFullRedrawNeeded = false;
5479 
5480         mIsDrawing = true;
5481         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw-" + mTag);
5482 
5483         addFrameCommitCallbackIfNeeded();
5484 
5485         boolean usingAsyncReport;
5486 
5487         try {
5488             usingAsyncReport = draw(fullRedrawNeeded, surfaceSyncGroup, mSyncBuffer);
5489             if (mAttachInfo.mThreadedRenderer != null && !usingAsyncReport) {
5490                 mAttachInfo.mThreadedRenderer.setFrameCallback(null);
5491             }
5492         } finally {
5493             mIsDrawing = false;
5494             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
5495         }
5496 
5497         // For whatever reason we didn't create a HardwareRenderer, end any
5498         // hardware animations that are now dangling
5499         if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
5500             final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
5501             for (int i = 0; i < count; i++) {
5502                 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
5503             }
5504             mAttachInfo.mPendingAnimatingRenderNodes.clear();
5505         }
5506 
5507         final Transaction pendingTransaction;
5508         if (!usingAsyncReport && mHasPendingTransactions) {
5509             pendingTransaction = new Transaction();
5510             pendingTransaction.merge(mPendingTransaction);
5511             mHasPendingTransactions = false;
5512         } else {
5513             pendingTransaction = null;
5514         }
5515 
5516         if (mReportNextDraw) {
5517             // if we're using multi-thread renderer, wait for the window frame draws
5518             if (mWindowDrawCountDown != null) {
5519                 try {
5520                     mWindowDrawCountDown.await();
5521                 } catch (InterruptedException e) {
5522                     Log.e(mTag, "Window redraw count down interrupted!");
5523                 }
5524                 mWindowDrawCountDown = null;
5525             }
5526 
5527             if (mAttachInfo.mThreadedRenderer != null) {
5528                 mAttachInfo.mThreadedRenderer.setStopped(mStopped);
5529             }
5530 
5531             if (LOCAL_LOGV) {
5532                 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
5533             }
5534 
5535             if (mSurfaceHolder != null && mSurface.isValid()) {
5536                 usingAsyncReport = true;
5537                 SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> {
5538                     handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null,
5539                             pendingTransaction, "SurfaceHolder");
5540                 });
5541 
5542                 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
5543 
5544                 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
5545             } else if (!usingAsyncReport) {
5546                 if (mAttachInfo.mThreadedRenderer != null) {
5547                     mAttachInfo.mThreadedRenderer.fence();
5548                 }
5549             }
5550         }
5551 
5552         if (!usingAsyncReport) {
5553             handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null,
5554                     pendingTransaction, "no async report");
5555         }
5556 
5557         if (mPerformContentCapture) {
5558             performContentCaptureInitialReport();
5559         }
5560         return true;
5561     }
5562 
handleSyncRequestWhenNoAsyncDraw(SurfaceSyncGroup surfaceSyncGroup, boolean hasPendingTransaction, @Nullable Transaction pendingTransaction, String logReason)5563     private void handleSyncRequestWhenNoAsyncDraw(SurfaceSyncGroup surfaceSyncGroup,
5564             boolean hasPendingTransaction, @Nullable Transaction pendingTransaction,
5565             String logReason) {
5566         if (surfaceSyncGroup != null) {
5567             if (hasPendingTransaction && pendingTransaction != null) {
5568                 surfaceSyncGroup.addTransaction(pendingTransaction);
5569             }
5570             surfaceSyncGroup.markSyncReady();
5571         } else if (hasPendingTransaction && pendingTransaction != null) {
5572             Trace.instant(Trace.TRACE_TAG_VIEW,
5573                     "Transaction not synced due to " + logReason + "-" + mTag);
5574             if (DEBUG_BLAST) {
5575                 Log.d(mTag, "Pending transaction will not be applied in sync with a draw due to "
5576                         + logReason);
5577             }
5578             // apply immediately with bbq apply token
5579             mergeWithNextTransaction(pendingTransaction, 0);
5580         }
5581     }
5582     /**
5583      * Checks (and caches) if content capture is enabled for this context.
5584      */
isContentCaptureEnabled()5585     private boolean isContentCaptureEnabled() {
5586         switch (mContentCaptureEnabled) {
5587             case CONTENT_CAPTURE_ENABLED_TRUE:
5588                 return true;
5589             case CONTENT_CAPTURE_ENABLED_FALSE:
5590                 return false;
5591             case CONTENT_CAPTURE_ENABLED_NOT_CHECKED:
5592                 final boolean reallyEnabled = isContentCaptureReallyEnabled();
5593                 mContentCaptureEnabled = reallyEnabled ? CONTENT_CAPTURE_ENABLED_TRUE
5594                         : CONTENT_CAPTURE_ENABLED_FALSE;
5595                 return reallyEnabled;
5596             default:
5597                 Log.w(TAG, "isContentCaptureEnabled(): invalid state " + mContentCaptureEnabled);
5598                 return false;
5599         }
5600 
5601     }
5602 
5603     /**
5604      * Checks (without caching) if content capture is enabled for this context.
5605      */
isContentCaptureReallyEnabled()5606     private boolean isContentCaptureReallyEnabled() {
5607         // First check if context supports it, so it saves a service lookup when it doesn't
5608         if (mContext.getContentCaptureOptions() == null) return false;
5609 
5610         final ContentCaptureManager ccm = mAttachInfo.getContentCaptureManager(mContext);
5611         // Then check if it's enabled in the contex itself.
5612         if (ccm == null || !ccm.isContentCaptureEnabled()) return false;
5613 
5614         return true;
5615     }
5616 
performContentCaptureInitialReport()5617     private void performContentCaptureInitialReport() {
5618         mPerformContentCapture = false; // One-time offer!
5619         final View rootView = mView;
5620         if (DEBUG_CONTENT_CAPTURE) {
5621             Log.v(mTag, "performContentCaptureInitialReport() on " + rootView);
5622         }
5623         boolean traceDispatchCapture = false;
5624         try {
5625             if (!isContentCaptureEnabled()) return;
5626 
5627             traceDispatchCapture = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
5628             if (traceDispatchCapture) {
5629                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for "
5630                         + getClass().getSimpleName());
5631             }
5632 
5633             // Initial dispatch of window bounds to content capture
5634             if (mAttachInfo.mContentCaptureManager != null) {
5635                 ContentCaptureSession session =
5636                         mAttachInfo.mContentCaptureManager.getMainContentCaptureSession();
5637                 session.notifyWindowBoundsChanged(session.getId(),
5638                         getConfiguration().windowConfiguration.getBounds());
5639             }
5640 
5641             // Content capture is a go!
5642             rootView.dispatchInitialProvideContentCaptureStructure();
5643         } finally {
5644             if (traceDispatchCapture) {
5645                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
5646             }
5647         }
5648     }
5649 
handleContentCaptureFlush()5650     private void handleContentCaptureFlush() {
5651         if (DEBUG_CONTENT_CAPTURE) {
5652             Log.v(mTag, "handleContentCaptureFlush()");
5653         }
5654         boolean traceFlushContentCapture = false;
5655         try {
5656             if (!isContentCaptureEnabled()) return;
5657 
5658             traceFlushContentCapture = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
5659             if (traceFlushContentCapture) {
5660                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for "
5661                         + getClass().getSimpleName());
5662             }
5663 
5664             final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager;
5665             if (ccm == null) {
5666                 Log.w(TAG, "No ContentCapture on AttachInfo");
5667                 return;
5668             }
5669             ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED);
5670         } finally {
5671             if (traceFlushContentCapture) {
5672                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
5673             }
5674         }
5675     }
5676 
draw(boolean fullRedrawNeeded, @Nullable SurfaceSyncGroup activeSyncGroup, boolean syncBuffer)5677     private boolean draw(boolean fullRedrawNeeded, @Nullable SurfaceSyncGroup activeSyncGroup,
5678             boolean syncBuffer) {
5679         Surface surface = mSurface;
5680         if (!surface.isValid()) {
5681             return false;
5682         }
5683 
5684         if (DEBUG_FPS) {
5685             trackFPS();
5686         }
5687 
5688         if (sToolkitMetricsForFrameRateDecisionFlagValue) {
5689             collectFrameRateDecisionMetrics();
5690         }
5691 
5692         if (!sFirstDrawComplete) {
5693             synchronized (sFirstDrawHandlers) {
5694                 sFirstDrawComplete = true;
5695                 final int count = sFirstDrawHandlers.size();
5696                 for (int i = 0; i< count; i++) {
5697                     mHandler.post(sFirstDrawHandlers.get(i));
5698                 }
5699             }
5700         }
5701 
5702         scrollToRectOrFocus(null, false);
5703 
5704         if (mAttachInfo.mViewScrollChanged) {
5705             mAttachInfo.mViewScrollChanged = false;
5706             mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
5707         }
5708 
5709         boolean animating = mScroller != null && mScroller.computeScrollOffset();
5710         final int curScrollY;
5711         if (animating) {
5712             curScrollY = mScroller.getCurrY();
5713         } else {
5714             curScrollY = mScrollY;
5715         }
5716         if (mCurScrollY != curScrollY) {
5717             mCurScrollY = curScrollY;
5718             fullRedrawNeeded = true;
5719             if (mView instanceof RootViewSurfaceTaker) {
5720                 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
5721             }
5722         }
5723 
5724         final float appScale = mAttachInfo.mApplicationScale;
5725         final boolean scalingRequired = mAttachInfo.mScalingRequired;
5726 
5727         final Rect dirty = mDirty;
5728         if (mSurfaceHolder != null) {
5729             // The app owns the surface, we won't draw.
5730             dirty.setEmpty();
5731             if (animating && mScroller != null) {
5732                 mScroller.abortAnimation();
5733             }
5734             return false;
5735         }
5736 
5737         if (fullRedrawNeeded) {
5738             dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
5739         }
5740 
5741         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
5742             Log.v(mTag, "Draw " + mView + "/"
5743                     + mWindowAttributes.getTitle()
5744                     + ": dirty={" + dirty.left + "," + dirty.top
5745                     + "," + dirty.right + "," + dirty.bottom + "} surface="
5746                     + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
5747                     appScale + ", width=" + mWidth + ", height=" + mHeight);
5748         }
5749 
5750         mAttachInfo.mTreeObserver.dispatchOnDraw();
5751 
5752         int xOffset = -mCanvasOffsetX;
5753         int yOffset = -mCanvasOffsetY + curScrollY;
5754         final WindowManager.LayoutParams params = mWindowAttributes;
5755         final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
5756         if (surfaceInsets != null) {
5757             xOffset -= surfaceInsets.left;
5758             yOffset -= surfaceInsets.top;
5759 
5760             // Offset dirty rect for surface insets.
5761             dirty.offset(surfaceInsets.left, surfaceInsets.top);
5762         }
5763 
5764         boolean accessibilityFocusDirty = isAccessibilityFocusDirty();
5765 
5766         // Force recalculation of transparent regions
5767         if (accessibilityFocusDirty) {
5768             final Rect bounds = mAttachInfo.mTmpInvalRect;
5769             if (getAccessibilityFocusedRect(bounds)) {
5770                 requestLayout();
5771             }
5772         }
5773 
5774         mAttachInfo.mDrawingTime =
5775                 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
5776 
5777         boolean useAsyncReport = false;
5778         if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
5779             if (isHardwareEnabled()) {
5780                 // If accessibility focus moved, always invalidate the root.
5781                 boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
5782                 mInvalidateRootRequested = false;
5783 
5784                 // Draw with hardware renderer.
5785                 mIsAnimating = false;
5786 
5787                 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
5788                     mHardwareYOffset = yOffset;
5789                     mHardwareXOffset = xOffset;
5790                     invalidateRoot = true;
5791                 }
5792 
5793                 if (invalidateRoot) {
5794                     mAttachInfo.mThreadedRenderer.invalidateRoot();
5795                 }
5796 
5797                 dirty.setEmpty();
5798 
5799                 // Stage the content drawn size now. It will be transferred to the renderer
5800                 // shortly before the draw commands get send to the renderer.
5801                 final boolean updated = updateContentDrawBounds();
5802 
5803                 if (mReportNextDraw) {
5804                     // report next draw overrides setStopped()
5805                     // This value is re-sync'd to the value of mStopped
5806                     // in the handling of mReportNextDraw post-draw.
5807                     mAttachInfo.mThreadedRenderer.setStopped(false);
5808                 }
5809 
5810                 if (updated) {
5811                     requestDrawWindow();
5812                 }
5813 
5814                 useAsyncReport = true;
5815 
5816                 if (mHdrRenderState.updateForFrame(mAttachInfo.mDrawingTime)) {
5817                     final float renderRatio = mHdrRenderState.getRenderHdrSdrRatio();
5818                     applyTransactionOnDraw(mTransaction.setExtendedRangeBrightness(
5819                             getSurfaceControl(), renderRatio,
5820                             mHdrRenderState.getDesiredHdrSdrRatio()));
5821                     mAttachInfo.mThreadedRenderer.setTargetHdrSdrRatio(renderRatio);
5822                 }
5823 
5824                 if (activeSyncGroup != null) {
5825                     registerCallbacksForSync(syncBuffer, activeSyncGroup);
5826                     if (syncBuffer) {
5827                         mAttachInfo.mThreadedRenderer.forceDrawNextFrame();
5828                     }
5829                 } else if (mHasPendingTransactions) {
5830                     // Register a callback if there's no sync involved but there were calls to
5831                     // applyTransactionOnDraw. If there is a sync involved, the sync callback will
5832                     // handle merging the pending transaction.
5833                     registerCallbackForPendingTransactions();
5834                 }
5835 
5836                 long timeNs = SystemClock.uptimeNanos();
5837                 mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
5838 
5839                 // Only trigger once per {@link ViewRootImpl} instance.
5840                 if (mAppStartInfoTimestampsFlagValue && mRenderThreadDrawStartTimeNs == -1) {
5841                     mRenderThreadDrawStartTimeNs = timeNs;
5842                 }
5843             } else {
5844                 // If we get here with a disabled & requested hardware renderer, something went
5845                 // wrong (an invalidate posted right before we destroyed the hardware surface
5846                 // for instance) so we should just bail out. Locking the surface with software
5847                 // rendering at this point would lock it forever and prevent hardware renderer
5848                 // from doing its job when it comes back.
5849                 // Before we request a new frame we must however attempt to reinitiliaze the
5850                 // hardware renderer if it's in requested state. This would happen after an
5851                 // eglTerminate() for instance.
5852                 if (mAttachInfo.mThreadedRenderer != null &&
5853                         !mAttachInfo.mThreadedRenderer.isEnabled() &&
5854                         mAttachInfo.mThreadedRenderer.isRequested() &&
5855                         mSurface.isValid()) {
5856 
5857                     try {
5858                         mAttachInfo.mThreadedRenderer.initializeIfNeeded(
5859                                 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
5860                     } catch (OutOfResourcesException e) {
5861                         handleOutOfResourcesException(e);
5862                         return false;
5863                     }
5864 
5865                     mFullRedrawNeeded = true;
5866                     scheduleTraversals();
5867                     return false;
5868                 }
5869 
5870                 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
5871                         scalingRequired, dirty, surfaceInsets)) {
5872                     return false;
5873                 }
5874             }
5875         }
5876 
5877         if (animating) {
5878             mFullRedrawNeeded = true;
5879             scheduleTraversals();
5880         }
5881         return useAsyncReport;
5882     }
5883 
5884     /**
5885      * @return true if drawing was successful, false if an error occurred
5886      */
drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets)5887     private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
5888             boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
5889 
5890         // Draw with software renderer.
5891         final Canvas canvas;
5892 
5893         try {
5894             canvas = mSurface.lockCanvas(dirty);
5895             canvas.setDensity(mDensity);
5896         } catch (Surface.OutOfResourcesException e) {
5897             handleOutOfResourcesException(e);
5898             return false;
5899         } catch (IllegalArgumentException e) {
5900             Log.e(mTag, "Could not lock surface", e);
5901             // Don't assume this is due to out of memory, it could be
5902             // something else, and if it is something else then we could
5903             // kill stuff (or ourself) for no reason.
5904             mLayoutRequested = true;    // ask wm for a new surface next time.
5905             return false;
5906         }
5907 
5908         try {
5909             if (DEBUG_ORIENTATION || DEBUG_DRAW) {
5910                 Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
5911                         + canvas.getWidth() + ", h=" + canvas.getHeight() + ", dirty: " + dirty
5912                         + ", xOff=" + xoff + ", yOff=" + yoff);
5913                 //canvas.drawARGB(255, 255, 0, 0);
5914             }
5915 
5916             // If this bitmap's format includes an alpha channel, we
5917             // need to clear it before drawing so that the child will
5918             // properly re-composite its drawing on a transparent
5919             // background. This automatically respects the clip/dirty region
5920             // or
5921             // If we are applying an offset, we need to clear the area
5922             // where the offset doesn't appear to avoid having garbage
5923             // left in the blank areas.
5924             if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
5925                 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
5926             }
5927 
5928             dirty.setEmpty();
5929             mIsAnimating = false;
5930             mView.mPrivateFlags |= View.PFLAG_DRAWN;
5931 
5932             if (DEBUG_DRAW) {
5933                 Context cxt = mView.getContext();
5934                 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
5935                         ", metrics=" + cxt.getResources().getDisplayMetrics() +
5936                         ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
5937             }
5938             canvas.translate(-xoff, -yoff);
5939             if (mTranslator != null) {
5940                 mTranslator.translateCanvas(canvas);
5941             }
5942             canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
5943 
5944             mView.draw(canvas);
5945 
5946             drawAccessibilityFocusedDrawableIfNeeded(canvas);
5947         } finally {
5948             try {
5949                 surface.unlockCanvasAndPost(canvas);
5950             } catch (IllegalArgumentException e) {
5951                 Log.e(mTag, "Could not unlock surface", e);
5952                 mLayoutRequested = true;    // ask wm for a new surface next time.
5953                 //noinspection ReturnInsideFinallyBlock
5954                 return false;
5955             }
5956 
5957             if (LOCAL_LOGV) {
5958                 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
5959             }
5960         }
5961         return true;
5962     }
5963 
5964     /**
5965      * We want to draw a highlight around the current accessibility focused.
5966      * Since adding a style for all possible view is not a viable option we
5967      * have this specialized drawing method.
5968      *
5969      * Note: We are doing this here to be able to draw the highlight for
5970      *       virtual views in addition to real ones.
5971      *
5972      * Note: A round accessibility focus border is drawn on rounded watch
5973      *
5974      * Note: Need to set bounds of accessibility focused drawable before drawing on rounded watch,
5975      * so that when accessibility focus moved, root will be invalidated at
5976      * {@link #draw(boolean, SurfaceSyncGroup, boolean)} and accessibility focus border will be
5977      * updated.
5978      *
5979      * @param canvas The canvas on which to draw.
5980      */
drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas)5981     private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
5982         final Rect bounds = mAttachInfo.mTmpInvalRect;
5983         if (getAccessibilityFocusedRect(bounds)) {
5984             boolean isRoundWatch = mContext.getResources().getConfiguration().isScreenRound()
5985                     && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
5986             final Drawable drawable = getAccessibilityFocusedDrawable();
5987             if (drawable != null) {
5988                 drawable.setBounds(bounds);
5989                 drawable.draw(canvas);
5990                 if (mDisplay != null && isRoundWatch) {
5991                     // Draw an extra round accessibility focus border on round watch
5992                     drawAccessibilityFocusedBorderOnRoundDisplay(canvas, bounds,
5993                             getRoundDisplayRadius(), getRoundDisplayAccessibilityHighlightPaint());
5994                 }
5995             }
5996         } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
5997             mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
5998         }
5999     }
6000 
getRoundDisplayRadius()6001     private int getRoundDisplayRadius() {
6002         Point displaySize = new Point();
6003         mDisplay.getRealSize(displaySize);
6004         return displaySize.x / 2;
6005     }
6006 
getRoundDisplayAccessibilityHighlightPaint()6007     private Paint getRoundDisplayAccessibilityHighlightPaint() {
6008         // Lazily create the round display accessibility highlight paint.
6009         if (mRoundDisplayAccessibilityHighlightPaint == null) {
6010             mRoundDisplayAccessibilityHighlightPaint = new Paint();
6011             mRoundDisplayAccessibilityHighlightPaint.setStyle(Paint.Style.STROKE);
6012             mRoundDisplayAccessibilityHighlightPaint.setAntiAlias(true);
6013         }
6014         mRoundDisplayAccessibilityHighlightPaint.setStrokeWidth(
6015                 mAccessibilityManager.getAccessibilityFocusStrokeWidth());
6016         mRoundDisplayAccessibilityHighlightPaint.setColor(
6017                 mAccessibilityManager.getAccessibilityFocusColor());
6018         return mRoundDisplayAccessibilityHighlightPaint;
6019     }
6020 
drawAccessibilityFocusedBorderOnRoundDisplay(Canvas canvas, Rect bounds, int roundDisplayRadius, Paint accessibilityFocusHighlightPaint)6021     private void drawAccessibilityFocusedBorderOnRoundDisplay(Canvas canvas, Rect bounds,
6022             int roundDisplayRadius, Paint accessibilityFocusHighlightPaint) {
6023         int saveCount = canvas.save();
6024         canvas.clipRect(bounds);
6025         canvas.drawCircle(/* cx= */ roundDisplayRadius,
6026                 /* cy= */ roundDisplayRadius,
6027                 /* radius= */ roundDisplayRadius
6028                         - mAccessibilityManager.getAccessibilityFocusStrokeWidth() / 2.0f,
6029                 accessibilityFocusHighlightPaint);
6030         canvas.restoreToCount(saveCount);
6031     }
6032 
getAccessibilityFocusedRect(Rect bounds)6033     private boolean getAccessibilityFocusedRect(Rect bounds) {
6034         if (mView == null) {
6035             Slog.w(TAG, "calling getAccessibilityFocusedRect() while the mView is null");
6036             return false;
6037         }
6038         if (!mAccessibilityManager.isEnabled()
6039                 || !mAccessibilityManager.isTouchExplorationEnabled()) {
6040             return false;
6041         }
6042 
6043         final View host = mAccessibilityFocusedHost;
6044         if (host == null || host.mAttachInfo == null) {
6045             return false;
6046         }
6047 
6048         final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
6049         if (provider == null) {
6050             host.getBoundsOnScreen(bounds, true);
6051         } else if (mAccessibilityFocusedVirtualView != null) {
6052             mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
6053         } else {
6054             return false;
6055         }
6056 
6057         // Transform the rect into window-relative coordinates.
6058         final AttachInfo attachInfo = mAttachInfo;
6059         bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
6060         bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
6061         if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
6062                 attachInfo.mViewRootImpl.mHeight)) {
6063             // If no intersection, set bounds to empty.
6064             bounds.setEmpty();
6065         }
6066 
6067         if (bounds.isEmpty()) {
6068             return false;
6069         }
6070 
6071         if (android.view.accessibility.Flags.focusRectMinSize()) {
6072             adjustAccessibilityFocusedRectBoundsIfNeeded(bounds);
6073         }
6074 
6075         return true;
6076     }
6077 
6078     /**
6079      * Adjusts accessibility focused rect bounds so that they are not invisible.
6080      *
6081      * <p>Focus bounds smaller than double the stroke width are very hard to see (or invisible).
6082      * Expand the focus bounds if necessary to at least double the stroke width.
6083      * @param bounds The bounds to adjust
6084      */
6085     @VisibleForTesting
adjustAccessibilityFocusedRectBoundsIfNeeded(Rect bounds)6086     public void adjustAccessibilityFocusedRectBoundsIfNeeded(Rect bounds) {
6087         final int minRectLength = mAccessibilityManager.getAccessibilityFocusStrokeWidth() * 2;
6088         if (bounds.width() < minRectLength || bounds.height() < minRectLength) {
6089             final float missingWidth = Math.max(0, minRectLength - bounds.width());
6090             final float missingHeight = Math.max(0, minRectLength - bounds.height());
6091             bounds.inset(-1 * (int) Math.ceil(missingWidth / 2),
6092                     -1 * (int) Math.ceil(missingHeight / 2));
6093         }
6094     }
6095 
getAccessibilityFocusedDrawable()6096     private Drawable getAccessibilityFocusedDrawable() {
6097         // Lazily load the accessibility focus drawable.
6098         if (mAttachInfo.mAccessibilityFocusDrawable == null) {
6099             final TypedValue value = new TypedValue();
6100             final boolean resolved = mView.mContext.getTheme().resolveAttribute(
6101                     R.attr.accessibilityFocusedDrawable, value, true);
6102             if (resolved) {
6103                 mAttachInfo.mAccessibilityFocusDrawable =
6104                         mView.mContext.getDrawable(value.resourceId);
6105             }
6106         }
6107         // Sets the focus appearance data into the accessibility focus drawable.
6108         if (mAttachInfo.mAccessibilityFocusDrawable instanceof GradientDrawable) {
6109             final GradientDrawable drawable =
6110                     (GradientDrawable) mAttachInfo.mAccessibilityFocusDrawable;
6111             drawable.setStroke(mAccessibilityManager.getAccessibilityFocusStrokeWidth(),
6112                     mAccessibilityManager.getAccessibilityFocusColor());
6113         }
6114 
6115         return mAttachInfo.mAccessibilityFocusDrawable;
6116     }
6117 
updateSystemGestureExclusionRectsForView(View view)6118     void updateSystemGestureExclusionRectsForView(View view) {
6119         boolean msgInQueue = reduceChangedExclusionRectsMsgs()
6120                 && mGestureExclusionTracker.isWaitingForComputeChanges();
6121         mGestureExclusionTracker.updateRectsForView(view);
6122         if (!msgInQueue) {
6123             mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
6124         }
6125     }
6126 
systemGestureExclusionChanged()6127     void systemGestureExclusionChanged() {
6128         final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects();
6129         if (rectsForWindowManager != null && mView != null) {
6130             try {
6131                 mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager);
6132             } catch (RemoteException e) {
6133                 throw e.rethrowFromSystemServer();
6134             }
6135             mAttachInfo.mTreeObserver
6136                     .dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager);
6137         }
6138     }
6139 
6140     /**
6141      * Called from DecorView when gesture interception state has changed.
6142      *
6143      * @param intercepted If DecorView is intercepting touch events
6144      */
updateDecorViewGestureInterception(boolean intercepted)6145     public void updateDecorViewGestureInterception(boolean intercepted) {
6146         mHandler.sendMessage(
6147                 mHandler.obtainMessage(
6148                         MSG_DECOR_VIEW_GESTURE_INTERCEPTION,
6149                         /* arg1= */ intercepted ? 1 : 0,
6150                         /* arg2= */ 0));
6151     }
6152 
decorViewInterceptionChanged(boolean intercepted)6153     void decorViewInterceptionChanged(boolean intercepted) {
6154         if (mView != null) {
6155             try {
6156                 mWindowSession.reportDecorViewGestureInterceptionChanged(mWindow, intercepted);
6157             } catch (RemoteException e) {
6158                 throw e.rethrowFromSystemServer();
6159             }
6160         }
6161     }
6162 
6163     /**
6164      * Set the root-level system gesture exclusion rects. These are added to those provided by
6165      * the root's view hierarchy.
6166      */
setRootSystemGestureExclusionRects(@onNull List<Rect> rects)6167     public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) {
6168         boolean msgInQueue = reduceChangedExclusionRectsMsgs()
6169                 && mGestureExclusionTracker.isWaitingForComputeChanges();
6170         mGestureExclusionTracker.setRootRects(rects);
6171         if (!msgInQueue) {
6172             mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
6173         }
6174     }
6175 
6176     /**
6177      * Returns the root-level system gesture exclusion rects. These do not include those provided by
6178      * the root's view hierarchy.
6179      */
6180     @NonNull
getRootSystemGestureExclusionRects()6181     public List<Rect> getRootSystemGestureExclusionRects() {
6182         return mGestureExclusionTracker.getRootRects();
6183     }
6184 
6185     /**
6186      * Called from View when the position listener is triggered
6187      */
updateKeepClearRectsForView(View view)6188     void updateKeepClearRectsForView(View view) {
6189         mKeepClearRectsTracker.updateRectsForView(view);
6190         mUnrestrictedKeepClearRectsTracker.updateRectsForView(view);
6191         mHandler.sendEmptyMessage(MSG_KEEP_CLEAR_RECTS_CHANGED);
6192     }
6193 
updateKeepClearForAccessibilityFocusRect()6194     private void updateKeepClearForAccessibilityFocusRect() {
6195         if (mViewConfiguration.isPreferKeepClearForFocusEnabled()) {
6196             if (mKeepClearAccessibilityFocusRect == null) {
6197                 mKeepClearAccessibilityFocusRect = new Rect();
6198             }
6199             boolean hasAccessibilityFocus =
6200                     getAccessibilityFocusedRect(mKeepClearAccessibilityFocusRect);
6201             if (!hasAccessibilityFocus) {
6202                 mKeepClearAccessibilityFocusRect.setEmpty();
6203             }
6204             mHandler.obtainMessage(MSG_KEEP_CLEAR_RECTS_CHANGED, 1, 0).sendToTarget();
6205         }
6206     }
6207 
keepClearRectsChanged(boolean accessibilityFocusRectChanged)6208     void keepClearRectsChanged(boolean accessibilityFocusRectChanged) {
6209         boolean restrictedKeepClearRectsChanged = mKeepClearRectsTracker.computeChanges();
6210         boolean unrestrictedKeepClearRectsChanged =
6211                 mUnrestrictedKeepClearRectsTracker.computeChanges();
6212 
6213         if ((restrictedKeepClearRectsChanged || unrestrictedKeepClearRectsChanged
6214                 || accessibilityFocusRectChanged) && mView != null) {
6215             mHasPendingKeepClearAreaChange = true;
6216             // Only report keep clear areas immediately if they have not been reported recently
6217             if (!mHandler.hasMessages(MSG_REPORT_KEEP_CLEAR_RECTS)) {
6218                 mHandler.sendEmptyMessageDelayed(MSG_REPORT_KEEP_CLEAR_RECTS,
6219                         KEEP_CLEAR_AREA_REPORT_RATE_MILLIS);
6220                 reportKeepClearAreasChanged();
6221             }
6222         }
6223     }
6224 
reportKeepClearAreasChanged()6225     void reportKeepClearAreasChanged() {
6226         if (!mHasPendingKeepClearAreaChange || mView == null) {
6227             return;
6228         }
6229         mHasPendingKeepClearAreaChange = false;
6230 
6231         List<Rect> restrictedKeepClearRects = mKeepClearRectsTracker.getLastComputedRects();
6232         final List<Rect> unrestrictedKeepClearRects =
6233                 mUnrestrictedKeepClearRectsTracker.getLastComputedRects();
6234 
6235         if (mKeepClearAccessibilityFocusRect != null
6236                 && !mKeepClearAccessibilityFocusRect.isEmpty()) {
6237             restrictedKeepClearRects = new ArrayList<>(restrictedKeepClearRects);
6238             restrictedKeepClearRects.add(mKeepClearAccessibilityFocusRect);
6239         }
6240 
6241         try {
6242             mWindowSession.reportKeepClearAreasChanged(mWindow, restrictedKeepClearRects,
6243                     unrestrictedKeepClearRects);
6244         } catch (RemoteException e) {
6245             throw e.rethrowFromSystemServer();
6246         }
6247     }
6248 
6249     /**
6250      * Requests that the root render node is invalidated next time we perform a draw, such that
6251      * {@link WindowCallbacks#onPostDraw} gets called.
6252      */
requestInvalidateRootRenderNode()6253     public void requestInvalidateRootRenderNode() {
6254         mInvalidateRootRequested = true;
6255     }
6256 
scrollToRectOrFocus(Rect rectangle, boolean immediate)6257     boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
6258         if (mImeBackAnimationController.isAnimationInProgress()) {
6259             // IME predictive back animation is currently in progress which means that scrollY is
6260             // currently controlled by ImeBackAnimationController.
6261             return false;
6262         }
6263 
6264         final Rect ci = mAttachInfo.mContentInsets;
6265         final Rect vi = mAttachInfo.mVisibleInsets;
6266         int scrollY = 0;
6267         boolean handled = false;
6268 
6269         if (vi.left > ci.left || vi.top > ci.top
6270                 || vi.right > ci.right || vi.bottom > ci.bottom) {
6271             // We'll assume that we aren't going to change the scroll
6272             // offset, since we want to avoid that unless it is actually
6273             // going to make the focus visible...  otherwise we scroll
6274             // all over the place.
6275             scrollY = mScrollY;
6276             // We can be called for two different situations: during a draw,
6277             // to update the scroll position if the focus has changed (in which
6278             // case 'rectangle' is null), or in response to a
6279             // requestChildRectangleOnScreen() call (in which case 'rectangle'
6280             // is non-null and we just want to scroll to whatever that
6281             // rectangle is).
6282             final View focus = mView.findFocus();
6283             if (focus == null) {
6284                 return false;
6285             }
6286             View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
6287             if (focus != lastScrolledFocus) {
6288                 // If the focus has changed, then ignore any requests to scroll
6289                 // to a rectangle; first we want to make sure the entire focus
6290                 // view is visible.
6291                 rectangle = null;
6292             }
6293             if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
6294                     + " rectangle=" + rectangle + " ci=" + ci
6295                     + " vi=" + vi);
6296             if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
6297                 // Optimization: if the focus hasn't changed since last
6298                 // time, and no layout has happened, then just leave things
6299                 // as they are.
6300                 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
6301                         + mScrollY + " vi=" + vi.toShortString());
6302             } else {
6303                 // We need to determine if the currently focused view is
6304                 // within the visible part of the window and, if not, apply
6305                 // a pan so it can be seen.
6306                 mLastScrolledFocus = new WeakReference<View>(focus);
6307                 mScrollMayChange = false;
6308                 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
6309                 // Try to find the rectangle from the focus view.
6310                 if (focus.getGlobalVisibleRect(mVisRect, null)) {
6311                     if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
6312                             + mView.getWidth() + " h=" + mView.getHeight()
6313                             + " ci=" + ci.toShortString()
6314                             + " vi=" + vi.toShortString());
6315                     if (rectangle == null) {
6316                         focus.getFocusedRect(mTempRect);
6317                         if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
6318                                 + ": focusRect=" + mTempRect.toShortString());
6319                         if (mView instanceof ViewGroup) {
6320                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
6321                                     focus, mTempRect);
6322                         }
6323                         if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6324                                 "Focus in window: focusRect="
6325                                 + mTempRect.toShortString()
6326                                 + " visRect=" + mVisRect.toShortString());
6327                     } else {
6328                         mTempRect.set(rectangle);
6329                         if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6330                                 "Request scroll to rect: "
6331                                 + mTempRect.toShortString()
6332                                 + " visRect=" + mVisRect.toShortString());
6333                     }
6334                     if (mTempRect.intersect(mVisRect)) {
6335                         if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6336                                 "Focus window visible rect: "
6337                                 + mTempRect.toShortString());
6338                         if (mTempRect.height() >
6339                                 (mView.getHeight()-vi.top-vi.bottom)) {
6340                             // If the focus simply is not going to fit, then
6341                             // best is probably just to leave things as-is.
6342                             if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6343                                     "Too tall; leaving scrollY=" + scrollY);
6344                         }
6345                         // Next, check whether top or bottom is covered based on the non-scrolled
6346                         // position, and calculate new scrollY (or set it to 0).
6347                         // We can't keep using mScrollY here. For example mScrollY is non-zero
6348                         // due to IME, then IME goes away. The current value of mScrollY leaves top
6349                         // and bottom both visible, but we still need to scroll it back to 0.
6350                         else if (mTempRect.top < vi.top) {
6351                             scrollY = mTempRect.top - vi.top;
6352                             if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6353                                     "Top covered; scrollY=" + scrollY);
6354                         } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) {
6355                             scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom);
6356                             if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6357                                     "Bottom covered; scrollY=" + scrollY);
6358                         } else {
6359                             scrollY = 0;
6360                         }
6361                         handled = true;
6362                     }
6363                 }
6364             }
6365         }
6366 
6367         if (scrollY != mScrollY) {
6368             if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
6369                     + mScrollY + " , new=" + scrollY);
6370             if (!immediate) {
6371                 if (mScroller == null) {
6372                     mScroller = new Scroller(mView.getContext());
6373                 }
6374                 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
6375             } else if (mScroller != null) {
6376                 mScroller.abortAnimation();
6377             }
6378             mScrollY = scrollY;
6379         }
6380 
6381         return handled;
6382     }
6383 
6384     @VisibleForTesting(visibility = PACKAGE)
setScrollY(int scrollY)6385     public void setScrollY(int scrollY) {
6386         if (mScroller != null) {
6387             mScroller.abortAnimation();
6388         }
6389         mScrollY = scrollY;
6390     }
6391 
6392     @VisibleForTesting
getScrollY()6393     public int getScrollY() {
6394         return mScrollY;
6395     }
6396 
6397     /**
6398      * @hide
6399      */
6400     @UnsupportedAppUsage
getAccessibilityFocusedHost()6401     public View getAccessibilityFocusedHost() {
6402         return mAccessibilityFocusedHost;
6403     }
6404 
6405     /**
6406      * Get accessibility-focused virtual view. The bounds and sourceNodeId of the returned node is
6407      * up-to-date while other fields may be stale.
6408      *
6409      * @hide
6410      */
6411     @UnsupportedAppUsage
getAccessibilityFocusedVirtualView()6412     public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
6413         return mAccessibilityFocusedVirtualView;
6414     }
6415 
setAccessibilityFocus(View view, AccessibilityNodeInfo node)6416     void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
6417         // If we have a virtual view with accessibility focus we need
6418         // to clear the focus and invalidate the virtual view bounds.
6419         if (mAccessibilityFocusedVirtualView != null) {
6420 
6421             AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
6422             View focusHost = mAccessibilityFocusedHost;
6423 
6424             // Wipe the state of the current accessibility focus since
6425             // the call into the provider to clear accessibility focus
6426             // will fire an accessibility event which will end up calling
6427             // this method and we want to have clean state when this
6428             // invocation happens.
6429             mAccessibilityFocusedHost = null;
6430             mAccessibilityFocusedVirtualView = null;
6431 
6432             // Clear accessibility focus on the host after clearing state since
6433             // this method may be reentrant.
6434             focusHost.clearAccessibilityFocusNoCallbacks(
6435                     AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
6436 
6437             AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
6438             if (provider != null) {
6439                 // Invalidate the area of the cleared accessibility focus.
6440                 focusNode.getBoundsInParent(mTempRect);
6441                 focusHost.invalidate(mTempRect);
6442                 // Clear accessibility focus in the virtual node.
6443                 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
6444                         focusNode.getSourceNodeId());
6445                 provider.performAction(virtualNodeId,
6446                         AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
6447             }
6448             focusNode.recycle();
6449         }
6450         if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view))  {
6451             // Clear accessibility focus in the view.
6452             mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(
6453                     AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
6454         }
6455 
6456         // Set the new focus host and node.
6457         mAccessibilityFocusedHost = view;
6458         mAccessibilityFocusedVirtualView = node;
6459         updateKeepClearForAccessibilityFocusRect();
6460 
6461         requestInvalidateRootRenderNode();
6462         if (isAccessibilityFocusDirty()) {
6463             scheduleTraversals();
6464         }
6465     }
6466 
hasPointerCapture()6467     boolean hasPointerCapture() {
6468         return mPointerCapture;
6469     }
6470 
requestPointerCapture(boolean enabled)6471     void requestPointerCapture(boolean enabled) {
6472         final IBinder inputToken = getInputToken();
6473         if (inputToken == null) {
6474             Log.e(mTag, "No input channel to request Pointer Capture.");
6475             return;
6476         }
6477         InputManagerGlobal
6478                 .getInstance()
6479                 .requestPointerCapture(inputToken, enabled);
6480     }
6481 
handlePointerCaptureChanged(boolean hasCapture)6482     private void handlePointerCaptureChanged(boolean hasCapture) {
6483         if (mPointerCapture == hasCapture) {
6484             return;
6485         }
6486         mPointerCapture = hasCapture;
6487         if (mView != null) {
6488             mView.dispatchPointerCaptureChanged(hasCapture);
6489         }
6490     }
6491 
updateColorModeIfNeeded(@ctivityInfo.ColorMode int colorMode, float desiredRatio)6492     private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode,
6493             float desiredRatio) {
6494         if (mAttachInfo.mThreadedRenderer == null) {
6495             return;
6496         }
6497 
6498         boolean isHdr = colorMode == ActivityInfo.COLOR_MODE_HDR
6499                 || colorMode == ActivityInfo.COLOR_MODE_HDR10;
6500         if (isHdr && !mDisplay.isHdrSdrRatioAvailable()) {
6501             colorMode = ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
6502             isHdr = false;
6503         }
6504         // TODO: Centralize this sanitization? Why do we let setting bad modes?
6505         // Alternatively, can we just let HWUI figure it out? Do we need to care here?
6506         if (colorMode != ActivityInfo.COLOR_MODE_A8
6507                 && !getConfiguration().isScreenWideColorGamut()) {
6508             colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
6509         }
6510 
6511         logColorMode(colorMode, false);
6512 
6513         float automaticRatio = mAttachInfo.mThreadedRenderer.setColorMode(colorMode);
6514         if (desiredRatio == 0 || desiredRatio > automaticRatio) {
6515             desiredRatio = automaticRatio;
6516         }
6517 
6518         mHdrRenderState.setDesiredHdrSdrRatio(isHdr, desiredRatio);
6519     }
6520 
6521     @Override
requestChildFocus(View child, View focused)6522     public void requestChildFocus(View child, View focused) {
6523         if (DEBUG_INPUT_RESIZE) {
6524             Log.v(mTag, "Request child focus: focus now " + focused);
6525         }
6526         checkThread();
6527         scheduleTraversals();
6528     }
6529 
6530     @Override
clearChildFocus(View child)6531     public void clearChildFocus(View child) {
6532         if (DEBUG_INPUT_RESIZE) {
6533             Log.v(mTag, "Clearing child focus");
6534         }
6535         checkThread();
6536         scheduleTraversals();
6537     }
6538 
6539     @Override
getParentForAccessibility()6540     public ViewParent getParentForAccessibility() {
6541         return null;
6542     }
6543 
6544     @Override
focusableViewAvailable(View v)6545     public void focusableViewAvailable(View v) {
6546         checkThread();
6547         if (mView != null) {
6548             if (!mView.hasFocus()) {
6549                 if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) {
6550                     v.requestFocus();
6551                 }
6552             } else {
6553                 // the one case where will transfer focus away from the current one
6554                 // is if the current view is a view group that prefers to give focus
6555                 // to its children first AND the view is a descendant of it.
6556                 View focused = mView.findFocus();
6557                 if (focused instanceof ViewGroup) {
6558                     ViewGroup group = (ViewGroup) focused;
6559                     if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
6560                             && isViewDescendantOf(v, focused)) {
6561                         v.requestFocus();
6562                     }
6563                 }
6564             }
6565         }
6566     }
6567 
6568     @Override
recomputeViewAttributes(View child)6569     public void recomputeViewAttributes(View child) {
6570         checkThread();
6571         if (mView == child) {
6572             mAttachInfo.mRecomputeGlobalAttributes = true;
6573             if (!mWillDrawSoon) {
6574                 scheduleTraversals();
6575             }
6576         }
6577     }
6578 
dispatchDetachedFromWindow()6579     void dispatchDetachedFromWindow() {
6580         // Make sure we free-up insets resources if view never received onWindowFocusLost()
6581         // because of a die-signal
6582         mInsetsController.onWindowFocusLost();
6583         mFirstInputStage.onDetachedFromWindow();
6584         if (mView != null && mView.mAttachInfo != null) {
6585             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
6586             mView.dispatchDetachedFromWindow();
6587         }
6588 
6589         mAccessibilityInteractionConnectionManager.ensureNoConnection();
6590         mAccessibilityInteractionConnectionManager.ensureNoDirectConnection();
6591         removeSendWindowContentChangedCallback();
6592         if (android.view.accessibility.Flags.preventLeakingViewrootimpl()
6593                 && mAccessibilityInteractionController != null) {
6594             mAccessibilityInteractionController.destroy();
6595             mAccessibilityInteractionController = null;
6596         }
6597 
6598         destroyHardwareRenderer();
6599 
6600         setAccessibilityFocus(null, null);
6601 
6602         mInsetsController.cancelExistingAnimations();
6603 
6604         mView.assignParent(null);
6605         mView = null;
6606         mAttachInfo.mRootView = null;
6607 
6608         destroySurface();
6609 
6610         if (mInputQueueCallback != null && mInputQueue != null) {
6611             mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
6612             mInputQueue.dispose();
6613             mInputQueueCallback = null;
6614             mInputQueue = null;
6615         }
6616         try {
6617             mWindowSession.remove(mWindow.asBinder());
6618         } catch (RemoteException e) {
6619         }
6620         // Dispose receiver would dispose client InputChannel, too. That could send out a socket
6621         // broken event, so we need to unregister the server InputChannel when removing window to
6622         // prevent server side receive the event and prompt error.
6623         if (mInputEventReceiver != null) {
6624             mInputEventReceiver.dispose();
6625             mInputEventReceiver = null;
6626         }
6627 
6628         unregisterListeners();
6629         unscheduleTraversals();
6630     }
6631 
6632     /**
6633      * Notifies all callbacks that configuration and/or display has changed and updates internal
6634      * state.
6635      * @param mergedConfiguration New global and override config in {@link MergedConfiguration}
6636      *                            container.
6637      * @param force Flag indicating if we should force apply the config.
6638      * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not
6639      *                     changed.
6640      * @param activityWindowInfo New activity window info. {@code null} if it is non-app window, or
6641      *                           this is not a Configuration change to the activity window (global).
6642      */
performConfigurationChange(@onNull MergedConfiguration mergedConfiguration, boolean force, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo)6643     private void performConfigurationChange(@NonNull MergedConfiguration mergedConfiguration,
6644             boolean force, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) {
6645         if (mergedConfiguration == null) {
6646             throw new IllegalArgumentException("No merged config provided.");
6647         }
6648 
6649         final int lastRotation = mLastReportedMergedConfiguration.getMergedConfiguration()
6650                 .windowConfiguration.getRotation();
6651         final int newRotation = mergedConfiguration.getMergedConfiguration()
6652                 .windowConfiguration.getRotation();
6653         if (lastRotation != newRotation) {
6654             // Trigger ThreadedRenderer#updateSurface() if the surface control doesn't change.
6655             // Because even if the actual surface size is not changed, e.g. flip 180 degrees,
6656             // the buffers may still have content in previous rotation. And the next draw may
6657             // not update all regions, that causes some afterimages to flicker.
6658             mUpdateSurfaceNeeded = true;
6659             if (!mIsInTraversal) {
6660                 mForceNextWindowRelayout = true;
6661             }
6662         }
6663 
6664         Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
6665         Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration();
6666         if (DEBUG_CONFIGURATION) Log.v(mTag,
6667                 "Applying new config to window " + mWindowAttributes.getTitle()
6668                         + ", globalConfig: " + globalConfig
6669                         + ", overrideConfig: " + overrideConfig);
6670 
6671         final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
6672         if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
6673             globalConfig = new Configuration(globalConfig);
6674             overrideConfig = new Configuration(overrideConfig);
6675             ci.applyToConfiguration(mNoncompatDensity, globalConfig);
6676             ci.applyToConfiguration(mNoncompatDensity, overrideConfig);
6677         }
6678 
6679         synchronized (sConfigCallbacks) {
6680             for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
6681                 sConfigCallbacks.get(i).onConfigurationChanged(globalConfig);
6682             }
6683         }
6684 
6685         mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
6686         if (mLastReportedActivityWindowInfo != null && activityWindowInfo != null) {
6687             mLastReportedActivityWindowInfo.set(activityWindowInfo);
6688         }
6689 
6690         mForceNextConfigUpdate = force;
6691         if (mActivityConfigCallback != null) {
6692             // An activity callback is set - notify it about override configuration update.
6693             // This basically initiates a round trip to ActivityThread and back, which will ensure
6694             // that corresponding activity and resources are updated before updating inner state of
6695             // ViewRootImpl. Eventually it will call #updateConfiguration().
6696             mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId,
6697                     activityWindowInfo);
6698         } else {
6699             if (enableWindowContextResourcesUpdateOnConfigChange()) {
6700                 // There is no activity callback - update resources for window token, if needed.
6701                 final IBinder windowContextToken = mContext.getWindowContextToken();
6702                 if (windowContextToken instanceof WindowTokenClient) {
6703                     WindowTokenClientController.getInstance().onWindowConfigurationChanged(
6704                             windowContextToken,
6705                             mLastReportedMergedConfiguration.getMergedConfiguration(),
6706                             newDisplayId == INVALID_DISPLAY
6707                                     ? mDisplay.getDisplayId()
6708                                     : newDisplayId
6709                     );
6710                 }
6711             }
6712             updateConfiguration(newDisplayId);
6713         }
6714         mForceNextConfigUpdate = false;
6715     }
6716 
6717     /**
6718      * Update display and views if last applied merged configuration changed.
6719      * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise.
6720      */
updateConfiguration(int newDisplayId)6721     public void updateConfiguration(int newDisplayId) {
6722         if (mView == null) {
6723             return;
6724         }
6725 
6726         // At this point the resources have been updated to
6727         // have the most recent config, whatever that is.  Use
6728         // the one in them which may be newer.
6729         final Resources localResources = mView.getResources();
6730         final Configuration config = localResources.getConfiguration();
6731 
6732         // Handle move to display.
6733         if (newDisplayId != INVALID_DISPLAY) {
6734             onMovedToDisplay(newDisplayId, config);
6735         }
6736 
6737         // Handle configuration change.
6738         if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
6739             // Update the display with new DisplayAdjustments.
6740             updateInternalDisplay(mDisplay.getDisplayId(), localResources);
6741 
6742             updateLastConfigurationFromResources(config);
6743             mView.dispatchConfigurationChanged(config);
6744 
6745             // We could have gotten this {@link Configuration} update after we called
6746             // {@link #performTraversals} with an older {@link Configuration}. As a result, our
6747             // window frame may be stale. We must ensure the next pass of {@link #performTraversals}
6748             // catches this.
6749             mForceNextWindowRelayout = true;
6750             requestLayout();
6751         }
6752 
6753         updateForceDarkMode();
6754     }
6755 
updateLastConfigurationFromResources(Configuration resConfig)6756     private void updateLastConfigurationFromResources(Configuration resConfig) {
6757         final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
6758         final int currentLayoutDirection = resConfig.getLayoutDirection();
6759         mLastConfigurationFromResources.setTo(resConfig);
6760         // Update layout direction in case the language or screen layout is changed.
6761         if (lastLayoutDirection != currentLayoutDirection && mView != null
6762                 && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
6763             mView.setLayoutDirection(currentLayoutDirection);
6764         }
6765     }
6766 
6767     /**
6768      * Return true if child is an ancestor of parent, (or equal to the parent).
6769      */
isViewDescendantOf(View child, View parent)6770     public static boolean isViewDescendantOf(View child, View parent) {
6771         if (child == parent) {
6772             return true;
6773         }
6774 
6775         final ViewParent theParent = child.getParent();
6776         return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
6777     }
6778 
forceLayout(View view)6779     private static void forceLayout(View view) {
6780         view.forceLayout();
6781         if (view instanceof ViewGroup) {
6782             ViewGroup group = (ViewGroup) view;
6783             final int count = group.getChildCount();
6784             for (int i = 0; i < count; i++) {
6785                 forceLayout(group.getChildAt(i));
6786             }
6787         }
6788     }
6789 
6790     private static final int MSG_INVALIDATE = 1;
6791     private static final int MSG_INVALIDATE_RECT = 2;
6792     private static final int MSG_DIE = 3;
6793     private static final int MSG_RESIZED = 4;
6794     private static final int MSG_RESIZED_REPORT = 5;
6795     private static final int MSG_WINDOW_FOCUS_CHANGED = 6;
6796     private static final int MSG_DISPATCH_INPUT_EVENT = 7;
6797     private static final int MSG_DISPATCH_APP_VISIBILITY = 8;
6798     private static final int MSG_DISPATCH_GET_NEW_SURFACE = 9;
6799     private static final int MSG_DISPATCH_KEY_FROM_IME = 11;
6800     private static final int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12;
6801     private static final int MSG_CHECK_FOCUS = 13;
6802     private static final int MSG_CLOSE_SYSTEM_DIALOGS = 14;
6803     private static final int MSG_DISPATCH_DRAG_EVENT = 15;
6804     private static final int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
6805     private static final int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
6806     private static final int MSG_UPDATE_CONFIGURATION = 18;
6807     private static final int MSG_PROCESS_INPUT_EVENTS = 19;
6808     private static final int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
6809     private static final int MSG_INVALIDATE_WORLD = 22;
6810     private static final int MSG_WINDOW_MOVED = 23;
6811     private static final int MSG_SYNTHESIZE_INPUT_EVENT = 24;
6812     private static final int MSG_DISPATCH_WINDOW_SHOWN = 25;
6813     private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
6814     private static final int MSG_POINTER_CAPTURE_CHANGED = 28;
6815     private static final int MSG_INSETS_CONTROL_CHANGED = 29;
6816     private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 30;
6817     private static final int MSG_SHOW_INSETS = 31;
6818     private static final int MSG_HIDE_INSETS = 32;
6819     private static final int MSG_REQUEST_SCROLL_CAPTURE = 33;
6820     private static final int MSG_WINDOW_TOUCH_MODE_CHANGED = 34;
6821     private static final int MSG_KEEP_CLEAR_RECTS_CHANGED = 35;
6822     private static final int MSG_REPORT_KEEP_CLEAR_RECTS = 36;
6823     private static final int MSG_PAUSED_FOR_SYNC_TIMEOUT = 37;
6824     private static final int MSG_DECOR_VIEW_GESTURE_INTERCEPTION = 38;
6825     private static final int MSG_TOUCH_BOOST_TIMEOUT = 39;
6826     private static final int MSG_CHECK_INVALIDATION_IDLE = 40;
6827     private static final int MSG_REFRESH_POINTER_ICON = 41;
6828     private static final int MSG_FRAME_RATE_SETTING = 42;
6829     private static final int MSG_SURFACE_REPLACED_TIMEOUT = 43;
6830     private static final int MSG_INITIAL_TOUCH_BOOST_TIMEOUT = 44;
6831 
6832     final class ViewRootHandler extends Handler {
6833         @Override
getMessageName(Message message)6834         public String getMessageName(Message message) {
6835             switch (message.what) {
6836                 case MSG_INVALIDATE:
6837                     return "MSG_INVALIDATE";
6838                 case MSG_INVALIDATE_RECT:
6839                     return "MSG_INVALIDATE_RECT";
6840                 case MSG_DIE:
6841                     return "MSG_DIE";
6842                 case MSG_RESIZED:
6843                     return "MSG_RESIZED";
6844                 case MSG_RESIZED_REPORT:
6845                     return "MSG_RESIZED_REPORT";
6846                 case MSG_WINDOW_FOCUS_CHANGED:
6847                     return "MSG_WINDOW_FOCUS_CHANGED";
6848                 case MSG_DISPATCH_INPUT_EVENT:
6849                     return "MSG_DISPATCH_INPUT_EVENT";
6850                 case MSG_DISPATCH_APP_VISIBILITY:
6851                     return "MSG_DISPATCH_APP_VISIBILITY";
6852                 case MSG_DISPATCH_GET_NEW_SURFACE:
6853                     return "MSG_DISPATCH_GET_NEW_SURFACE";
6854                 case MSG_DISPATCH_KEY_FROM_IME:
6855                     return "MSG_DISPATCH_KEY_FROM_IME";
6856                 case MSG_DISPATCH_KEY_FROM_AUTOFILL:
6857                     return "MSG_DISPATCH_KEY_FROM_AUTOFILL";
6858                 case MSG_CHECK_FOCUS:
6859                     return "MSG_CHECK_FOCUS";
6860                 case MSG_CLOSE_SYSTEM_DIALOGS:
6861                     return "MSG_CLOSE_SYSTEM_DIALOGS";
6862                 case MSG_DISPATCH_DRAG_EVENT:
6863                     return "MSG_DISPATCH_DRAG_EVENT";
6864                 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
6865                     return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
6866                 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
6867                     return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
6868                 case MSG_UPDATE_CONFIGURATION:
6869                     return "MSG_UPDATE_CONFIGURATION";
6870                 case MSG_PROCESS_INPUT_EVENTS:
6871                     return "MSG_PROCESS_INPUT_EVENTS";
6872                 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
6873                     return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
6874                 case MSG_WINDOW_MOVED:
6875                     return "MSG_WINDOW_MOVED";
6876                 case MSG_SYNTHESIZE_INPUT_EVENT:
6877                     return "MSG_SYNTHESIZE_INPUT_EVENT";
6878                 case MSG_DISPATCH_WINDOW_SHOWN:
6879                     return "MSG_DISPATCH_WINDOW_SHOWN";
6880                 case MSG_POINTER_CAPTURE_CHANGED:
6881                     return "MSG_POINTER_CAPTURE_CHANGED";
6882                 case MSG_INSETS_CONTROL_CHANGED:
6883                     return "MSG_INSETS_CONTROL_CHANGED";
6884                 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED:
6885                     return "MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED";
6886                 case MSG_SHOW_INSETS:
6887                     return "MSG_SHOW_INSETS";
6888                 case MSG_HIDE_INSETS:
6889                     return "MSG_HIDE_INSETS";
6890                 case MSG_WINDOW_TOUCH_MODE_CHANGED:
6891                     return "MSG_WINDOW_TOUCH_MODE_CHANGED";
6892                 case MSG_KEEP_CLEAR_RECTS_CHANGED:
6893                     return "MSG_KEEP_CLEAR_RECTS_CHANGED";
6894                 case MSG_CHECK_INVALIDATION_IDLE:
6895                     return "MSG_CHECK_INVALIDATION_IDLE";
6896                 case MSG_REFRESH_POINTER_ICON:
6897                     return "MSG_REFRESH_POINTER_ICON";
6898                 case MSG_TOUCH_BOOST_TIMEOUT:
6899                     return "MSG_TOUCH_BOOST_TIMEOUT";
6900                 case MSG_FRAME_RATE_SETTING:
6901                     return "MSG_FRAME_RATE_SETTING";
6902                 case MSG_SURFACE_REPLACED_TIMEOUT:
6903                     return "MSG_SURFACE_REPLACED_TIMEOUT";
6904                 case MSG_INITIAL_TOUCH_BOOST_TIMEOUT:
6905                     return "MSG_INITIAL_TOUCH_BOOST_TIMEOUT";
6906             }
6907             return super.getMessageName(message);
6908         }
6909 
6910         @Override
sendMessageAtTime(Message msg, long uptimeMillis)6911         public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
6912             if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
6913                 // Debugging for b/27963013
6914                 throw new NullPointerException(
6915                         "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
6916             }
6917             return super.sendMessageAtTime(msg, uptimeMillis);
6918         }
6919 
6920         @Override
handleMessage(Message msg)6921         public void handleMessage(Message msg) {
6922             if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
6923                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, getMessageName(msg));
6924             }
6925             try {
6926                 handleMessageImpl(msg);
6927             } finally {
6928                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
6929             }
6930         }
6931 
handleMessageImpl(Message msg)6932         private void handleMessageImpl(Message msg) {
6933             switch (msg.what) {
6934                 case MSG_INVALIDATE:
6935                     ((View) msg.obj).invalidate();
6936                     break;
6937                 case MSG_INVALIDATE_RECT:
6938                     final View.AttachInfo.InvalidateInfo info =
6939                             (View.AttachInfo.InvalidateInfo) msg.obj;
6940                     info.target.invalidate(info.left, info.top, info.right, info.bottom);
6941                     info.recycle();
6942                     break;
6943                 case MSG_PROCESS_INPUT_EVENTS:
6944                     mProcessInputEventsScheduled = false;
6945                     doProcessInputEvents();
6946                     break;
6947                 case MSG_DISPATCH_APP_VISIBILITY:
6948                     handleAppVisibility(msg.arg1 != 0);
6949                     break;
6950                 case MSG_DISPATCH_GET_NEW_SURFACE:
6951                     handleGetNewSurface();
6952                     break;
6953                 case MSG_RESIZED:
6954                 case MSG_RESIZED_REPORT: {
6955                     final SomeArgs args = (SomeArgs) msg.obj;
6956                     final ClientWindowFrames frames = (ClientWindowFrames) args.arg1;
6957                     final boolean reportDraw = msg.what == MSG_RESIZED_REPORT;
6958                     final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2;
6959                     final InsetsState insetsState = (InsetsState) args.arg3;
6960                     final ActivityWindowInfo activityWindowInfo = (ActivityWindowInfo) args.arg4;
6961                     final boolean forceLayout = args.argi1 != 0;
6962                     final boolean alwaysConsumeSystemBars = args.argi2 != 0;
6963                     final int displayId = args.argi3;
6964                     final int syncSeqId = args.argi4;
6965                     final boolean dragResizing = args.argi5 != 0;
6966                     handleResized(frames, reportDraw, mergedConfiguration, insetsState, forceLayout,
6967                             alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing,
6968                             activityWindowInfo);
6969                     args.recycle();
6970                     break;
6971                 }
6972                 case MSG_INSETS_CONTROL_CHANGED: {
6973                     final SomeArgs args = (SomeArgs) msg.obj;
6974                     final InsetsState insetsState = (InsetsState) args.arg1;
6975                     final InsetsSourceControl.Array activeControls =
6976                             (InsetsSourceControl.Array) args.arg2;
6977                     handleInsetsControlChanged(insetsState, activeControls);
6978                     args.recycle();
6979                     break;
6980                 }
6981                 case MSG_SHOW_INSETS: {
6982                     final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj;
6983                     ImeTracker.forLogging().onProgress(statsToken,
6984                             ImeTracker.PHASE_CLIENT_HANDLE_SHOW_INSETS);
6985                     if (mView == null) {
6986                         Log.e(TAG,
6987                                 String.format("Calling showInsets(%d,%b) on window that no longer"
6988                                         + " has views.", msg.arg1, msg.arg2 == 1));
6989                     }
6990                     clearLowProfileModeIfNeeded(msg.arg1, msg.arg2 == 1);
6991                     mInsetsController.show(msg.arg1, msg.arg2 == 1, statsToken);
6992                     break;
6993                 }
6994                 case MSG_HIDE_INSETS: {
6995                     final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj;
6996                     ImeTracker.forLogging().onProgress(statsToken,
6997                             ImeTracker.PHASE_CLIENT_HANDLE_HIDE_INSETS);
6998                     mInsetsController.hide(msg.arg1, msg.arg2 == 1, statsToken);
6999                     break;
7000                 }
7001                 case MSG_WINDOW_MOVED:
7002                     if (mAdded) {
7003                         final int w = mWinFrame.width();
7004                         final int h = mWinFrame.height();
7005                         final int l = msg.arg1;
7006                         final int t = msg.arg2;
7007                         mTmpFrames.frame.left = l;
7008                         mTmpFrames.frame.right = l + w;
7009                         mTmpFrames.frame.top = t;
7010                         mTmpFrames.frame.bottom = t + h;
7011                         setFrame(mTmpFrames.frame, false /* withinRelayout */);
7012                         maybeHandleWindowMove(mWinFrame);
7013                     }
7014                     break;
7015                 case MSG_WINDOW_FOCUS_CHANGED: {
7016                     handleWindowFocusChanged();
7017                 } break;
7018                 case MSG_WINDOW_TOUCH_MODE_CHANGED: {
7019                     handleWindowTouchModeChanged();
7020                 } break;
7021                 case MSG_DIE: {
7022                     doDie();
7023                 } break;
7024                 case MSG_DISPATCH_INPUT_EVENT: {
7025                     SomeArgs args = (SomeArgs) msg.obj;
7026                     InputEvent event = (InputEvent) args.arg1;
7027                     InputEventReceiver receiver = (InputEventReceiver) args.arg2;
7028                     enqueueInputEvent(event, receiver, 0, true);
7029                     args.recycle();
7030                 } break;
7031                 case MSG_SYNTHESIZE_INPUT_EVENT: {
7032                     InputEvent event = (InputEvent) msg.obj;
7033                     enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
7034                 } break;
7035                 case MSG_DISPATCH_KEY_FROM_IME: {
7036                     if (LOCAL_LOGV) {
7037                         Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView);
7038                     }
7039                     KeyEvent event = (KeyEvent) msg.obj;
7040                     if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) {
7041                         // The IME is trying to say this event is from the
7042                         // system!  Bad bad bad!
7043                         //noinspection UnusedAssignment
7044                         event = KeyEvent.changeFlags(event,
7045                                 event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
7046                     }
7047                     enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
7048                 } break;
7049                 case MSG_DISPATCH_KEY_FROM_AUTOFILL: {
7050                     if (LOCAL_LOGV) {
7051                         Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView);
7052                     }
7053                     KeyEvent event = (KeyEvent) msg.obj;
7054                     enqueueInputEvent(event, null, 0, true);
7055                 } break;
7056                 case MSG_CHECK_FOCUS: {
7057                     getImeFocusController().onScheduledCheckFocus();
7058                 } break;
7059                 case MSG_CLOSE_SYSTEM_DIALOGS: {
7060                     if (mView != null) {
7061                         mView.onCloseSystemDialogs((String) msg.obj);
7062                     }
7063                 } break;
7064                 case MSG_DISPATCH_DRAG_EVENT: {
7065                 } // fall through
7066                 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
7067                     DragEvent event = (DragEvent) msg.obj;
7068                     // only present when this app called startDrag()
7069                     event.mLocalState = mLocalDragState;
7070                     final boolean traceDragEvent = event.mAction != ACTION_DRAG_LOCATION;
7071                     try {
7072                         if (traceDragEvent) {
7073                             Trace.traceBegin(TRACE_TAG_VIEW,
7074                                     "c#" + DragEvent.actionToString(event.mAction));
7075                         }
7076                         handleDragEvent(event);
7077                     } finally {
7078                         if (traceDragEvent) {
7079                             Trace.traceEnd(TRACE_TAG_VIEW);
7080                         }
7081                     }
7082                 } break;
7083                 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
7084                     handleDispatchSystemUiVisibilityChanged();
7085                 } break;
7086                 case MSG_UPDATE_CONFIGURATION: {
7087                     Configuration config = (Configuration) msg.obj;
7088                     if (config.isOtherSeqNewer(
7089                             mLastReportedMergedConfiguration.getMergedConfiguration())) {
7090                         // If we already have a newer merged config applied - use its global part.
7091                         config = mLastReportedMergedConfiguration.getGlobalConfiguration();
7092                     }
7093 
7094                     // Use the newer global config and last reported override config.
7095                     mPendingMergedConfiguration.setConfiguration(config,
7096                             mLastReportedMergedConfiguration.getOverrideConfiguration());
7097                     if (mPendingActivityWindowInfo != null) {
7098                         mPendingActivityWindowInfo.set(mLastReportedActivityWindowInfo);
7099                     }
7100 
7101                     performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration),
7102                             false /* force */, INVALID_DISPLAY /* same display */,
7103                             mPendingActivityWindowInfo != null
7104                                     ? new ActivityWindowInfo(mPendingActivityWindowInfo)
7105                                     : null);
7106                 } break;
7107                 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
7108                     setAccessibilityFocus(null, null);
7109                 } break;
7110                 case MSG_INVALIDATE_WORLD: {
7111                     if (mView != null) {
7112                         invalidateWorld(mView);
7113                     }
7114                 } break;
7115                 case MSG_DISPATCH_WINDOW_SHOWN: {
7116                     handleDispatchWindowShown();
7117                 } break;
7118                 case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
7119                     final IResultReceiver receiver = (IResultReceiver) msg.obj;
7120                     final int deviceId = msg.arg1;
7121                     handleRequestKeyboardShortcuts(receiver, deviceId);
7122                 } break;
7123                 case MSG_POINTER_CAPTURE_CHANGED: {
7124                     final boolean hasCapture = msg.arg1 != 0;
7125                     handlePointerCaptureChanged(hasCapture);
7126                 } break;
7127                 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: {
7128                     systemGestureExclusionChanged();
7129                 }   break;
7130                 case MSG_DECOR_VIEW_GESTURE_INTERCEPTION: {
7131                     decorViewInterceptionChanged(/* intercepted= */ msg.arg1 == 1);
7132                 }   break;
7133                 case MSG_KEEP_CLEAR_RECTS_CHANGED: {
7134                     keepClearRectsChanged(/* accessibilityFocusRectChanged= */ msg.arg1 == 1);
7135                 }   break;
7136                 case MSG_REPORT_KEEP_CLEAR_RECTS: {
7137                     reportKeepClearAreasChanged();
7138                 }   break;
7139                 case MSG_REQUEST_SCROLL_CAPTURE:
7140                     handleScrollCaptureRequest((IScrollCaptureResponseListener) msg.obj);
7141                     break;
7142                 case MSG_PAUSED_FOR_SYNC_TIMEOUT:
7143                     resumeAfterSyncTimeout();
7144                     break;
7145                 case MSG_CHECK_INVALIDATION_IDLE: {
7146                     long delta;
7147                     if (mIsTouchBoosting || mIsFrameRateBoosting || mInsetsAnimationRunning) {
7148                         delta = 0;
7149                     } else {
7150                         delta = System.nanoTime() / NANOS_PER_MILLI - mLastUpdateTimeMillis;
7151                     }
7152                     if (delta >= IDLE_TIME_MILLIS) {
7153                         mFrameRateCategoryHighCount = 0;
7154                         mFrameRateCategoryHighHintCount = 0;
7155                         mFrameRateCategoryNormalCount = 0;
7156                         mFrameRateCategoryLowCount = 0;
7157                         mPreferredFrameRate = 0;
7158                         mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
7159                         updateFrameRateFromThreadedRendererViews();
7160                         setPreferredFrameRate(mPreferredFrameRate);
7161                         setPreferredFrameRateCategory(mPreferredFrameRateCategory);
7162                         mInvalidationIdleMessagePosted = false;
7163                         mIsPressedGesture = false;
7164                     } else {
7165                         mInvalidationIdleMessagePosted = true;
7166                         mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
7167                                 IDLE_TIME_MILLIS - delta);
7168                     }
7169                     break;
7170                 }
7171                 case MSG_TOUCH_BOOST_TIMEOUT:
7172                     /**
7173                      * Lower the frame rate after the boosting period (FRAME_RATE_TOUCH_BOOST_TIME).
7174                      */
7175                     mIsFrameRateBoosting = false;
7176                     mIsTouchBoosting = false;
7177                     if (!mDrawnThisFrame) {
7178                         setPreferredFrameRateCategory(FRAME_RATE_CATEGORY_NO_PREFERENCE);
7179                     }
7180                     break;
7181                 case MSG_INITIAL_TOUCH_BOOST_TIMEOUT:
7182                     if (mTouchAndDrawn) {
7183                         mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT);
7184                         mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT,
7185                                 FRAME_RATE_TOUCH_BOOST_TIME);
7186                     } else {
7187                         mIsTouchBoosting = false;
7188                         setPreferredFrameRateCategory(FRAME_RATE_CATEGORY_NO_PREFERENCE);
7189                     }
7190                     mTouchAndDrawn = false;
7191                     break;
7192                 case MSG_REFRESH_POINTER_ICON:
7193                     if (mPointerIconEvent == null) {
7194                         break;
7195                     }
7196                     updatePointerIcon(mPointerIconEvent);
7197                     break;
7198                 case MSG_FRAME_RATE_SETTING:
7199                     mPreferredFrameRate = 0;
7200                     mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
7201                     break;
7202                 case MSG_SURFACE_REPLACED_TIMEOUT:
7203                     mSurfaceReplaced = false;
7204                     break;
7205             }
7206         }
7207     }
7208 
7209     final ViewRootHandler mHandler = new ViewRootHandler();
7210     final Executor mExecutor = (Runnable r) -> {
7211         mHandler.post(r);
7212     };
7213 
7214     /**
7215      * Something in the current window tells us we need to change the touch mode.  For
7216      * example, we are not in touch mode, and the user touches the screen.
7217      *
7218      * If the touch mode has changed, tell the window manager, and handle it locally.
7219      *
7220      * @param inTouchMode Whether we want to be in touch mode.
7221      * @return True if the touch mode changed and focus changed was changed as a result
7222      */
7223     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
ensureTouchMode(boolean inTouchMode)7224     boolean ensureTouchMode(boolean inTouchMode) {
7225         if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
7226                 + "touch mode is " + mAttachInfo.mInTouchMode);
7227         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
7228 
7229         if (inTouchMode && mAttachInfo.mThreadedRenderer != null && mSendPerfHintOnTouch) {
7230             mAttachInfo.mThreadedRenderer.notifyExpensiveFrame();
7231         }
7232 
7233         // tell the window manager
7234         try {
7235             IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService();
7236             windowManager.setInTouchMode(inTouchMode, getDisplayId());
7237         } catch (RemoteException e) {
7238             throw new RuntimeException(e);
7239         }
7240 
7241         // handle the change
7242         return ensureTouchModeLocally(inTouchMode);
7243     }
7244 
7245     /**
7246      * Ensure that the touch mode for this window is set, and if it is changing,
7247      * take the appropriate action.
7248      * @param inTouchMode Whether we want to be in touch mode.
7249      * @return True if the touch mode changed and focus changed was changed as a result
7250      */
ensureTouchModeLocally(boolean inTouchMode)7251     private boolean ensureTouchModeLocally(boolean inTouchMode) {
7252         if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
7253                 + "touch mode is " + mAttachInfo.mInTouchMode);
7254 
7255         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
7256 
7257         mAttachInfo.mInTouchMode = inTouchMode;
7258         mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
7259 
7260         return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
7261     }
7262 
enterTouchMode()7263     private boolean enterTouchMode() {
7264         if (mView != null && mView.hasFocus()) {
7265             // note: not relying on mFocusedView here because this could
7266             // be when the window is first being added, and mFocused isn't
7267             // set yet.
7268             final View focused = mView.findFocus();
7269             if (focused != null && !focused.isFocusableInTouchMode()) {
7270                 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
7271                 if (ancestorToTakeFocus != null) {
7272                     // there is an ancestor that wants focus after its
7273                     // descendants that is focusable in touch mode.. give it
7274                     // focus
7275                     return ancestorToTakeFocus.requestFocus();
7276                 } else {
7277                     // There's nothing to focus. Clear and propagate through the
7278                     // hierarchy, but don't attempt to place new focus.
7279                     focused.clearFocusInternal(null, true, false);
7280                     return true;
7281                 }
7282             }
7283         }
7284         return false;
7285     }
7286 
7287     /**
7288      * Find an ancestor of focused that wants focus after its descendants and is
7289      * focusable in touch mode.
7290      * @param focused The currently focused view.
7291      * @return An appropriate view, or null if no such view exists.
7292      */
findAncestorToTakeFocusInTouchMode(View focused)7293     private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
7294         ViewParent parent = focused.getParent();
7295         while (parent instanceof ViewGroup) {
7296             final ViewGroup vgParent = (ViewGroup) parent;
7297             if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
7298                     && vgParent.isFocusableInTouchMode()) {
7299                 return vgParent;
7300             }
7301             if (vgParent.isRootNamespace()) {
7302                 return null;
7303             } else {
7304                 parent = vgParent.getParent();
7305             }
7306         }
7307         return null;
7308     }
7309 
leaveTouchMode()7310     private boolean leaveTouchMode() {
7311         if (mView != null) {
7312             if (mView.hasFocus()) {
7313                 View focusedView = mView.findFocus();
7314                 if (!(focusedView instanceof ViewGroup)) {
7315                     // some view has focus, let it keep it
7316                     return false;
7317                 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
7318                         ViewGroup.FOCUS_AFTER_DESCENDANTS) {
7319                     // some view group has focus, and doesn't prefer its children
7320                     // over itself for focus, so let them keep it.
7321                     return false;
7322                 }
7323             }
7324 
7325             // find the best view to give focus to in this brave new non-touch-mode
7326             // world
7327             return mView.restoreDefaultFocus();
7328         }
7329         return false;
7330     }
7331 
7332     /**
7333      * Base class for implementing a stage in the chain of responsibility
7334      * for processing input events.
7335      * <p>
7336      * Events are delivered to the stage by the {@link #deliver} method.  The stage
7337      * then has the choice of finishing the event or forwarding it to the next stage.
7338      * </p>
7339      */
7340     abstract class InputStage {
7341         private final InputStage mNext;
7342 
7343         protected static final int FORWARD = 0;
7344         protected static final int FINISH_HANDLED = 1;
7345         protected static final int FINISH_NOT_HANDLED = 2;
7346 
7347         private String mTracePrefix;
7348 
7349         /**
7350          * Creates an input stage.
7351          * @param next The next stage to which events should be forwarded.
7352          */
InputStage(InputStage next)7353         public InputStage(InputStage next) {
7354             mNext = next;
7355         }
7356 
7357         /**
7358          * Delivers an event to be processed.
7359          */
deliver(QueuedInputEvent q)7360         public final void deliver(QueuedInputEvent q) {
7361             if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
7362                 forward(q);
7363             } else if (shouldDropInputEvent(q)) {
7364                 finish(q, false);
7365             } else {
7366                 traceEvent(q, Trace.TRACE_TAG_VIEW);
7367                 final int result;
7368                 try {
7369                     result = onProcess(q);
7370                 } finally {
7371                     Trace.traceEnd(Trace.TRACE_TAG_VIEW);
7372                 }
7373                 apply(q, result);
7374             }
7375         }
7376 
7377         /**
7378          * Marks the input event as finished then forwards it to the next stage.
7379          */
finish(QueuedInputEvent q, boolean handled)7380         protected void finish(QueuedInputEvent q, boolean handled) {
7381             q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
7382             if (handled) {
7383                 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
7384             }
7385             forward(q);
7386         }
7387 
7388         /**
7389          * Forwards the event to the next stage.
7390          */
forward(QueuedInputEvent q)7391         protected void forward(QueuedInputEvent q) {
7392             onDeliverToNext(q);
7393         }
7394 
7395         /**
7396          * Applies a result code from {@link #onProcess} to the specified event.
7397          */
apply(QueuedInputEvent q, int result)7398         protected void apply(QueuedInputEvent q, int result) {
7399             if (result == FORWARD) {
7400                 forward(q);
7401             } else if (result == FINISH_HANDLED) {
7402                 finish(q, true);
7403             } else if (result == FINISH_NOT_HANDLED) {
7404                 finish(q, false);
7405             } else {
7406                 throw new IllegalArgumentException("Invalid result: " + result);
7407             }
7408         }
7409 
7410         /**
7411          * Called when an event is ready to be processed.
7412          * @return A result code indicating how the event was handled.
7413          */
onProcess(QueuedInputEvent q)7414         protected int onProcess(QueuedInputEvent q) {
7415             return FORWARD;
7416         }
7417 
7418         /**
7419          * Called when an event is being delivered to the next stage.
7420          */
onDeliverToNext(QueuedInputEvent q)7421         protected void onDeliverToNext(QueuedInputEvent q) {
7422             if (DEBUG_INPUT_STAGES) {
7423                 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
7424             }
7425             if (mNext != null) {
7426                 mNext.deliver(q);
7427             } else {
7428                 finishInputEvent(q);
7429             }
7430         }
7431 
onWindowFocusChanged(boolean hasWindowFocus)7432         protected void onWindowFocusChanged(boolean hasWindowFocus) {
7433             if (mNext != null) {
7434                 mNext.onWindowFocusChanged(hasWindowFocus);
7435             }
7436         }
7437 
onDetachedFromWindow()7438         protected void onDetachedFromWindow() {
7439             if (mNext != null) {
7440                 mNext.onDetachedFromWindow();
7441             }
7442         }
7443 
shouldDropInputEvent(QueuedInputEvent q)7444         protected boolean shouldDropInputEvent(QueuedInputEvent q) {
7445             if (mView == null || !mAdded) {
7446                 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
7447                 return true;
7448             }
7449 
7450             // Find a reason for dropping or canceling the event.
7451             final String reason;
7452             // The embedded window is focused, allow this VRI to handle back key.
7453             if (!mAttachInfo.mHasWindowFocus && !isBack(q.mEvent)
7454                     && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
7455                     && !isAutofillUiShowing()) {
7456                 // This is a non-pointer event and the window doesn't currently have input focus
7457                 // This could be an event that came back from the previous stage
7458                 // but the window has lost focus or stopped in the meantime.
7459                 reason = "no window focus";
7460             } else if (mStopped) {
7461                 reason = "window is stopped";
7462             } else if (mIsAmbientMode
7463                     && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) {
7464                 reason = "non-button event in ambient mode";
7465             } else if (mPausedForTransition && !isBack(q.mEvent)) {
7466                 reason = "paused for transition";
7467             } else {
7468                 // Most common path: no reason to drop or cancel the event
7469                 return false;
7470             }
7471 
7472             if (isTerminalInputEvent(q.mEvent)) {
7473                 // Don't drop terminal input events, however mark them as canceled.
7474                 q.mEvent.cancel();
7475                 Slog.w(mTag, "Cancelling event (" + reason + "):" + q.mEvent);
7476                 return false;
7477             }
7478 
7479             // Drop non-terminal input events.
7480             Slog.w(mTag, "Dropping event (" + reason + "):" + q.mEvent);
7481             return true;
7482         }
7483 
dump(String prefix, PrintWriter writer)7484         void dump(String prefix, PrintWriter writer) {
7485             if (mNext != null) {
7486                 mNext.dump(prefix, writer);
7487             }
7488         }
7489 
isBack(InputEvent event)7490         boolean isBack(InputEvent event) {
7491             if (event instanceof KeyEvent) {
7492                 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
7493             } else {
7494                 return false;
7495             }
7496         }
7497 
traceEvent(QueuedInputEvent q, long traceTag)7498         private void traceEvent(QueuedInputEvent q, long traceTag) {
7499             if (!Trace.isTagEnabled(traceTag)) {
7500                 return;
7501             }
7502 
7503             if (mTracePrefix == null) {
7504                 mTracePrefix = getClass().getSimpleName();
7505             }
7506             Trace.traceBegin(traceTag, mTracePrefix + " id=0x"
7507                     + Integer.toHexString(q.mEvent.getId()));
7508         }
7509     }
7510 
7511     /**
7512      * Base class for implementing an input pipeline stage that supports
7513      * asynchronous and out-of-order processing of input events.
7514      * <p>
7515      * In addition to what a normal input stage can do, an asynchronous
7516      * input stage may also defer an input event that has been delivered to it
7517      * and finish or forward it later.
7518      * </p>
7519      */
7520     abstract class AsyncInputStage extends InputStage {
7521         private final String mTraceCounter;
7522 
7523         private QueuedInputEvent mQueueHead;
7524         private QueuedInputEvent mQueueTail;
7525         private int mQueueLength;
7526 
7527         protected static final int DEFER = 3;
7528 
7529         /**
7530          * Creates an asynchronous input stage.
7531          * @param next The next stage to which events should be forwarded.
7532          * @param traceCounter The name of a counter to record the size of
7533          * the queue of pending events.
7534          */
AsyncInputStage(InputStage next, String traceCounter)7535         public AsyncInputStage(InputStage next, String traceCounter) {
7536             super(next);
7537             mTraceCounter = traceCounter;
7538         }
7539 
7540         /**
7541          * Marks the event as deferred, which is to say that it will be handled
7542          * asynchronously.  The caller is responsible for calling {@link #forward}
7543          * or {@link #finish} later when it is done handling the event.
7544          */
defer(QueuedInputEvent q)7545         protected void defer(QueuedInputEvent q) {
7546             q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
7547             enqueue(q);
7548         }
7549 
7550         @Override
forward(QueuedInputEvent q)7551         protected void forward(QueuedInputEvent q) {
7552             // Clear the deferred flag.
7553             q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
7554 
7555             // Fast path if the queue is empty.
7556             QueuedInputEvent curr = mQueueHead;
7557             if (curr == null) {
7558                 super.forward(q);
7559                 return;
7560             }
7561 
7562             // Determine whether the event must be serialized behind any others
7563             // before it can be delivered to the next stage.  This is done because
7564             // deferred events might be handled out of order by the stage.
7565             final int deviceId = q.mEvent.getDeviceId();
7566             QueuedInputEvent prev = null;
7567             boolean blocked = false;
7568             while (curr != null && curr != q) {
7569                 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
7570                     blocked = true;
7571                 }
7572                 prev = curr;
7573                 curr = curr.mNext;
7574             }
7575 
7576             // If the event is blocked, then leave it in the queue to be delivered later.
7577             // Note that the event might not yet be in the queue if it was not previously
7578             // deferred so we will enqueue it if needed.
7579             if (blocked) {
7580                 if (curr == null) {
7581                     enqueue(q);
7582                 }
7583                 return;
7584             }
7585 
7586             // The event is not blocked.  Deliver it immediately.
7587             if (curr != null) {
7588                 curr = curr.mNext;
7589                 dequeue(q, prev);
7590             }
7591             super.forward(q);
7592 
7593             // Dequeuing this event may have unblocked successors.  Deliver them.
7594             while (curr != null) {
7595                 if (deviceId == curr.mEvent.getDeviceId()) {
7596                     if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
7597                         break;
7598                     }
7599                     QueuedInputEvent next = curr.mNext;
7600                     dequeue(curr, prev);
7601                     super.forward(curr);
7602                     curr = next;
7603                 } else {
7604                     prev = curr;
7605                     curr = curr.mNext;
7606                 }
7607             }
7608         }
7609 
7610         @Override
apply(QueuedInputEvent q, int result)7611         protected void apply(QueuedInputEvent q, int result) {
7612             if (result == DEFER) {
7613                 defer(q);
7614             } else {
7615                 super.apply(q, result);
7616             }
7617         }
7618 
enqueue(QueuedInputEvent q)7619         private void enqueue(QueuedInputEvent q) {
7620             if (mQueueTail == null) {
7621                 mQueueHead = q;
7622                 mQueueTail = q;
7623             } else {
7624                 mQueueTail.mNext = q;
7625                 mQueueTail = q;
7626             }
7627 
7628             mQueueLength += 1;
7629             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
7630         }
7631 
dequeue(QueuedInputEvent q, QueuedInputEvent prev)7632         private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
7633             if (prev == null) {
7634                 mQueueHead = q.mNext;
7635             } else {
7636                 prev.mNext = q.mNext;
7637             }
7638             if (mQueueTail == q) {
7639                 mQueueTail = prev;
7640             }
7641             q.mNext = null;
7642 
7643             mQueueLength -= 1;
7644             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
7645         }
7646 
7647         @Override
dump(String prefix, PrintWriter writer)7648         void dump(String prefix, PrintWriter writer) {
7649             writer.print(prefix);
7650             writer.print(getClass().getName());
7651             writer.print(": mQueueLength=");
7652             writer.println(mQueueLength);
7653 
7654             super.dump(prefix, writer);
7655         }
7656     }
7657 
7658     /**
7659      * Delivers pre-ime input events to a native activity.
7660      * Does not support pointer events.
7661      */
7662     final class NativePreImeInputStage extends AsyncInputStage
7663             implements InputQueue.FinishedInputEventCallback {
7664 
NativePreImeInputStage(InputStage next, String traceCounter)7665         public NativePreImeInputStage(InputStage next, String traceCounter) {
7666             super(next, traceCounter);
7667         }
7668 
7669         @Override
onProcess(QueuedInputEvent q)7670         protected int onProcess(QueuedInputEvent q) {
7671             if (q.forPreImeOnly()) {
7672                 // this event is intended for the ViewPreImeInputStage only, let's forward
7673                 return FORWARD;
7674             }
7675             if (q.mEvent instanceof KeyEvent) {
7676                 final KeyEvent keyEvent = (KeyEvent) q.mEvent;
7677 
7678                 // If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the
7679                 // view tree or IME, and invoke the appropriate {@link OnBackInvokedCallback}.
7680                 if (isBack(keyEvent)) {
7681                     if (mWindowlessBackKeyCallback != null) {
7682                         if (mWindowlessBackKeyCallback.test(keyEvent)) {
7683                             return keyEvent.getAction() == KeyEvent.ACTION_UP
7684                                     && !keyEvent.isCanceled()
7685                                     ? FINISH_HANDLED : FINISH_NOT_HANDLED;
7686                         } else {
7687                             // Unable to forward the back key to host, forward to next stage.
7688                             return FORWARD;
7689                         }
7690                     } else if (mContext != null
7691                             && mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
7692                         return doOnBackKeyEvent(keyEvent);
7693                     }
7694                 }
7695 
7696                 if (mInputQueue != null) {
7697                     mInputQueue.sendInputEvent(q.mEvent, q, true, this);
7698                     return DEFER;
7699                 }
7700             }
7701             return FORWARD;
7702         }
7703 
doOnBackKeyEvent(KeyEvent keyEvent)7704         private int doOnBackKeyEvent(KeyEvent keyEvent) {
7705             WindowOnBackInvokedDispatcher dispatcher = getOnBackInvokedDispatcher();
7706             OnBackInvokedCallback topCallback = dispatcher.getTopCallback();
7707             if (dispatcher.isBackGestureInProgress()) {
7708                 return FINISH_NOT_HANDLED;
7709             }
7710             if (topCallback instanceof OnBackAnimationCallback
7711                     && !(topCallback instanceof ImeBackAnimationController)) {
7712                 final OnBackAnimationCallback animationCallback =
7713                         (OnBackAnimationCallback) topCallback;
7714                 switch (keyEvent.getAction()) {
7715                     case KeyEvent.ACTION_DOWN:
7716                         // ACTION_DOWN is emitted twice: once when the user presses the button,
7717                         // and again a few milliseconds later.
7718                         // Based on the result of `keyEvent.getRepeatCount()` we have:
7719                         // - 0 means the button was pressed.
7720                         // - 1 means the button continues to be pressed (long press).
7721                         if (keyEvent.getRepeatCount() == 0) {
7722                             BackEvent backEvent;
7723                             if (predictiveBackSwipeEdgeNoneApi()) {
7724                                 backEvent = new BackEvent(0, 0, 0f, BackEvent.EDGE_NONE);
7725                             } else {
7726                                 backEvent = new BackEvent(0, 0, 0f, BackEvent.EDGE_LEFT);
7727                             }
7728                             animationCallback.onBackStarted(backEvent);
7729                         }
7730                         break;
7731                     case KeyEvent.ACTION_UP:
7732                         if (keyEvent.isCanceled()) {
7733                             animationCallback.onBackCancelled();
7734                         } else {
7735                             dispatcher.tryInvokeSystemNavigationObserverCallback();
7736                             topCallback.onBackInvoked();
7737                         }
7738                         break;
7739                 }
7740             } else if (topCallback != null) {
7741                 if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
7742                     if (!keyEvent.isCanceled()) {
7743                         dispatcher.tryInvokeSystemNavigationObserverCallback();
7744                         topCallback.onBackInvoked();
7745                     } else {
7746                         Log.d(mTag, "Skip onBackInvoked(), reason: keyEvent.isCanceled=true");
7747                     }
7748                 }
7749             }
7750             if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
7751                 // forward a cancelled event so that following stages cancel their back logic
7752                 keyEvent.cancel();
7753             }
7754             return FORWARD;
7755         }
7756 
7757         @Override
onFinishedInputEvent(Object token, boolean handled)7758         public void onFinishedInputEvent(Object token, boolean handled) {
7759             QueuedInputEvent q = (QueuedInputEvent)token;
7760             if (handled) {
7761                 finish(q, true);
7762                 return;
7763             }
7764             forward(q);
7765         }
7766     }
7767 
7768     /**
7769      * Delivers pre-ime input events to the view hierarchy.
7770      * Does not support pointer events.
7771      */
7772     final class ViewPreImeInputStage extends InputStage {
ViewPreImeInputStage(InputStage next)7773         public ViewPreImeInputStage(InputStage next) {
7774             super(next);
7775         }
7776 
7777         @Override
onProcess(QueuedInputEvent q)7778         protected int onProcess(QueuedInputEvent q) {
7779             if (q.mEvent instanceof KeyEvent) {
7780                 return processKeyEvent(q);
7781             }
7782             return FORWARD;
7783         }
7784 
processKeyEvent(QueuedInputEvent q)7785         private int processKeyEvent(QueuedInputEvent q) {
7786             final KeyEvent event = (KeyEvent)q.mEvent;
7787             if (mView.dispatchKeyEventPreIme(event)) {
7788                 return FINISH_HANDLED;
7789             } else if (q.forPreImeOnly()) {
7790                 return FINISH_NOT_HANDLED;
7791             }
7792             return FORWARD;
7793         }
7794     }
7795 
7796     /**
7797      * Delivers input events to the ime.
7798      * Does not support pointer events.
7799      */
7800     final class ImeInputStage extends AsyncInputStage
7801             implements InputMethodManager.FinishedInputEventCallback {
ImeInputStage(InputStage next, String traceCounter)7802         public ImeInputStage(InputStage next, String traceCounter) {
7803             super(next, traceCounter);
7804         }
7805 
7806         @Override
onProcess(QueuedInputEvent q)7807         protected int onProcess(QueuedInputEvent q) {
7808             final int result = mImeFocusController.onProcessImeInputStage(
7809                     q, q.mEvent, mWindowAttributes, this);
7810             switch (result) {
7811                 case InputMethodManager.DISPATCH_IN_PROGRESS:
7812                     // callback will be invoked later
7813                     return DEFER;
7814                 case InputMethodManager.DISPATCH_NOT_HANDLED:
7815                     // The IME could not handle it, so skip along to the next InputStage
7816                     return FORWARD;
7817                 case InputMethodManager.DISPATCH_HANDLED:
7818                     return FINISH_HANDLED;
7819                 default:
7820                     throw new IllegalStateException("Unexpected result=" + result);
7821             }
7822         }
7823 
7824         @Override
onFinishedInputEvent(Object token, boolean handled)7825         public void onFinishedInputEvent(Object token, boolean handled) {
7826             QueuedInputEvent q = (QueuedInputEvent)token;
7827             if (handled) {
7828                 finish(q, true);
7829                 return;
7830             }
7831             forward(q);
7832         }
7833     }
7834 
7835     /**
7836      * Performs early processing of post-ime input events.
7837      */
7838     final class EarlyPostImeInputStage extends InputStage {
EarlyPostImeInputStage(InputStage next)7839         public EarlyPostImeInputStage(InputStage next) {
7840             super(next);
7841         }
7842 
7843         @Override
onProcess(QueuedInputEvent q)7844         protected int onProcess(QueuedInputEvent q) {
7845             if (q.mEvent instanceof KeyEvent) {
7846                 return processKeyEvent(q);
7847             } else if (q.mEvent instanceof MotionEvent) {
7848                 return processMotionEvent(q);
7849             }
7850             return FORWARD;
7851         }
7852 
processKeyEvent(QueuedInputEvent q)7853         private int processKeyEvent(QueuedInputEvent q) {
7854             final KeyEvent event = (KeyEvent)q.mEvent;
7855 
7856             if (mAttachInfo.mTooltipHost != null) {
7857                 mAttachInfo.mTooltipHost.handleTooltipKey(event);
7858             }
7859 
7860             // If the key's purpose is to exit touch mode then we consume it
7861             // and consider it handled.
7862             if (checkForLeavingTouchModeAndConsume(event)) {
7863                 return FINISH_HANDLED;
7864             }
7865 
7866             // Make sure the fallback event policy sees all keys that will be
7867             // delivered to the view hierarchy.
7868             mFallbackEventHandler.preDispatchKeyEvent(event);
7869 
7870             // Reset last tracked MotionEvent click toolType.
7871             if (event.getAction() == KeyEvent.ACTION_DOWN) {
7872                 mLastClickToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
7873             }
7874 
7875             return FORWARD;
7876         }
7877 
processMotionEvent(QueuedInputEvent q)7878         private int processMotionEvent(QueuedInputEvent q) {
7879             final MotionEvent event = (MotionEvent) q.mEvent;
7880 
7881             if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
7882                 return processPointerEvent(q);
7883             }
7884 
7885             // If the motion event is from an absolute position device, exit touch mode
7886             final int action = event.getActionMasked();
7887             if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
7888                 if (event.isFromSource(InputDevice.SOURCE_CLASS_POSITION)) {
7889                     ensureTouchMode(false);
7890                 }
7891             }
7892             return FORWARD;
7893         }
7894 
processPointerEvent(QueuedInputEvent q)7895         private int processPointerEvent(QueuedInputEvent q) {
7896             final MotionEvent event = (MotionEvent)q.mEvent;
7897 
7898             // Translate the pointer event for compatibility, if needed.
7899             if (mTranslator != null) {
7900                 mTranslator.translateEventInScreenToAppWindow(event);
7901             }
7902 
7903             // Enter touch mode on down or scroll from any type of a device.
7904             final int action = event.getAction();
7905             if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
7906                 ensureTouchMode(true);
7907             }
7908 
7909             if (action == MotionEvent.ACTION_DOWN) {
7910                 // Upon motion event within app window, close autofill ui.
7911                 AutofillManager afm = getAutofillManager();
7912                 if (afm != null) {
7913                     afm.requestHideFillUi();
7914                 }
7915             }
7916 
7917             if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
7918                 mAttachInfo.mTooltipHost.hideTooltip();
7919             }
7920 
7921             // Offset the scroll position.
7922             if (mCurScrollY != 0) {
7923                 event.offsetLocation(0, mCurScrollY);
7924             }
7925 
7926             if (event.isTouchEvent()) {
7927                 // Remember the touch position for possible drag-initiation.
7928                 mLastTouchPoint.x = event.getRawX();
7929                 mLastTouchPoint.y = event.getRawY();
7930                 mLastTouchSource = event.getSource();
7931                 mLastTouchDeviceId = event.getDeviceId();
7932                 mLastTouchPointerId = event.getPointerId(0);
7933 
7934                 // Register last ACTION_UP. This will be propagated to IME.
7935                 if (event.getActionMasked() == MotionEvent.ACTION_UP) {
7936                     mLastClickToolType = event.getToolType(event.getActionIndex());
7937                 }
7938             }
7939             return FORWARD;
7940         }
7941     }
7942 
7943     /**
7944      * Delivers post-ime input events to a native activity.
7945      */
7946     final class NativePostImeInputStage extends AsyncInputStage
7947             implements InputQueue.FinishedInputEventCallback {
NativePostImeInputStage(InputStage next, String traceCounter)7948         public NativePostImeInputStage(InputStage next, String traceCounter) {
7949             super(next, traceCounter);
7950         }
7951 
7952         @Override
onProcess(QueuedInputEvent q)7953         protected int onProcess(QueuedInputEvent q) {
7954             if (mInputQueue != null) {
7955                 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
7956                 return DEFER;
7957             }
7958             return FORWARD;
7959         }
7960 
7961         @Override
onFinishedInputEvent(Object token, boolean handled)7962         public void onFinishedInputEvent(Object token, boolean handled) {
7963             QueuedInputEvent q = (QueuedInputEvent)token;
7964             if (handled) {
7965                 finish(q, true);
7966                 return;
7967             }
7968             forward(q);
7969         }
7970     }
7971 
7972     /**
7973      * Delivers post-ime input events to the view hierarchy.
7974      */
7975     final class ViewPostImeInputStage extends InputStage {
ViewPostImeInputStage(InputStage next)7976         public ViewPostImeInputStage(InputStage next) {
7977             super(next);
7978         }
7979 
7980         @Override
onProcess(QueuedInputEvent q)7981         protected int onProcess(QueuedInputEvent q) {
7982             if (q.mEvent instanceof KeyEvent) {
7983                 return processKeyEvent(q);
7984             } else {
7985                 final int source = q.mEvent.getSource();
7986                 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
7987                     return processPointerEvent(q);
7988                 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
7989                     return processTrackballEvent(q);
7990                 } else {
7991                     return processGenericMotionEvent(q);
7992                 }
7993             }
7994         }
7995 
7996         @Override
onDeliverToNext(QueuedInputEvent q)7997         protected void onDeliverToNext(QueuedInputEvent q) {
7998             if (mUnbufferedInputDispatch
7999                     && q.mEvent instanceof MotionEvent
8000                     && ((MotionEvent)q.mEvent).isTouchEvent()
8001                     && isTerminalInputEvent(q.mEvent)) {
8002                 mUnbufferedInputDispatch = false;
8003                 scheduleConsumeBatchedInput();
8004             }
8005             super.onDeliverToNext(q);
8006         }
8007 
performFocusNavigation(KeyEvent event)8008         private boolean performFocusNavigation(KeyEvent event) {
8009             @FocusDirection int direction = 0;
8010             switch (event.getKeyCode()) {
8011                 case KeyEvent.KEYCODE_DPAD_LEFT:
8012                     if (event.hasNoModifiers()) {
8013                         direction = View.FOCUS_LEFT;
8014                     }
8015                     break;
8016                 case KeyEvent.KEYCODE_DPAD_RIGHT:
8017                     if (event.hasNoModifiers()) {
8018                         direction = View.FOCUS_RIGHT;
8019                     }
8020                     break;
8021                 case KeyEvent.KEYCODE_DPAD_UP:
8022                     if (event.hasNoModifiers()) {
8023                         direction = View.FOCUS_UP;
8024                     }
8025                     break;
8026                 case KeyEvent.KEYCODE_DPAD_DOWN:
8027                     if (event.hasNoModifiers()) {
8028                         direction = View.FOCUS_DOWN;
8029                     }
8030                     break;
8031                 case KeyEvent.KEYCODE_TAB:
8032                     if (event.hasNoModifiers()) {
8033                         direction = View.FOCUS_FORWARD;
8034                     } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
8035                         direction = View.FOCUS_BACKWARD;
8036                     }
8037                     break;
8038             }
8039             if (direction != 0) {
8040                 View focused = mView.findFocus();
8041                 if (focused != null) {
8042                     mAttachInfo.mNextFocusLooped = false;
8043                     View v = focused.focusSearch(direction);
8044                     if (v != null && v != focused) {
8045                         if (mAttachInfo.mNextFocusLooped) {
8046                             // The next focus is looped. Let's try to move the focus to the adjacent
8047                             // window. Note: we still need to move the focus in this window
8048                             // regardless of what moveFocusToAdjacentWindow returns, so the focus
8049                             // can be looped back from the focus in the adjacent window to next
8050                             // focus of this window.
8051                             moveFocusToAdjacentWindow(direction);
8052                         }
8053 
8054                         // do the math the get the interesting rect
8055                         // of previous focused into the coord system of
8056                         // newly focused view
8057                         focused.getFocusedRect(mTempRect);
8058                         if (mView instanceof ViewGroup) {
8059                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
8060                                     focused, mTempRect);
8061                             ((ViewGroup) mView).offsetRectIntoDescendantCoords(
8062                                     v, mTempRect);
8063                         }
8064                         if (v.requestFocus(direction, mTempRect)) {
8065                             boolean isFastScrolling = event.getRepeatCount() > 0;
8066                             playSoundEffect(
8067                                     SoundEffectConstants.getConstantForFocusDirection(direction,
8068                                             isFastScrolling));
8069                             return true;
8070                         }
8071                     } else if (moveFocusToAdjacentWindow(direction)) {
8072                         return true;
8073                     }
8074 
8075                     // Give the focused view a last chance to handle the dpad key.
8076                     if (mView.dispatchUnhandledMove(focused, direction)) {
8077                         return true;
8078                     }
8079                 } else {
8080                     if (mView.restoreDefaultFocus()) {
8081                         return true;
8082                     } else if (moveFocusToAdjacentWindow(direction)) {
8083                         return true;
8084                     }
8085                 }
8086             }
8087             return false;
8088         }
8089 
moveFocusToAdjacentWindow(@ocusDirection int direction)8090         private boolean moveFocusToAdjacentWindow(@FocusDirection int direction) {
8091             final int windowingMode = getConfiguration().windowConfiguration.getWindowingMode();
8092             if (windowingMode != WINDOWING_MODE_MULTI_WINDOW
8093                     && windowingMode != WINDOWING_MODE_FREEFORM) {
8094                 return false;
8095             }
8096             try {
8097                 return mWindowSession.moveFocusToAdjacentWindow(mWindow, direction);
8098             } catch (RemoteException e) {
8099                 return false;
8100             }
8101         }
8102 
performKeyboardGroupNavigation(int direction)8103         private boolean performKeyboardGroupNavigation(int direction) {
8104             final View focused = mView.findFocus();
8105             if (focused == null && mView.restoreDefaultFocus()) {
8106                 return true;
8107             }
8108             View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction)
8109                     : focused.keyboardNavigationClusterSearch(null, direction);
8110 
8111             // Since requestFocus only takes "real" focus directions (and therefore also
8112             // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN.
8113             int realDirection = direction;
8114             if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
8115                 realDirection = View.FOCUS_DOWN;
8116             }
8117 
8118             if (cluster != null && cluster.isRootNamespace()) {
8119                 // the default cluster. Try to find a non-clustered view to focus.
8120                 if (cluster.restoreFocusNotInCluster()) {
8121                     playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
8122                     return true;
8123                 }
8124                 // otherwise skip to next actual cluster
8125                 cluster = keyboardNavigationClusterSearch(null, direction);
8126             }
8127 
8128             if (cluster != null && cluster.restoreFocusInCluster(realDirection)) {
8129                 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
8130                 return true;
8131             }
8132 
8133             return false;
8134         }
8135 
processKeyEvent(QueuedInputEvent q)8136         private int processKeyEvent(QueuedInputEvent q) {
8137             final KeyEvent event = (KeyEvent)q.mEvent;
8138 
8139             if (mUnhandledKeyManager.preViewDispatch(event)) {
8140                 return FINISH_HANDLED;
8141             }
8142 
8143             // Deliver the key to the view hierarchy.
8144             if (mView.dispatchKeyEvent(event)) {
8145                 return FINISH_HANDLED;
8146             }
8147 
8148             if (shouldDropInputEvent(q)) {
8149                 return FINISH_NOT_HANDLED;
8150             }
8151 
8152             // This dispatch is for windows that don't have a Window.Callback. Otherwise,
8153             // the Window.Callback usually will have already called this (see
8154             // DecorView.superDispatchKeyEvent) leaving this call a no-op.
8155             if (mUnhandledKeyManager.dispatch(mView, event)) {
8156                 return FINISH_HANDLED;
8157             }
8158 
8159             int groupNavigationDirection = 0;
8160 
8161             if (event.getAction() == KeyEvent.ACTION_DOWN
8162                     && event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
8163                 if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_CTRL_ON)) {
8164                     groupNavigationDirection = View.FOCUS_FORWARD;
8165                 } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),
8166                         KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) {
8167                     groupNavigationDirection = View.FOCUS_BACKWARD;
8168                 }
8169             }
8170 
8171             // If a modifier is held, try to interpret the key as a shortcut.
8172             if (event.getAction() == KeyEvent.ACTION_DOWN
8173                     && !KeyEvent.metaStateHasNoModifiers(event.getMetaState())
8174                     && event.getRepeatCount() == 0
8175                     && !KeyEvent.isModifierKey(event.getKeyCode())
8176                     && groupNavigationDirection == 0) {
8177                 if (mView.dispatchKeyShortcutEvent(event)) {
8178                     return FINISH_HANDLED;
8179                 }
8180                 if (shouldDropInputEvent(q)) {
8181                     return FINISH_NOT_HANDLED;
8182                 }
8183             }
8184 
8185             // Apply the fallback event policy.
8186             if (mFallbackEventHandler.dispatchKeyEvent(event)) {
8187                 return FINISH_HANDLED;
8188             }
8189             if (shouldDropInputEvent(q)) {
8190                 return FINISH_NOT_HANDLED;
8191             }
8192 
8193             // Handle automatic focus changes.
8194             if (event.getAction() == KeyEvent.ACTION_DOWN) {
8195                 if (groupNavigationDirection != 0) {
8196                     if (performKeyboardGroupNavigation(groupNavigationDirection)) {
8197                         return FINISH_HANDLED;
8198                     }
8199                 } else {
8200                     if (performFocusNavigation(event)) {
8201                         return FINISH_HANDLED;
8202                     }
8203                 }
8204             }
8205             return FORWARD;
8206         }
8207 
processPointerEvent(QueuedInputEvent q)8208         private int processPointerEvent(QueuedInputEvent q) {
8209             final MotionEvent event = (MotionEvent)q.mEvent;
8210             final int action = event.getAction();
8211             if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
8212                 mIsPressedGesture = false;
8213             }
8214             boolean handled = false;
8215             if (!disableHandwritingInitiatorForIme()
8216                     || mWindowAttributes.type != TYPE_INPUT_METHOD) {
8217                 handled = mHandwritingInitiator.onTouchEvent(event);
8218             }
8219             if (handled) {
8220                 // If handwriting is started, toolkit doesn't receive ACTION_UP.
8221                 mLastClickToolType = event.getToolType(event.getActionIndex());
8222             }
8223 
8224             mAttachInfo.mUnbufferedDispatchRequested = false;
8225             mAttachInfo.mHandlingPointerEvent = true;
8226             // If the event was fully handled by the handwriting initiator, then don't dispatch it
8227             // to the view tree.
8228             handled = handled || mView.dispatchPointerEvent(event);
8229             maybeUpdatePointerIcon(event);
8230             maybeUpdateTooltip(event);
8231             mAttachInfo.mHandlingPointerEvent = false;
8232             if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
8233                 mUnbufferedInputDispatch = true;
8234                 if (mConsumeBatchedInputScheduled) {
8235                     scheduleConsumeBatchedInputImmediately();
8236                 }
8237             }
8238 
8239             // For the variable refresh rate project
8240             if (handled && shouldTouchBoost(action & MotionEvent.ACTION_MASK,
8241                     mWindowAttributes.type)) {
8242                 // set the frame rate to the maximum value.
8243                 mIsTouchBoosting = true;
8244                 if (action == MotionEvent.ACTION_DOWN) {
8245                     mIsPressedGesture = true;
8246                 }
8247                 setPreferredFrameRateCategory(mLastPreferredFrameRateCategory);
8248             }
8249             /**
8250              * We want to lower the refresh rate when MotionEvent.ACTION_UP,
8251              * MotionEvent.ACTION_CANCEL is detected.
8252              * Not using ACTION_MOVE to avoid checking and sending messages too frequently.
8253              */
8254             if (mIsTouchBoosting && (action == MotionEvent.ACTION_UP
8255                     || action == MotionEvent.ACTION_CANCEL)) {
8256 
8257                 if (sToolkitInitialTouchBoostFlagValue) {
8258                     mHandler.removeMessages(MSG_INITIAL_TOUCH_BOOST_TIMEOUT);
8259                     mHandler.sendEmptyMessageDelayed(MSG_INITIAL_TOUCH_BOOST_TIMEOUT,
8260                             FRAME_RATE_INITIAL_TOUCH_BOOST_TIME);
8261                 } else {
8262                     mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT);
8263                     mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT,
8264                             FRAME_RATE_TOUCH_BOOST_TIME);
8265                 }
8266             }
8267             return handled ? FINISH_HANDLED : FORWARD;
8268         }
8269 
maybeUpdatePointerIcon(MotionEvent event)8270         private void maybeUpdatePointerIcon(MotionEvent event) {
8271             if (event.getPointerCount() != 1) {
8272                 return;
8273             }
8274             final int action = event.getActionMasked();
8275             final boolean needsStylusPointerIcon = event.isStylusPointer()
8276                     && event.isHoverEvent()
8277                     && mIsStylusPointerIconEnabled;
8278             if (!needsStylusPointerIcon && !event.isFromSource(InputDevice.SOURCE_MOUSE)) {
8279                 return;
8280             }
8281 
8282             if (action == MotionEvent.ACTION_HOVER_ENTER
8283                     || action == MotionEvent.ACTION_HOVER_EXIT) {
8284                 // Other apps or the window manager may change the icon type outside of
8285                 // this app, therefore the icon type has to be reset on enter/exit event.
8286                 mResolvedPointerIcon = null;
8287             }
8288 
8289             if (action != MotionEvent.ACTION_HOVER_EXIT) {
8290                 // Resolve the pointer icon
8291                 if (!updatePointerIcon(event) && action == MotionEvent.ACTION_HOVER_MOVE) {
8292                     mResolvedPointerIcon = null;
8293                 }
8294             }
8295 
8296             // Keep track of the newest event used to resolve the pointer icon.
8297             switch (action) {
8298                 case MotionEvent.ACTION_HOVER_EXIT:
8299                 case MotionEvent.ACTION_UP:
8300                 case MotionEvent.ACTION_POINTER_UP:
8301                 case MotionEvent.ACTION_CANCEL:
8302                     if (mPointerIconEvent != null) {
8303                         mPointerIconEvent.recycle();
8304                     }
8305                     mPointerIconEvent = null;
8306                     break;
8307                 default:
8308                     mPointerIconEvent = MotionEvent.obtain(event);
8309                     break;
8310             }
8311         }
8312 
processTrackballEvent(QueuedInputEvent q)8313         private int processTrackballEvent(QueuedInputEvent q) {
8314             final MotionEvent event = (MotionEvent)q.mEvent;
8315 
8316             if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
8317                 if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) {
8318                     return FINISH_HANDLED;
8319                 }
8320             }
8321 
8322             if (mView.dispatchTrackballEvent(event)) {
8323                 return FINISH_HANDLED;
8324             }
8325             return FORWARD;
8326         }
8327 
processGenericMotionEvent(QueuedInputEvent q)8328         private int processGenericMotionEvent(QueuedInputEvent q) {
8329             final MotionEvent event = (MotionEvent)q.mEvent;
8330 
8331             if (event.isFromSource(InputDevice.SOURCE_TOUCHPAD)) {
8332                 if (hasPointerCapture() && mView.dispatchCapturedPointerEvent(event)) {
8333                     return FINISH_HANDLED;
8334                 }
8335             }
8336 
8337             // Deliver the event to the view.
8338             if (mView.dispatchGenericMotionEvent(event)) {
8339                 return FINISH_HANDLED;
8340             }
8341             return FORWARD;
8342         }
8343     }
8344 
8345     /**
8346      * Returns whether this view is currently handling a pointer event.
8347      *
8348      * @hide
8349      */
isHandlingPointerEvent()8350     public boolean isHandlingPointerEvent() {
8351         return mAttachInfo.mHandlingPointerEvent;
8352     }
8353 
8354 
8355     /**
8356      * If there is pointer that is showing a PointerIcon in this window, refresh the icon for that
8357      * pointer. This will resolve the PointerIcon through the view hierarchy.
8358      */
refreshPointerIcon()8359     public void refreshPointerIcon() {
8360         mHandler.removeMessages(MSG_REFRESH_POINTER_ICON);
8361         mHandler.sendEmptyMessage(MSG_REFRESH_POINTER_ICON);
8362     }
8363 
updatePointerIcon(MotionEvent event)8364     private boolean updatePointerIcon(MotionEvent event) {
8365         final int pointerIndex = 0;
8366         final float x = event.getX(pointerIndex);
8367         final float y = event.getY(pointerIndex);
8368         if (mView == null) {
8369             // E.g. click outside a popup to dismiss it
8370             Slog.d(mTag, "updatePointerIcon called after view was removed");
8371             return false;
8372         }
8373         if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
8374             // E.g. when moving window divider with mouse
8375             Slog.d(mTag, "updatePointerIcon called with position out of bounds");
8376             return false;
8377         }
8378 
8379         PointerIcon pointerIcon = null;
8380         if (event.isStylusPointer() && mIsStylusPointerIconEnabled
8381                 && (!disableHandwritingInitiatorForIme()
8382                         || mWindowAttributes.type != TYPE_INPUT_METHOD)) {
8383             pointerIcon = mHandwritingInitiator.onResolvePointerIcon(mContext, event);
8384         }
8385         if (pointerIcon == null) {
8386             pointerIcon = mView.onResolvePointerIcon(event, pointerIndex);
8387         }
8388         if (pointerIcon == null) {
8389             pointerIcon = PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_NOT_SPECIFIED);
8390         }
8391         if (Objects.equals(mResolvedPointerIcon, pointerIcon)) {
8392             return true;
8393         }
8394         mResolvedPointerIcon = pointerIcon;
8395 
8396         InputManagerGlobal.getInstance()
8397                 .setPointerIcon(pointerIcon, event.getDisplayId(),
8398                         event.getDeviceId(), event.getPointerId(0), getInputToken());
8399         return true;
8400     }
8401 
maybeUpdateTooltip(MotionEvent event)8402     private void maybeUpdateTooltip(MotionEvent event) {
8403         if (event.getPointerCount() != 1) {
8404             return;
8405         }
8406         final int action = event.getActionMasked();
8407         if (action != MotionEvent.ACTION_HOVER_ENTER
8408                 && action != MotionEvent.ACTION_HOVER_MOVE
8409                 && action != MotionEvent.ACTION_HOVER_EXIT) {
8410             return;
8411         }
8412         if (mAccessibilityManager.isEnabled()
8413                 && mAccessibilityManager.isTouchExplorationEnabled()) {
8414             return;
8415         }
8416         if (mView == null) {
8417             Slog.d(mTag, "maybeUpdateTooltip called after view was removed");
8418             return;
8419         }
8420         mView.dispatchTooltipHoverEvent(event);
8421     }
8422 
8423     @Nullable
getFocusedViewOrNull()8424     private View getFocusedViewOrNull() {
8425         return mView != null ? mView.findFocus() : null;
8426     }
8427 
8428     /**
8429      * Performs synthesis of new input events from unhandled input events.
8430      */
8431     final class SyntheticInputStage extends InputStage {
8432         private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
8433         private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
8434         private final SyntheticTouchNavigationHandler mTouchNavigation =
8435                 new SyntheticTouchNavigationHandler();
8436         private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
8437 
SyntheticInputStage()8438         public SyntheticInputStage() {
8439             super(null);
8440         }
8441 
8442         @Override
onProcess(QueuedInputEvent q)8443         protected int onProcess(QueuedInputEvent q) {
8444             q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
8445             if (q.mEvent instanceof MotionEvent) {
8446                 final MotionEvent event = (MotionEvent)q.mEvent;
8447                 final int source = event.getSource();
8448                 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
8449                     // Do not synthesize events for relative mouse movement. If apps opt into
8450                     // relative mouse movement they must be prepared to handle the events.
8451                     if (!event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
8452                         mTrackball.process(event);
8453                     }
8454                     return FINISH_HANDLED;
8455                 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
8456                     mJoystick.process(event);
8457                     return FINISH_HANDLED;
8458                 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
8459                         == InputDevice.SOURCE_TOUCH_NAVIGATION) {
8460                     mTouchNavigation.process(event);
8461                     return FINISH_HANDLED;
8462                 }
8463             } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
8464                 mKeyboard.process((KeyEvent)q.mEvent);
8465                 return FINISH_HANDLED;
8466             }
8467 
8468             return FORWARD;
8469         }
8470 
8471         @Override
onDeliverToNext(QueuedInputEvent q)8472         protected void onDeliverToNext(QueuedInputEvent q) {
8473             if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
8474                 // Cancel related synthetic events if any prior stage has handled the event.
8475                 if (q.mEvent instanceof MotionEvent) {
8476                     final MotionEvent event = (MotionEvent)q.mEvent;
8477                     final int source = event.getSource();
8478                     if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
8479                         mTrackball.cancel();
8480                     } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
8481                         mJoystick.cancel();
8482                     } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
8483                             == InputDevice.SOURCE_TOUCH_NAVIGATION) {
8484                         // Touch navigation events cannot be cancelled since they are dispatched
8485                         // immediately.
8486                     }
8487                 }
8488             }
8489             super.onDeliverToNext(q);
8490         }
8491 
8492         @Override
onWindowFocusChanged(boolean hasWindowFocus)8493         protected void onWindowFocusChanged(boolean hasWindowFocus) {
8494             if (!hasWindowFocus) {
8495                 mJoystick.cancel();
8496             }
8497         }
8498 
8499         @Override
onDetachedFromWindow()8500         protected void onDetachedFromWindow() {
8501             mJoystick.cancel();
8502         }
8503     }
8504 
8505     /**
8506      * Creates dpad events from unhandled trackball movements.
8507      */
8508     final class SyntheticTrackballHandler {
8509         private final TrackballAxis mX = new TrackballAxis();
8510         private final TrackballAxis mY = new TrackballAxis();
8511         private long mLastTime;
8512 
process(MotionEvent event)8513         public void process(MotionEvent event) {
8514             // Translate the trackball event into DPAD keys and try to deliver those.
8515             long curTime = SystemClock.uptimeMillis();
8516             if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
8517                 // It has been too long since the last movement,
8518                 // so restart at the beginning.
8519                 mX.reset(0);
8520                 mY.reset(0);
8521                 mLastTime = curTime;
8522             }
8523 
8524             final int action = event.getAction();
8525             final int metaState = event.getMetaState();
8526             switch (action) {
8527                 case MotionEvent.ACTION_DOWN:
8528                     mX.reset(2);
8529                     mY.reset(2);
8530                     enqueueInputEvent(new KeyEvent(curTime, curTime,
8531                             KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
8532                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
8533                             InputDevice.SOURCE_KEYBOARD));
8534                     break;
8535                 case MotionEvent.ACTION_UP:
8536                     mX.reset(2);
8537                     mY.reset(2);
8538                     enqueueInputEvent(new KeyEvent(curTime, curTime,
8539                             KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
8540                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
8541                             InputDevice.SOURCE_KEYBOARD));
8542                     break;
8543             }
8544 
8545             if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
8546                     + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
8547                     + " move=" + event.getX()
8548                     + " / Y=" + mY.position + " step="
8549                     + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
8550                     + " move=" + event.getY());
8551             final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
8552             final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
8553 
8554             // Generate DPAD events based on the trackball movement.
8555             // We pick the axis that has moved the most as the direction of
8556             // the DPAD.  When we generate DPAD events for one axis, then the
8557             // other axis is reset -- we don't want to perform DPAD jumps due
8558             // to slight movements in the trackball when making major movements
8559             // along the other axis.
8560             int keycode = 0;
8561             int movement = 0;
8562             float accel = 1;
8563             if (xOff > yOff) {
8564                 movement = mX.generate();
8565                 if (movement != 0) {
8566                     keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
8567                             : KeyEvent.KEYCODE_DPAD_LEFT;
8568                     accel = mX.acceleration;
8569                     mY.reset(2);
8570                 }
8571             } else if (yOff > 0) {
8572                 movement = mY.generate();
8573                 if (movement != 0) {
8574                     keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
8575                             : KeyEvent.KEYCODE_DPAD_UP;
8576                     accel = mY.acceleration;
8577                     mX.reset(2);
8578                 }
8579             }
8580 
8581             if (keycode != 0) {
8582                 if (movement < 0) movement = -movement;
8583                 int accelMovement = (int)(movement * accel);
8584                 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
8585                         + " accelMovement=" + accelMovement
8586                         + " accel=" + accel);
8587                 if (accelMovement > movement) {
8588                     if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
8589                             + keycode);
8590                     movement--;
8591                     int repeatCount = accelMovement - movement;
8592                     enqueueInputEvent(new KeyEvent(curTime, curTime,
8593                             KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
8594                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
8595                             InputDevice.SOURCE_KEYBOARD));
8596                 }
8597                 while (movement > 0) {
8598                     if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
8599                             + keycode);
8600                     movement--;
8601                     curTime = SystemClock.uptimeMillis();
8602                     enqueueInputEvent(new KeyEvent(curTime, curTime,
8603                             KeyEvent.ACTION_DOWN, keycode, 0, metaState,
8604                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
8605                             InputDevice.SOURCE_KEYBOARD));
8606                     enqueueInputEvent(new KeyEvent(curTime, curTime,
8607                             KeyEvent.ACTION_UP, keycode, 0, metaState,
8608                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
8609                             InputDevice.SOURCE_KEYBOARD));
8610                 }
8611                 mLastTime = curTime;
8612             }
8613         }
8614 
cancel()8615         public void cancel() {
8616             mLastTime = Integer.MIN_VALUE;
8617 
8618             // If we reach this, we consumed a trackball event.
8619             // Because we will not translate the trackball event into a key event,
8620             // touch mode will not exit, so we exit touch mode here.
8621             if (mView != null && mAdded) {
8622                 ensureTouchMode(false);
8623             }
8624         }
8625     }
8626 
8627     /**
8628      * Maintains state information for a single trackball axis, generating
8629      * discrete (DPAD) movements based on raw trackball motion.
8630      */
8631     static final class TrackballAxis {
8632         /**
8633          * The maximum amount of acceleration we will apply.
8634          */
8635         static final float MAX_ACCELERATION = 20;
8636 
8637         /**
8638          * The maximum amount of time (in milliseconds) between events in order
8639          * for us to consider the user to be doing fast trackball movements,
8640          * and thus apply an acceleration.
8641          */
8642         static final long FAST_MOVE_TIME = 150;
8643 
8644         /**
8645          * Scaling factor to the time (in milliseconds) between events to how
8646          * much to multiple/divide the current acceleration.  When movement
8647          * is < FAST_MOVE_TIME this multiplies the acceleration; when >
8648          * FAST_MOVE_TIME it divides it.
8649          */
8650         static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
8651 
8652         static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
8653         static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
8654         static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
8655 
8656         float position;
8657         float acceleration = 1;
8658         long lastMoveTime = 0;
8659         int step;
8660         int dir;
8661         int nonAccelMovement;
8662 
reset(int _step)8663         void reset(int _step) {
8664             position = 0;
8665             acceleration = 1;
8666             lastMoveTime = 0;
8667             step = _step;
8668             dir = 0;
8669         }
8670 
8671         /**
8672          * Add trackball movement into the state.  If the direction of movement
8673          * has been reversed, the state is reset before adding the
8674          * movement (so that you don't have to compensate for any previously
8675          * collected movement before see the result of the movement in the
8676          * new direction).
8677          *
8678          * @return Returns the absolute value of the amount of movement
8679          * collected so far.
8680          */
collect(float off, long time, String axis)8681         float collect(float off, long time, String axis) {
8682             long normTime;
8683             if (off > 0) {
8684                 normTime = (long)(off * FAST_MOVE_TIME);
8685                 if (dir < 0) {
8686                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
8687                     position = 0;
8688                     step = 0;
8689                     acceleration = 1;
8690                     lastMoveTime = 0;
8691                 }
8692                 dir = 1;
8693             } else if (off < 0) {
8694                 normTime = (long)((-off) * FAST_MOVE_TIME);
8695                 if (dir > 0) {
8696                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
8697                     position = 0;
8698                     step = 0;
8699                     acceleration = 1;
8700                     lastMoveTime = 0;
8701                 }
8702                 dir = -1;
8703             } else {
8704                 normTime = 0;
8705             }
8706 
8707             // The number of milliseconds between each movement that is
8708             // considered "normal" and will not result in any acceleration
8709             // or deceleration, scaled by the offset we have here.
8710             if (normTime > 0) {
8711                 long delta = time - lastMoveTime;
8712                 lastMoveTime = time;
8713                 float acc = acceleration;
8714                 if (delta < normTime) {
8715                     // The user is scrolling rapidly, so increase acceleration.
8716                     float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
8717                     if (scale > 1) acc *= scale;
8718                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
8719                             + off + " normTime=" + normTime + " delta=" + delta
8720                             + " scale=" + scale + " acc=" + acc);
8721                     acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
8722                 } else {
8723                     // The user is scrolling slowly, so decrease acceleration.
8724                     float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
8725                     if (scale > 1) acc /= scale;
8726                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
8727                             + off + " normTime=" + normTime + " delta=" + delta
8728                             + " scale=" + scale + " acc=" + acc);
8729                     acceleration = acc > 1 ? acc : 1;
8730                 }
8731             }
8732             position += off;
8733             return Math.abs(position);
8734         }
8735 
8736         /**
8737          * Generate the number of discrete movement events appropriate for
8738          * the currently collected trackball movement.
8739          *
8740          * @return Returns the number of discrete movements, either positive
8741          * or negative, or 0 if there is not enough trackball movement yet
8742          * for a discrete movement.
8743          */
generate()8744         int generate() {
8745             int movement = 0;
8746             nonAccelMovement = 0;
8747             do {
8748                 final int dir = position >= 0 ? 1 : -1;
8749                 switch (step) {
8750                     // If we are going to execute the first step, then we want
8751                     // to do this as soon as possible instead of waiting for
8752                     // a full movement, in order to make things look responsive.
8753                     case 0:
8754                         if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
8755                             return movement;
8756                         }
8757                         movement += dir;
8758                         nonAccelMovement += dir;
8759                         step = 1;
8760                         break;
8761                     // If we have generated the first movement, then we need
8762                     // to wait for the second complete trackball motion before
8763                     // generating the second discrete movement.
8764                     case 1:
8765                         if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
8766                             return movement;
8767                         }
8768                         movement += dir;
8769                         nonAccelMovement += dir;
8770                         position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
8771                         step = 2;
8772                         break;
8773                     // After the first two, we generate discrete movements
8774                     // consistently with the trackball, applying an acceleration
8775                     // if the trackball is moving quickly.  This is a simple
8776                     // acceleration on top of what we already compute based
8777                     // on how quickly the wheel is being turned, to apply
8778                     // a longer increasing acceleration to continuous movement
8779                     // in one direction.
8780                     default:
8781                         if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
8782                             return movement;
8783                         }
8784                         movement += dir;
8785                         position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
8786                         float acc = acceleration;
8787                         acc *= 1.1f;
8788                         acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
8789                         break;
8790                 }
8791             } while (true);
8792         }
8793     }
8794 
8795     /**
8796      * Creates dpad events from unhandled joystick movements.
8797      */
8798     final class SyntheticJoystickHandler extends Handler {
8799         private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
8800         private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
8801 
8802         private final JoystickAxesState mJoystickAxesState = new JoystickAxesState();
8803         private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>();
8804 
8805         public SyntheticJoystickHandler() {
8806             super(true);
8807         }
8808 
8809         @Override
8810         public void handleMessage(Message msg) {
8811             switch (msg.what) {
8812                 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
8813                 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
8814                     if (mAttachInfo.mHasWindowFocus) {
8815                         KeyEvent oldEvent = (KeyEvent) msg.obj;
8816                         KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
8817                                 SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1);
8818                         enqueueInputEvent(e);
8819                         Message m = obtainMessage(msg.what, e);
8820                         m.setAsynchronous(true);
8821                         sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
8822                     }
8823                 } break;
8824             }
8825         }
8826 
8827         public void process(MotionEvent event) {
8828             switch(event.getActionMasked()) {
8829                 case MotionEvent.ACTION_CANCEL:
8830                     cancel();
8831                     break;
8832                 case MotionEvent.ACTION_MOVE:
8833                     update(event);
8834                     break;
8835                 default:
8836                     Log.w(mTag, "Unexpected action: " + event.getActionMasked());
8837             }
8838         }
8839 
8840         private void cancel() {
8841             removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
8842             removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
8843             for (int i = 0; i < mDeviceKeyEvents.size(); i++) {
8844                 final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i);
8845                 if (keyEvent != null) {
8846                     enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent,
8847                             SystemClock.uptimeMillis(), 0));
8848                 }
8849             }
8850             mDeviceKeyEvents.clear();
8851             mJoystickAxesState.resetState();
8852         }
8853 
8854         private void update(MotionEvent event) {
8855             final int historySize = event.getHistorySize();
8856             for (int h = 0; h < historySize; h++) {
8857                 final long time = event.getHistoricalEventTime(h);
8858                 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
8859                         event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h));
8860                 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
8861                         event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h));
8862                 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
8863                         event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h));
8864                 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
8865                         event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h));
8866             }
8867             final long time = event.getEventTime();
8868             mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
8869                     event.getAxisValue(MotionEvent.AXIS_X));
8870             mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
8871                     event.getAxisValue(MotionEvent.AXIS_Y));
8872             mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
8873                     event.getAxisValue(MotionEvent.AXIS_HAT_X));
8874             mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
8875                     event.getAxisValue(MotionEvent.AXIS_HAT_Y));
8876         }
8877 
8878         final class JoystickAxesState {
8879             // State machine: from neutral state (no button press) can go into
8880             // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event.
8881             // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state,
8882             // emitting an ACTION_UP event.
8883             private static final int STATE_UP_OR_LEFT = -1;
8884             private static final int STATE_NEUTRAL = 0;
8885             private static final int STATE_DOWN_OR_RIGHT = 1;
8886 
8887             final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y}
8888             final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y}
8889 
8890             void resetState() {
8891                 mAxisStatesHat[0] = STATE_NEUTRAL;
8892                 mAxisStatesHat[1] = STATE_NEUTRAL;
8893                 mAxisStatesStick[0] = STATE_NEUTRAL;
8894                 mAxisStatesStick[1] = STATE_NEUTRAL;
8895             }
8896 
8897             void updateStateForAxis(MotionEvent event, long time, int axis, float value) {
8898                 // Emit KeyEvent if necessary
8899                 // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y
8900                 final int axisStateIndex;
8901                 final int repeatMessage;
8902                 if (isXAxis(axis)) {
8903                     axisStateIndex = 0;
8904                     repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT;
8905                 } else if (isYAxis(axis)) {
8906                     axisStateIndex = 1;
8907                     repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT;
8908                 } else {
8909                     Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!");
8910                     return;
8911                 }
8912                 final int newState = joystickAxisValueToState(value);
8913 
8914                 final int currentState;
8915                 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
8916                     currentState = mAxisStatesStick[axisStateIndex];
8917                 } else {
8918                     currentState = mAxisStatesHat[axisStateIndex];
8919                 }
8920 
8921                 if (currentState == newState) {
8922                     return;
8923                 }
8924 
8925                 final int metaState = event.getMetaState();
8926                 final int deviceId = event.getDeviceId();
8927                 final int source = event.getSource();
8928 
8929                 if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) {
8930                     // send a button release event
8931                     final int keyCode = joystickAxisAndStateToKeycode(axis, currentState);
8932                     if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
8933                         enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
8934                                 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
8935                         // remove the corresponding pending UP event if focus lost/view detached
8936                         mDeviceKeyEvents.put(deviceId, null);
8937                     }
8938                     removeMessages(repeatMessage);
8939                 }
8940 
8941                 if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) {
8942                     // send a button down event
8943                     final int keyCode = joystickAxisAndStateToKeycode(axis, newState);
8944                     if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
8945                         KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode,
8946                                 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
8947                         enqueueInputEvent(keyEvent);
8948                         Message m = obtainMessage(repeatMessage, keyEvent);
8949                         m.setAsynchronous(true);
8950                         sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
8951                         // store the corresponding ACTION_UP event so that it can be sent
8952                         // if focus is lost or root view is removed
8953                         mDeviceKeyEvents.put(deviceId,
8954                                 new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
8955                                         0, metaState, deviceId, 0,
8956                                         KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED,
8957                                         source));
8958                     }
8959                 }
8960                 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
8961                     mAxisStatesStick[axisStateIndex] = newState;
8962                 } else {
8963                     mAxisStatesHat[axisStateIndex] = newState;
8964                 }
8965             }
8966 
8967             private boolean isXAxis(int axis) {
8968                 return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X;
8969             }
8970             private boolean isYAxis(int axis) {
8971                 return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y;
8972             }
8973 
8974             private int joystickAxisAndStateToKeycode(int axis, int state) {
8975                 if (isXAxis(axis) && state == STATE_UP_OR_LEFT) {
8976                     return KeyEvent.KEYCODE_DPAD_LEFT;
8977                 }
8978                 if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
8979                     return KeyEvent.KEYCODE_DPAD_RIGHT;
8980                 }
8981                 if (isYAxis(axis) && state == STATE_UP_OR_LEFT) {
8982                     return KeyEvent.KEYCODE_DPAD_UP;
8983                 }
8984                 if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
8985                     return KeyEvent.KEYCODE_DPAD_DOWN;
8986                 }
8987                 Log.e(mTag, "Unknown axis " + axis + " or direction " + state);
8988                 return KeyEvent.KEYCODE_UNKNOWN; // should never happen
8989             }
8990 
8991             private int joystickAxisValueToState(float value) {
8992                 if (value >= 0.5f) {
8993                     return STATE_DOWN_OR_RIGHT;
8994                 } else if (value <= -0.5f) {
8995                     return STATE_UP_OR_LEFT;
8996                 } else {
8997                     return STATE_NEUTRAL;
8998                 }
8999             }
9000         }
9001     }
9002 
9003     /**
9004      * Creates DPAD events from unhandled touch navigation movements.
9005      */
9006     final class SyntheticTouchNavigationHandler extends Handler {
9007         private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
9008 
9009         // The id of the input device that is being tracked.
9010         private int mCurrentDeviceId = -1;
9011         private int mCurrentSource;
9012 
9013         private int mPendingKeyMetaState;
9014 
9015         private final GestureDetector mGestureDetector;
9016 
9017         SyntheticTouchNavigationHandler() {
9018             super(true);
9019             mGestureDetector = new GestureDetector(mContext,
9020                     new GestureDetector.OnGestureListener() {
9021                         @Override
9022                         public boolean onDown(@NonNull MotionEvent e) {
9023                             // This can be ignored since it's not clear what KeyEvent this will
9024                             // belong to.
9025                             return true;
9026                         }
9027 
9028                         @Override
9029                         public void onShowPress(@NonNull MotionEvent e) {
9030                         }
9031 
9032                         @Override
9033                         public boolean onSingleTapUp(@NonNull MotionEvent e) {
9034                             dispatchTap(e.getEventTime());
9035                             return true;
9036                         }
9037 
9038                         @Override
9039                         public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
9040                                 float distanceX, float distanceY) {
9041                             // Scroll doesn't translate to DPAD events so should be ignored.
9042                             return true;
9043                         }
9044 
9045                         @Override
9046                         public void onLongPress(@NonNull MotionEvent e) {
9047                             // Long presses don't translate to DPAD events so should be ignored.
9048                         }
9049 
9050                         @Override
9051                         public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
9052                                 float velocityX, float velocityY) {
9053                             dispatchFling(velocityX, velocityY, e2.getEventTime());
9054                             return true;
9055                         }
9056                     },
9057                     /* handler= */ null,
9058                     VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE);
9059         }
9060 
9061         public void process(MotionEvent event) {
9062             if (event.getDevice() == null) {
9063                 // The current device is not supported.
9064                 if (DEBUG_TOUCH_NAVIGATION) {
9065                     Log.d(LOCAL_TAG,
9066                             "Current device not supported so motion event is not processed");
9067                 }
9068                 return;
9069             }
9070             mPendingKeyMetaState = event.getMetaState();
9071             // Update the current device information.
9072             final int deviceId = event.getDeviceId();
9073             final int source = event.getSource();
9074             if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
9075                 mCurrentDeviceId = deviceId;
9076                 mCurrentSource = source;
9077             }
9078 
9079             // Interpret the event.
9080             mGestureDetector.onTouchEvent(event);
9081         }
9082 
9083         private void dispatchTap(long time) {
9084             dispatchEvent(time, KeyEvent.KEYCODE_DPAD_CENTER);
9085         }
9086 
9087         private void dispatchFling(float x, float y, long time) {
9088             if (Math.abs(x) > Math.abs(y)) {
9089                 dispatchEvent(time,
9090                         x > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT);
9091             } else {
9092                 dispatchEvent(time, y > 0 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP);
9093             }
9094         }
9095 
dispatchEvent(long time, int keyCode)9096         private void dispatchEvent(long time, int keyCode) {
9097             if (DEBUG_TOUCH_NAVIGATION) {
9098                 Log.d(LOCAL_TAG, "Dispatching DPAD events DOWN and UP with keycode " + keyCode);
9099             }
9100             enqueueInputEvent(new KeyEvent(time, time,
9101                     KeyEvent.ACTION_DOWN, keyCode, /* repeat= */ 0, mPendingKeyMetaState,
9102                     mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK,
9103                     mCurrentSource));
9104             enqueueInputEvent(new KeyEvent(time, time,
9105                     KeyEvent.ACTION_UP, keyCode, /* repeat= */ 0, mPendingKeyMetaState,
9106                     mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK,
9107                     mCurrentSource));
9108         }
9109     }
9110 
9111     final class SyntheticKeyboardHandler {
process(KeyEvent event)9112         public void process(KeyEvent event) {
9113             if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
9114                 return;
9115             }
9116 
9117             final KeyCharacterMap kcm = event.getKeyCharacterMap();
9118             final int keyCode = event.getKeyCode();
9119             final int metaState = event.getMetaState();
9120 
9121             // Check for fallback actions specified by the key character map.
9122             KeyCharacterMap.FallbackAction fallbackAction =
9123                     kcm.getFallbackAction(keyCode, metaState);
9124             if (fallbackAction != null) {
9125                 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
9126                 KeyEvent fallbackEvent = KeyEvent.obtain(
9127                         event.getDownTime(), event.getEventTime(),
9128                         event.getAction(), fallbackAction.keyCode,
9129                         event.getRepeatCount(), fallbackAction.metaState,
9130                         event.getDeviceId(), event.getScanCode(),
9131                         flags, event.getSource(), null);
9132                 fallbackAction.recycle();
9133                 enqueueInputEvent(fallbackEvent);
9134             }
9135         }
9136     }
9137 
9138     /**
9139      * Returns true if the key is used for keyboard navigation.
9140      * @param keyEvent The key event.
9141      * @return True if the key is used for keyboard navigation.
9142      */
isNavigationKey(KeyEvent keyEvent)9143     private static boolean isNavigationKey(KeyEvent keyEvent) {
9144         switch (keyEvent.getKeyCode()) {
9145         case KeyEvent.KEYCODE_DPAD_LEFT:
9146         case KeyEvent.KEYCODE_DPAD_RIGHT:
9147         case KeyEvent.KEYCODE_DPAD_UP:
9148         case KeyEvent.KEYCODE_DPAD_DOWN:
9149         case KeyEvent.KEYCODE_DPAD_CENTER:
9150         case KeyEvent.KEYCODE_PAGE_UP:
9151         case KeyEvent.KEYCODE_PAGE_DOWN:
9152         case KeyEvent.KEYCODE_MOVE_HOME:
9153         case KeyEvent.KEYCODE_MOVE_END:
9154         case KeyEvent.KEYCODE_TAB:
9155         case KeyEvent.KEYCODE_SPACE:
9156         case KeyEvent.KEYCODE_ENTER:
9157             return true;
9158         }
9159         return false;
9160     }
9161 
9162     /**
9163      * Returns true if the key is used for typing.
9164      * @param keyEvent The key event.
9165      * @return True if the key is used for typing.
9166      */
isTypingKey(KeyEvent keyEvent)9167     private static boolean isTypingKey(KeyEvent keyEvent) {
9168         return keyEvent.getUnicodeChar() > 0;
9169     }
9170 
9171     /**
9172      * See if the key event means we should leave touch mode (and leave touch mode if so).
9173      * @param event The key event.
9174      * @return Whether this key event should be consumed (meaning the act of
9175      *   leaving touch mode alone is considered the event).
9176      */
checkForLeavingTouchModeAndConsume(KeyEvent event)9177     private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
9178         // Only relevant in touch mode.
9179         if (!mAttachInfo.mInTouchMode) {
9180             return false;
9181         }
9182 
9183         // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
9184         final int action = event.getAction();
9185         if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
9186             return false;
9187         }
9188 
9189         // Don't leave touch mode if the IME told us not to.
9190         if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
9191             return false;
9192         }
9193 
9194         // If the key can be used for keyboard navigation then leave touch mode
9195         // and select a focused view if needed (in ensureTouchMode).
9196         // When a new focused view is selected, we consume the navigation key because
9197         // navigation doesn't make much sense unless a view already has focus so
9198         // the key's purpose is to set focus.
9199         if (event.hasNoModifiers() && isNavigationKey(event)) {
9200             return ensureTouchMode(false);
9201         }
9202 
9203         // If the key can be used for typing then leave touch mode
9204         // and select a focused view if needed (in ensureTouchMode).
9205         // Always allow the view to process the typing key.
9206         if (isTypingKey(event)) {
9207             ensureTouchMode(false);
9208             return false;
9209         }
9210 
9211         return false;
9212     }
9213 
9214     /* drag/drop */
9215     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setLocalDragState(Object obj)9216     void setLocalDragState(Object obj) {
9217         mLocalDragState = obj;
9218     }
9219 
handleDragEvent(DragEvent event)9220     private void handleDragEvent(DragEvent event) {
9221         // From the root, only drag start/end/location are dispatched.  entered/exited
9222         // are determined and dispatched by the viewgroup hierarchy, who then report
9223         // that back here for ultimate reporting back to the framework.
9224         if (mView != null && mAdded) {
9225             final int what = event.mAction;
9226 
9227             // Cache the drag description when the operation starts, then fill it in
9228             // on subsequent calls as a convenience
9229             if (what == DragEvent.ACTION_DRAG_STARTED) {
9230                 mCurrentDragView = null;    // Start the current-recipient tracking
9231                 mDragDescription = event.mClipDescription;
9232                 if (mStartedDragViewForA11y != null) {
9233                     // Send a drag started a11y event
9234                     mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
9235                             AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_STARTED);
9236                 }
9237             } else {
9238                 if (what == DragEvent.ACTION_DRAG_ENDED) {
9239                     mDragDescription = null;
9240                 }
9241                 event.mClipDescription = mDragDescription;
9242             }
9243 
9244             if (what == DragEvent.ACTION_DRAG_EXITED) {
9245                 // A direct EXITED event means that the window manager knows we've just crossed
9246                 // a window boundary, so the current drag target within this one must have
9247                 // just been exited. Send the EXITED notification to the current drag view, if any.
9248                 if (View.sCascadedDragDrop) {
9249                     mView.dispatchDragEnterExitInPreN(event);
9250                 }
9251                 setDragFocus(null, event);
9252             } else {
9253                 // For events with a [screen] location, translate into window coordinates
9254                 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
9255                     mDragPoint.set(event.mX, event.mY);
9256                     if (mTranslator != null) {
9257                         mTranslator.translatePointInScreenToAppWindow(mDragPoint);
9258                     }
9259 
9260                     if (mCurScrollY != 0) {
9261                         mDragPoint.offset(0, mCurScrollY);
9262                     }
9263 
9264                     event.mX = mDragPoint.x;
9265                     event.mY = mDragPoint.y;
9266                 }
9267 
9268                 // Remember who the current drag target is pre-dispatch
9269                 final View prevDragView = mCurrentDragView;
9270 
9271                 if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
9272                     event.mClipData.prepareToEnterProcess(
9273                             mView.getContext().getAttributionSource());
9274                 }
9275 
9276                 // Now dispatch the drag/drop event
9277                 boolean result = mView.dispatchDragEvent(event);
9278 
9279                 if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
9280                     // If the LOCATION event wasn't delivered to any handler, no view now has a drag
9281                     // focus.
9282                     setDragFocus(null, event);
9283                 }
9284 
9285                 // If we changed apparent drag target, tell the OS about it
9286                 if (prevDragView != mCurrentDragView) {
9287                     try {
9288                         if (prevDragView != null) {
9289                             mWindowSession.dragRecipientExited(mWindow);
9290                         }
9291                         if (mCurrentDragView != null) {
9292                             mWindowSession.dragRecipientEntered(mWindow);
9293                         }
9294                     } catch (RemoteException e) {
9295                         Slog.e(mTag, "Unable to note drag target change");
9296                     }
9297                 }
9298 
9299                 // Report the drop result when we're done
9300                 if (what == DragEvent.ACTION_DROP) {
9301                     try {
9302                         Log.i(mTag, "Reporting drop result: " + result);
9303                         mWindowSession.reportDropResult(mWindow, result);
9304                     } catch (RemoteException e) {
9305                         Log.e(mTag, "Unable to report drop result");
9306                     }
9307                 }
9308 
9309                 // When the drag operation ends, reset drag-related state
9310                 if (what == DragEvent.ACTION_DRAG_ENDED) {
9311                     if (mStartedDragViewForA11y != null) {
9312                         // If the drag failed, send a cancelled event from the source. Otherwise,
9313                         // the View that accepted the drop sends CONTENT_CHANGE_TYPE_DRAG_DROPPED
9314                         if (!event.getResult()) {
9315                             mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
9316                                     AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_CANCELLED);
9317                         }
9318                         mStartedDragViewForA11y.setAccessibilityDragStarted(false);
9319                     }
9320                     mStartedDragViewForA11y = null;
9321                     mCurrentDragView = null;
9322                     setLocalDragState(null);
9323                     mAttachInfo.mDragToken = null;
9324                     if (mAttachInfo.mDragSurface != null) {
9325                         mAttachInfo.mDragSurface.release();
9326                         mAttachInfo.mDragSurface = null;
9327                     }
9328                     if (mAttachInfo.mDragData != null) {
9329                         View.cleanUpPendingIntents(mAttachInfo.mDragData);
9330                         mAttachInfo.mDragData = null;
9331                     }
9332                 }
9333             }
9334         }
9335         event.recycle();
9336     }
9337 
9338     /**
9339      * Notify that the window title changed
9340      */
onWindowTitleChanged()9341     public void onWindowTitleChanged() {
9342         mAttachInfo.mForceReportNewAttributes = true;
9343     }
9344 
handleDispatchWindowShown()9345     public void handleDispatchWindowShown() {
9346         mAttachInfo.mTreeObserver.dispatchOnWindowShown();
9347     }
9348 
handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)9349     public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
9350         Bundle data = new Bundle();
9351         ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
9352         if (mView != null) {
9353             mView.requestKeyboardShortcuts(list, deviceId);
9354         }
9355         int numGroups = list.size();
9356         for (int i = 0; i < numGroups; ++i) {
9357             final KeyboardShortcutGroup group = list.get(i);
9358             group.setPackageName(mBasePackageName);
9359 
9360         }
9361         data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
9362         try {
9363             receiver.send(0, data);
9364         } catch (RemoteException e) {
9365         }
9366     }
9367 
9368     @UnsupportedAppUsage
getLastTouchPoint(Point outLocation)9369     public void getLastTouchPoint(Point outLocation) {
9370         outLocation.x = (int) mLastTouchPoint.x;
9371         outLocation.y = (int) mLastTouchPoint.y;
9372     }
9373 
getLastTouchSource()9374     public int getLastTouchSource() {
9375         return mLastTouchSource;
9376     }
9377 
getLastTouchDeviceId()9378     public int getLastTouchDeviceId() {
9379         return mLastTouchDeviceId;
9380     }
9381 
getLastTouchPointerId()9382     public int getLastTouchPointerId() {
9383         return mLastTouchPointerId;
9384     }
9385 
9386     /**
9387      * Used by InputMethodManager.
9388      * @hide
9389      */
getLastClickToolType()9390     public int getLastClickToolType() {
9391         return mLastClickToolType;
9392     }
9393 
setDragFocus(View newDragTarget, DragEvent event)9394     public void setDragFocus(View newDragTarget, DragEvent event) {
9395         if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
9396             // Send EXITED and ENTERED notifications to the old and new drag focus views.
9397 
9398             final float tx = event.mX;
9399             final float ty = event.mY;
9400             final int action = event.mAction;
9401             final ClipData td = event.mClipData;
9402             // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
9403             event.mX = 0;
9404             event.mY = 0;
9405             event.mClipData = null;
9406 
9407             if (mCurrentDragView != null) {
9408                 event.mAction = DragEvent.ACTION_DRAG_EXITED;
9409                 mCurrentDragView.callDragEventHandler(event);
9410             }
9411 
9412             if (newDragTarget != null) {
9413                 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
9414                 newDragTarget.callDragEventHandler(event);
9415             }
9416 
9417             event.mAction = action;
9418             event.mX = tx;
9419             event.mY = ty;
9420             event.mClipData = td;
9421         }
9422 
9423         mCurrentDragView = newDragTarget;
9424     }
9425 
9426     /** Sets the view that started drag and drop for the purpose of sending AccessibilityEvents */
setDragStartedViewForAccessibility(View view)9427     void setDragStartedViewForAccessibility(View view) {
9428         if (mStartedDragViewForA11y == null) {
9429             mStartedDragViewForA11y = view;
9430         }
9431     }
9432 
getAudioManager()9433     private AudioManager getAudioManager() {
9434         if (mView == null) {
9435             throw new IllegalStateException("getAudioManager called when there is no mView");
9436         }
9437         if (mAudioManager == null) {
9438             mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
9439             mFastScrollSoundEffectsEnabled = mAudioManager.areNavigationRepeatSoundEffectsEnabled();
9440         }
9441         return mAudioManager;
9442     }
9443 
getSystemVibrator()9444     private Vibrator getSystemVibrator() {
9445         if (mVibrator == null) {
9446             mVibrator = mContext.getSystemService(Vibrator.class);
9447         }
9448         return mVibrator;
9449     }
9450 
9451     /**
9452      * Clears the system vibrator.
9453      *
9454      * <p>This method releases the reference to the system vibrator. It's crucial to call this
9455      * method when the vibrator is no longer needed to prevent any potential memory leaks.
9456      */
clearSystemVibrator()9457     public void clearSystemVibrator() {
9458         mVibrator = null;
9459     }
9460 
getAutofillManager()9461     private @Nullable AutofillManager getAutofillManager() {
9462         if (mView instanceof ViewGroup) {
9463             ViewGroup decorView = (ViewGroup) mView;
9464             if (decorView.getChildCount() > 0) {
9465                 // We cannot use decorView's Context for querying AutofillManager: DecorView's
9466                 // context is based on Application Context, it would allocate a different
9467                 // AutofillManager instance.
9468                 return decorView.getChildAt(0).getContext()
9469                         .getSystemService(AutofillManager.class);
9470             }
9471         }
9472         return null;
9473     }
9474 
isAutofillUiShowing()9475     private boolean isAutofillUiShowing() {
9476         AutofillManager afm = getAutofillManager();
9477         if (afm == null) {
9478             return false;
9479         }
9480         return afm.isAutofillUiShowing();
9481     }
9482 
getAccessibilityInteractionController()9483     public AccessibilityInteractionController getAccessibilityInteractionController() {
9484         if (mView == null) {
9485             throw new IllegalStateException("getAccessibilityInteractionController"
9486                     + " called when there is no mView");
9487         }
9488         if (mAccessibilityInteractionController == null) {
9489             mAccessibilityInteractionController = new AccessibilityInteractionController(this);
9490         }
9491         return mAccessibilityInteractionController;
9492     }
9493 
relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending)9494     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
9495             boolean insetsPending) throws RemoteException {
9496         final WindowConfiguration winConfigFromAm = getConfiguration().windowConfiguration;
9497         final WindowConfiguration winConfigFromWm =
9498                 mLastReportedMergedConfiguration.getMergedConfiguration().windowConfiguration;
9499         final WindowConfiguration winConfig = getCompatWindowConfiguration();
9500         final int measuredWidth = mMeasuredWidth;
9501         final int measuredHeight = mMeasuredHeight;
9502         final boolean relayoutAsync;
9503         if ((mViewFrameInfo.flags & FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED) == 0
9504                 && mWindowAttributes.type != TYPE_APPLICATION_STARTING
9505                 && mSyncSeqId <= mLastSyncSeqId
9506                 && winConfigFromAm.diff(winConfigFromWm, false /* compareUndefined */) == 0) {
9507             final InsetsState state = mInsetsController.getState();
9508             final Rect displayCutoutSafe = mTempRect;
9509             state.getDisplayCutoutSafe(displayCutoutSafe);
9510             mWindowLayout.computeFrames(mWindowAttributes.forRotation(winConfig.getRotation()),
9511                     state, displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
9512                     measuredWidth, measuredHeight, mInsetsController.getRequestedVisibleTypes(),
9513                     1f /* compatScale */, mTmpFrames);
9514             mWinFrameInScreen.set(mTmpFrames.frame);
9515             if (mTranslator != null) {
9516                 mTranslator.translateRectInAppWindowToScreen(mWinFrameInScreen);
9517             }
9518 
9519             // If the position and the size of the frame are both changed, it will trigger a BLAST
9520             // sync, and we still need to call relayout to obtain the syncSeqId. Otherwise, we just
9521             // need to send attributes via relayoutAsync.
9522             final Rect oldFrame = mLastLayoutFrame;
9523             final Rect newFrame = mTmpFrames.frame;
9524             final boolean positionChanged =
9525                     newFrame.top != oldFrame.top || newFrame.left != oldFrame.left;
9526             final boolean sizeChanged =
9527                     newFrame.width() != oldFrame.width() || newFrame.height() != oldFrame.height();
9528             relayoutAsync = !positionChanged || !sizeChanged;
9529         } else {
9530             relayoutAsync = false;
9531         }
9532 
9533         float appScale = mAttachInfo.mApplicationScale;
9534         boolean restore = false;
9535         if (params != null && mTranslator != null) {
9536             restore = true;
9537             params.backup();
9538             mTranslator.translateWindowLayout(params);
9539         }
9540 
9541         if (params != null) {
9542             if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
9543 
9544             if (mOrigWindowType != params.type) {
9545                 // For compatibility with old apps, don't crash here.
9546                 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
9547                     Slog.w(mTag, "Window type can not be changed after "
9548                             + "the window is added; ignoring change of " + mView);
9549                     params.type = mOrigWindowType;
9550                 }
9551             }
9552         }
9553 
9554         final int requestedWidth = (int) (measuredWidth * appScale + 0.5f);
9555         final int requestedHeight = (int) (measuredHeight * appScale + 0.5f);
9556         int relayoutResult = 0;
9557         mRelayoutSeq++;
9558         if (relayoutAsync) {
9559             mWindowSession.relayoutAsync(mWindow, params,
9560                     requestedWidth, requestedHeight, viewVisibility,
9561                     insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
9562                     mLastSyncSeqId);
9563         } else {
9564             relayoutResult = mWindowSession.relayout(mWindow, params,
9565                     requestedWidth, requestedHeight, viewVisibility,
9566                     insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
9567                     mRelayoutSeq, mLastSyncSeqId, mRelayoutResult);
9568             mRelayoutRequested = true;
9569 
9570             onClientWindowFramesChanged(mTmpFrames);
9571 
9572             if (mPendingActivityWindowInfo != null) {
9573                 final ActivityWindowInfo outInfo = mRelayoutResult.activityWindowInfo;
9574                 if (outInfo != null) {
9575                     mPendingActivityWindowInfo.set(outInfo);
9576                 }
9577             }
9578             final int maybeSyncSeqId = mRelayoutResult.syncSeqId;
9579             if (maybeSyncSeqId > 0) {
9580                 mSyncSeqId = maybeSyncSeqId;
9581             }
9582 
9583             mWinFrameInScreen.set(mTmpFrames.frame);
9584             if (mTranslator != null) {
9585                 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
9586                 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.displayFrame);
9587                 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.attachedFrame);
9588             }
9589             mInvCompatScale = 1f / mTmpFrames.compatScale;
9590             CompatibilityInfo.applyOverrideIfNeeded(mPendingMergedConfiguration);
9591             handleInsetsControlChanged(mTempInsets, mTempControls);
9592 
9593             mPendingAlwaysConsumeSystemBars =
9594                     (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
9595         }
9596 
9597         final int transformHint = SurfaceControl.rotationToBufferTransform(
9598                 (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4);
9599         final boolean transformHintChanged = transformHint != mPreviousTransformHint;
9600         mPreviousTransformHint = transformHint;
9601         mSurfaceControl.setTransformHint(transformHint);
9602 
9603         WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth,
9604                 requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize);
9605 
9606         final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize);
9607         final boolean surfaceControlChanged =
9608                 (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) == RELAYOUT_RES_SURFACE_CHANGED;
9609         if (mAttachInfo.mThreadedRenderer != null &&
9610                 (transformHintChanged || sizeChanged || surfaceControlChanged)) {
9611             if (mAttachInfo.mThreadedRenderer.pause()) {
9612                 // Animations were running so we need to push a frame
9613                 // to resume them
9614                 mDirty.set(0, 0, mWidth, mHeight);
9615             }
9616         }
9617 
9618         if (mSurfaceControl.isValid()) {
9619             if (mPendingDragResizing && !mSurfaceSize.equals(
9620                     mWinFrameInScreen.width(), mWinFrameInScreen.height())) {
9621                 // During drag-resize, a single fullscreen-sized surface is reused for optimization.
9622                 // Crop to the content size instead of the surface size to avoid exposing garbage
9623                 // content that is still on the surface from previous re-layouts (e.g. when
9624                 // resizing to a larger size).
9625                 mTransaction.setWindowCrop(mSurfaceControl,
9626                         mWinFrameInScreen.width(), mWinFrameInScreen.height());
9627             } else if (!HardwareRenderer.isDrawingEnabled()) {
9628                 // When drawing is disabled the window layer won't have a valid buffer.
9629                 // Set a window crop so input can get delivered to the window.
9630                 mTransaction.setWindowCrop(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y).apply();
9631             }
9632         }
9633 
9634         if (mAttachInfo.mContentCaptureManager != null) {
9635             ContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
9636                     .getMainContentCaptureSession();
9637             mainSession.notifyWindowBoundsChanged(mainSession.getId(),
9638                     getConfiguration().windowConfiguration.getBounds());
9639         }
9640 
9641         if (mSurfaceControl.isValid()) {
9642             updateBlastSurfaceIfNeeded();
9643             if (mAttachInfo.mThreadedRenderer != null) {
9644                 mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
9645             }
9646             mHdrRenderState.forceUpdateHdrSdrRatio();
9647             if (transformHintChanged) {
9648                 dispatchTransformHintChanged(transformHint);
9649             }
9650         } else {
9651             if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.pause()) {
9652                 mDirty.set(0, 0, mWidth, mHeight);
9653             }
9654             destroySurface();
9655         }
9656 
9657         if (restore) {
9658             params.restore();
9659         }
9660 
9661         setFrame(mTmpFrames.frame, true /* withinRelayout */);
9662         return relayoutResult;
9663     }
9664 
updateOpacity(WindowManager.LayoutParams params, boolean dragResizing, boolean forceUpdate)9665     private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing,
9666             boolean forceUpdate) {
9667         boolean opaque = false;
9668 
9669         if (!PixelFormat.formatHasAlpha(params.format)
9670                 // Don't make surface with surfaceInsets opaque as they display a
9671                 // translucent shadow.
9672                 && params.surfaceInsets.left == 0
9673                 && params.surfaceInsets.top == 0
9674                 && params.surfaceInsets.right == 0
9675                 && params.surfaceInsets.bottom == 0
9676                 // Don't make surface opaque when resizing to reduce the amount of
9677                 // artifacts shown in areas the app isn't drawing content to.
9678                 && !dragResizing) {
9679             opaque = true;
9680         }
9681 
9682         if (!forceUpdate && mIsSurfaceOpaque == opaque) {
9683             return;
9684         }
9685 
9686         final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
9687         if (renderer != null && renderer.rendererOwnsSurfaceControlOpacity()) {
9688             opaque = renderer.setSurfaceControlOpaque(opaque);
9689         } else {
9690             mTransaction.setOpaque(mSurfaceControl, opaque).apply();
9691         }
9692 
9693         mIsSurfaceOpaque = opaque;
9694     }
9695 
9696     /**
9697      * Set the mWinFrame of this window.
9698      * @param frame the new frame of this window.
9699      * @param withinRelayout {@code true} if this setting is within the relayout, or is the initial
9700      *                       setting. That will make sure in the relayout process, we always compare
9701      *                       the window frame with the last processed window frame.
9702      */
setFrame(Rect frame, boolean withinRelayout)9703     private void setFrame(Rect frame, boolean withinRelayout) {
9704         mWinFrame.set(frame);
9705         if (withinRelayout) {
9706             mLastLayoutFrame.set(frame);
9707         }
9708 
9709         final WindowConfiguration winConfig = getCompatWindowConfiguration();
9710         mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop()
9711                 ? winConfig.getMaxBounds()
9712                 : frame);
9713         // Surface position is now inherited from parent, and BackdropFrameRenderer uses backdrop
9714         // frame to position content. Thus, we just keep the size of backdrop frame, and remove the
9715         // offset to avoid double offset from display origin.
9716         mPendingBackDropFrame.offsetTo(0, 0);
9717 
9718         mInsetsController.onFrameChanged(mOverrideInsetsFrame != null ?
9719                 mOverrideInsetsFrame : frame);
9720     }
9721 
9722     /**
9723      * In the normal course of operations we compute insets relative to
9724      * the frame returned from relayout window. In the case of
9725      * SurfaceControlViewHost, this frame is in local coordinates
9726      * instead of global coordinates. We support this override
9727      * frame so we can allow SurfaceControlViewHost to set a frame
9728      * to be used to calculate insets, without disturbing the main
9729      * mFrame.
9730      */
setOverrideInsetsFrame(Rect frame)9731     void setOverrideInsetsFrame(Rect frame) {
9732         mOverrideInsetsFrame = new Rect(frame);
9733         mInsetsController.onFrameChanged(mOverrideInsetsFrame);
9734     }
9735 
9736     /**
9737      * Gets the current display size in which the window is being laid out, accounting for screen
9738      * decorations around it.
9739      */
getDisplayFrame(Rect outFrame)9740     void getDisplayFrame(Rect outFrame) {
9741         outFrame.set(mTmpFrames.displayFrame);
9742         // Apply sandboxing here (in getter) due to possible layout updates on the client after
9743         // mTmpFrames.displayFrame is received from the server.
9744         applyViewBoundsSandboxingIfNeeded(outFrame);
9745     }
9746 
9747     /**
9748      * Gets the current display size in which the window is being laid out, accounting for screen
9749      * decorations around it.
9750      */
getWindowVisibleDisplayFrame(Rect outFrame)9751     void getWindowVisibleDisplayFrame(Rect outFrame) {
9752         outFrame.set(mTmpFrames.displayFrame);
9753         // XXX This is really broken, and probably all needs to be done
9754         // in the window manager, and we need to know more about whether
9755         // we want the area behind or in front of the IME.
9756         final Rect insets = mAttachInfo.mVisibleInsets;
9757         outFrame.left += insets.left;
9758         outFrame.top += insets.top;
9759         outFrame.right -= insets.right;
9760         outFrame.bottom -= insets.bottom;
9761         // Apply sandboxing here (in getter) due to possible layout updates on the client after
9762         // mTmpFrames.displayFrame is received from the server.
9763         applyViewBoundsSandboxingIfNeeded(outFrame);
9764     }
9765 
9766     /**
9767      * Offset outRect to make it sandboxed within Window's bounds.
9768      *
9769      * <p>This is used by {@link android.view.View#getBoundsOnScreen},
9770      * {@link android.view.ViewRootImpl#getDisplayFrame} and
9771      * {@link android.view.ViewRootImpl#getWindowVisibleDisplayFrame}, which are invoked by
9772      * {@link android.view.View#getWindowDisplayFrame} and
9773      * {@link android.view.View#getWindowVisibleDisplayFrame}, as well as
9774      * {@link android.view.ViewDebug#captureLayers} for debugging.
9775      */
applyViewBoundsSandboxingIfNeeded(final Rect inOutRect)9776     void applyViewBoundsSandboxingIfNeeded(final Rect inOutRect) {
9777         if (mViewBoundsSandboxingEnabled) {
9778             final Rect bounds = getConfiguration().windowConfiguration.getBounds();
9779             inOutRect.offset(-bounds.left, -bounds.top);
9780         }
9781     }
9782 
9783     /**
9784      * Offset outLocation to make it sandboxed within Window's bounds.
9785      *
9786      * <p>This is used by {@link android.view.View#getLocationOnScreen(int[])}
9787      */
applyViewLocationSandboxingIfNeeded(@ize2) int[] outLocation)9788     public void applyViewLocationSandboxingIfNeeded(@Size(2) int[] outLocation) {
9789         if (mViewBoundsSandboxingEnabled) {
9790             final Rect bounds = getConfiguration().windowConfiguration.getBounds();
9791             outLocation[0] -= bounds.left;
9792             outLocation[1] -= bounds.top;
9793         }
9794     }
9795 
getViewBoundsSandboxingEnabled()9796     private boolean getViewBoundsSandboxingEnabled() {
9797         // System dialogs (e.g. ANR) can be created within System process, so handleBindApplication
9798         // may be never called. This results into all app compat changes being enabled
9799         // (see b/268007823) because AppCompatCallbacks.install() is never called with non-empty
9800         // array.
9801         // With ActivityThread.isSystem we verify that it is not the system process,
9802         // then this CompatChange can take effect.
9803         if (ActivityThread.isSystem()
9804                 || !CompatChanges.isChangeEnabled(OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS)) {
9805             // It is a system process or OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS change-id is disabled.
9806             return false;
9807         }
9808 
9809         // OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS is enabled by the device manufacturer.
9810         try {
9811             final List<PackageManager.Property> properties = mContext.getPackageManager()
9812                     .queryApplicationProperty(PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS);
9813 
9814             final boolean isOptedOut = !properties.isEmpty() && !properties.get(0).getBoolean();
9815             if (isOptedOut) {
9816                 // PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS is disabled by the app devs.
9817                 return false;
9818             }
9819         } catch (RuntimeException e) {
9820             // remote exception.
9821         }
9822 
9823         return true;
9824     }
9825 
9826     /**
9827      * {@inheritDoc}
9828      */
9829     @Override
playSoundEffect(@oundEffectConstants.SoundEffect int effectId)9830     public void playSoundEffect(@SoundEffectConstants.SoundEffect int effectId) {
9831         if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
9832             return;
9833         }
9834 
9835         checkThread();
9836 
9837         try {
9838             final AudioManager audioManager = getAudioManager();
9839 
9840             if (mFastScrollSoundEffectsEnabled
9841                     && SoundEffectConstants.isNavigationRepeat(effectId)) {
9842                 audioManager.playSoundEffect(
9843                         SoundEffectConstants.nextNavigationRepeatSoundEffectId());
9844                 return;
9845             }
9846 
9847             switch (effectId) {
9848                 case SoundEffectConstants.CLICK:
9849                     audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
9850                     return;
9851                 case SoundEffectConstants.NAVIGATION_DOWN:
9852                 case SoundEffectConstants.NAVIGATION_REPEAT_DOWN:
9853                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
9854                     return;
9855                 case SoundEffectConstants.NAVIGATION_LEFT:
9856                 case SoundEffectConstants.NAVIGATION_REPEAT_LEFT:
9857                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
9858                     return;
9859                 case SoundEffectConstants.NAVIGATION_RIGHT:
9860                 case SoundEffectConstants.NAVIGATION_REPEAT_RIGHT:
9861                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
9862                     return;
9863                 case SoundEffectConstants.NAVIGATION_UP:
9864                 case SoundEffectConstants.NAVIGATION_REPEAT_UP:
9865                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
9866                     return;
9867                 default:
9868                     throw new IllegalArgumentException("unknown effect id " + effectId +
9869                             " not defined in " + SoundEffectConstants.class.getCanonicalName());
9870             }
9871         } catch (IllegalStateException e) {
9872             // Exception thrown by getAudioManager() when mView is null
9873             Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
9874             e.printStackTrace();
9875         }
9876     }
9877 
9878     /**
9879      * {@inheritDoc}
9880      */
9881     @Override
performHapticFeedback(int effectId, int flags, int privFlags)9882     public boolean performHapticFeedback(int effectId, int flags, int privFlags) {
9883         if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
9884             return false;
9885         }
9886 
9887         getSystemVibrator().performHapticFeedback(
9888                 effectId, "ViewRootImpl#performHapticFeedback", flags, privFlags);
9889         return true;
9890     }
9891 
9892     @Override
performHapticFeedbackForInputDevice(int effectId, int inputDeviceId, int inputSource, @HapticFeedbackConstants.Flags int flags, @HapticFeedbackConstants.PrivateFlags int privFlags)9893     public void performHapticFeedbackForInputDevice(int effectId,
9894             int inputDeviceId, int inputSource,
9895             @HapticFeedbackConstants.Flags int flags,
9896             @HapticFeedbackConstants.PrivateFlags int privFlags) {
9897         if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
9898             return;
9899         }
9900 
9901         getSystemVibrator().performHapticFeedbackForInputDevice(effectId,
9902                 inputDeviceId, inputSource, "ViewRootImpl#performHapticFeedbackForInputDevice",
9903                 flags, privFlags);
9904     }
9905 
9906     /**
9907      * {@inheritDoc}
9908      */
9909     @Override
focusSearch(View focused, int direction)9910     public View focusSearch(View focused, int direction) {
9911         checkThread();
9912         if (!(mView instanceof ViewGroup)) {
9913             return null;
9914         }
9915         return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
9916     }
9917 
9918     /**
9919      * {@inheritDoc}
9920      */
9921     @Override
keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)9922     public View keyboardNavigationClusterSearch(View currentCluster,
9923             @FocusDirection int direction) {
9924         checkThread();
9925         return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
9926                 mView, currentCluster, direction);
9927     }
9928 
debug()9929     public void debug() {
9930         mView.debug();
9931     }
9932 
9933     /**
9934      * Export the state of {@link ViewRootImpl} and other relevant classes into a protocol buffer
9935      * output stream.
9936      *
9937      * @param proto Stream to write the state to
9938      * @param fieldId FieldId of ViewRootImpl as defined in the parent message
9939      */
9940     @GuardedBy("this")
dumpDebug(ProtoOutputStream proto, long fieldId)9941     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
9942         final long token = proto.start(fieldId);
9943         proto.write(VIEW, Objects.toString(mView));
9944         proto.write(DISPLAY_ID, mDisplay.getDisplayId());
9945         proto.write(APP_VISIBLE, mAppVisible);
9946         proto.write(HEIGHT, mHeight);
9947         proto.write(WIDTH, mWidth);
9948         proto.write(IS_ANIMATING, mIsAnimating);
9949         mVisRect.dumpDebug(proto, VISIBLE_RECT);
9950         proto.write(IS_DRAWING, mIsDrawing);
9951         proto.write(ADDED, mAdded);
9952         mWinFrame.dumpDebug(proto, WIN_FRAME);
9953         proto.write(LAST_WINDOW_INSETS, Objects.toString(mLastWindowInsets));
9954         proto.write(SOFT_INPUT_MODE, InputMethodDebug.softInputModeToString(mSoftInputMode));
9955         proto.write(SCROLL_Y, mScrollY);
9956         proto.write(CUR_SCROLL_Y, mCurScrollY);
9957         proto.write(REMOVED, mRemoved);
9958         mWindowAttributes.dumpDebug(proto, WINDOW_ATTRIBUTES);
9959         proto.end(token);
9960         mInsetsController.dumpDebug(proto, INSETS_CONTROLLER);
9961         mImeFocusController.dumpDebug(proto, IME_FOCUS_CONTROLLER);
9962     }
9963 
9964     /**
9965      * Dump information about this ViewRootImpl
9966      * @param prefix the prefix that will be prepended to each line of the produced output
9967      * @param writer the writer that will receive the resulting text
9968      */
dump(String prefix, PrintWriter writer)9969     public void dump(String prefix, PrintWriter writer) {
9970         String innerPrefix = prefix + "  ";
9971         writer.println(prefix + "ViewRoot:");
9972         writer.println(innerPrefix + "mAdded=" + mAdded);
9973         writer.println(innerPrefix + "mRemoved=" + mRemoved);
9974         writer.println(innerPrefix + "mStopped=" + mStopped);
9975         writer.println(innerPrefix + "mPausedForTransition=" + mPausedForTransition);
9976         writer.println(innerPrefix + "mConsumeBatchedInputScheduled="
9977                 + mConsumeBatchedInputScheduled);
9978         writer.println(innerPrefix + "mConsumeBatchedInputImmediatelyScheduled="
9979                 + mConsumeBatchedInputImmediatelyScheduled);
9980         writer.println(innerPrefix + "mPendingInputEventCount=" + mPendingInputEventCount);
9981         writer.println(innerPrefix + "mProcessInputEventsScheduled="
9982                 + mProcessInputEventsScheduled);
9983         writer.println(innerPrefix + "mTraversalScheduled=" + mTraversalScheduled);
9984         if (mTraversalScheduled) {
9985             writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")");
9986         }
9987         writer.println(innerPrefix + "mReportNextDraw=" + mReportNextDraw);
9988         if (mReportNextDraw) {
9989             writer.println(innerPrefix + " (reason=" + mLastReportNextDrawReason + ")");
9990         }
9991         if (mLastPerformTraversalsSkipDrawReason != null) {
9992             writer.println(innerPrefix + "mLastPerformTraversalsFailedReason="
9993                 + mLastPerformTraversalsSkipDrawReason);
9994         }
9995         if (mLastPerformDrawSkippedReason != null) {
9996             writer.println(innerPrefix + "mLastPerformDrawFailedReason="
9997                 + mLastPerformDrawSkippedReason);
9998         }
9999         if (mWmsRequestSyncGroupState != WMS_SYNC_NONE) {
10000             writer.println(innerPrefix + "mWmsRequestSyncGroupState=" + mWmsRequestSyncGroupState);
10001         }
10002         writer.println(innerPrefix + "mLastReportedMergedConfiguration="
10003                 + mLastReportedMergedConfiguration);
10004         writer.println(innerPrefix + "mLastConfigurationFromResources="
10005                 + mLastConfigurationFromResources);
10006         if (mLastReportedActivityWindowInfo != null) {
10007             writer.println(innerPrefix + "mLastReportedActivityWindowInfo="
10008                     + mLastReportedActivityWindowInfo);
10009         }
10010         writer.println(innerPrefix + "mIsAmbientMode="  + mIsAmbientMode);
10011         writer.println(innerPrefix + "mUnbufferedInputSource="
10012                 + Integer.toHexString(mUnbufferedInputSource));
10013         if (mAttachInfo != null) {
10014             writer.print(innerPrefix + "mAttachInfo= ");
10015             mAttachInfo.dump(innerPrefix, writer);
10016         } else {
10017             writer.println(innerPrefix + "mAttachInfo=<null>");
10018         }
10019 
10020         mFirstInputStage.dump(innerPrefix, writer);
10021 
10022         if (mInputEventReceiver != null) {
10023             mInputEventReceiver.dump(innerPrefix, writer);
10024         }
10025 
10026         mChoreographer.dump(prefix, writer);
10027 
10028         mInsetsController.dump(prefix, writer);
10029 
10030         mOnBackInvokedDispatcher.dump(prefix, writer);
10031 
10032         mImeBackAnimationController.dump(prefix, writer);
10033 
10034         writer.println(prefix + "View Hierarchy:");
10035         dumpViewHierarchy(innerPrefix, writer, mView);
10036     }
10037 
dumpViewHierarchy(String prefix, PrintWriter writer, View view)10038     private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
10039         writer.print(prefix);
10040         if (view == null) {
10041             writer.println("null");
10042             return;
10043         }
10044         writer.println(view.toString());
10045         if (!(view instanceof ViewGroup)) {
10046             return;
10047         }
10048         ViewGroup grp = (ViewGroup)view;
10049         final int N = grp.getChildCount();
10050         if (N <= 0) {
10051             return;
10052         }
10053         prefix = prefix + "  ";
10054         for (int i=0; i<N; i++) {
10055             dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
10056         }
10057     }
10058 
10059     static final class GfxInfo {
10060         public int viewCount;
10061         public long renderNodeMemoryUsage;
10062         public long renderNodeMemoryAllocated;
10063 
add(GfxInfo other)10064         void add(GfxInfo other) {
10065             viewCount += other.viewCount;
10066             renderNodeMemoryUsage += other.renderNodeMemoryUsage;
10067             renderNodeMemoryAllocated += other.renderNodeMemoryAllocated;
10068         }
10069     }
10070 
getGfxInfo()10071     GfxInfo getGfxInfo() {
10072         GfxInfo info = new GfxInfo();
10073         if (mView != null) {
10074             appendGfxInfo(mView, info);
10075         }
10076         return info;
10077     }
10078 
computeRenderNodeUsage(RenderNode node, GfxInfo info)10079     private static void computeRenderNodeUsage(RenderNode node, GfxInfo info) {
10080         if (node == null) return;
10081         info.renderNodeMemoryUsage += node.computeApproximateMemoryUsage();
10082         info.renderNodeMemoryAllocated += node.computeApproximateMemoryAllocated();
10083     }
10084 
appendGfxInfo(View view, GfxInfo info)10085     private static void appendGfxInfo(View view, GfxInfo info) {
10086         info.viewCount++;
10087         computeRenderNodeUsage(view.mRenderNode, info);
10088         computeRenderNodeUsage(view.mBackgroundRenderNode, info);
10089         if (view instanceof ViewGroup) {
10090             ViewGroup group = (ViewGroup) view;
10091 
10092             int count = group.getChildCount();
10093             for (int i = 0; i < count; i++) {
10094                 appendGfxInfo(group.getChildAt(i), info);
10095             }
10096         }
10097     }
10098 
10099     /**
10100      * @param immediate True, do now if not in traversal. False, put on queue and do later.
10101      * @return True, request has been queued. False, request has been completed.
10102      */
die(boolean immediate)10103     boolean die(boolean immediate) {
10104         // Make sure we do execute immediately if we are in the middle of a traversal or the damage
10105         // done by dispatchDetachedFromWindow will cause havoc on return.
10106         if (immediate && !mIsInTraversal) {
10107             doDie();
10108             return false;
10109         }
10110 
10111         if (!com.android.graphics.hwui.flags.Flags.removeVriSketchyDestroy()) {
10112             if (!mIsDrawing) {
10113                 destroyHardwareRenderer();
10114             } else {
10115                 Log.e(mTag, "Attempting to destroy the window while drawing!\n"
10116                         + "  window=" + this + ", title=" + mWindowAttributes.getTitle());
10117             }
10118         }
10119         mHandler.sendEmptyMessage(MSG_DIE);
10120         return true;
10121     }
10122 
doDie()10123     void doDie() {
10124         checkThread();
10125         if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
10126         synchronized (this) {
10127             if (mRemoved) {
10128                 return;
10129             }
10130             mRemoved = true;
10131             mOnBackInvokedDispatcher.detachFromWindow();
10132             removeVrrMessages();
10133 
10134             if (mAdded) {
10135                 dispatchDetachedFromWindow();
10136             }
10137 
10138             destroyHardwareRenderer();
10139 
10140             if (mAdded && !mFirst) {
10141                 if (mView != null) {
10142                     int viewVisibility = mView.getVisibility();
10143                     boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
10144                     if (mWindowAttributesChanged || viewVisibilityChanged) {
10145                         // If layout params have been changed, first give them
10146                         // to the window manager to make sure it has the correct
10147                         // animation info.
10148                         try {
10149                             if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
10150                                     & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
10151                                 mWindowSession.finishDrawing(
10152                                     mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
10153                             }
10154                         } catch (RemoteException e) {
10155                         }
10156                     }
10157 
10158                     destroySurface();
10159                 }
10160             }
10161 
10162             // If our window is removed, we might not get notified about losing control.
10163             // Invoking this can release the leashes as soon as possible instead of relying on GC.
10164             mInsetsController.onControlsChanged(null);
10165 
10166             mAdded = false;
10167             AnimationHandler.removeRequestor(this);
10168         }
10169         handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
10170                 mPendingTransaction, "shutting down VRI");
10171         mHasPendingTransactions = false;
10172         WindowManagerGlobal.getInstance().doRemoveView(this);
10173     }
10174 
requestUpdateConfiguration(Configuration config)10175     public void requestUpdateConfiguration(Configuration config) {
10176         Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
10177         mHandler.sendMessage(msg);
10178     }
10179 
loadSystemProperties()10180     public void loadSystemProperties() {
10181         mHandler.post(new Runnable() {
10182             @Override
10183             public void run() {
10184                 // Profiling
10185                 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
10186                 profileRendering(mAttachInfo.mHasWindowFocus);
10187 
10188                 // Hardware rendering
10189                 if (mAttachInfo.mThreadedRenderer != null) {
10190                     if (mAttachInfo.mThreadedRenderer.loadSystemProperties()) {
10191                         invalidate();
10192                     }
10193                 }
10194 
10195                 // Layout debugging
10196                 boolean layout = DisplayProperties.debug_layout().orElse(false);
10197                 if (layout != mAttachInfo.mDebugLayout) {
10198                     mAttachInfo.mDebugLayout = layout;
10199                     if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
10200                         mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
10201                     }
10202                 }
10203             }
10204         });
10205     }
10206 
destroyHardwareRenderer()10207     private void destroyHardwareRenderer() {
10208         ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
10209 
10210         mHdrRenderState.stopListening();
10211 
10212         if (hardwareRenderer != null) {
10213             if (mHardwareRendererObserver != null) {
10214                 hardwareRenderer.removeObserver(mHardwareRendererObserver);
10215             }
10216             if (mView != null) {
10217                 hardwareRenderer.destroyHardwareResources(mView);
10218             }
10219             hardwareRenderer.destroy();
10220             hardwareRenderer.setRequested(false);
10221 
10222             mAttachInfo.mThreadedRenderer = null;
10223             mAttachInfo.mHardwareAccelerated = false;
10224             logColorMode(mCurrentColorMode, true);
10225         }
10226     }
10227 
10228     @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, @Nullable ActivityWindowInfo activityWindowInfo)10229     private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
10230             MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
10231             boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing,
10232             @Nullable ActivityWindowInfo activityWindowInfo) {
10233         Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
10234         SomeArgs args = SomeArgs.obtain();
10235         args.arg1 = frames;
10236         args.arg2 = mergedConfiguration;
10237         args.arg3 = insetsState;
10238         args.arg4 = activityWindowInfo;
10239         args.argi1 = forceLayout ? 1 : 0;
10240         args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
10241         args.argi3 = displayId;
10242         args.argi4 = syncSeqId;
10243         args.argi5 = dragResizing ? 1 : 0;
10244 
10245         msg.obj = args;
10246         mHandler.sendMessage(msg);
10247     }
10248 
dispatchInsetsControlChanged(@onNull InsetsState insetsState, @NonNull InsetsSourceControl.Array activeControls)10249     private void dispatchInsetsControlChanged(@NonNull InsetsState insetsState,
10250             @NonNull InsetsSourceControl.Array activeControls) {
10251         final SomeArgs args = SomeArgs.obtain();
10252         args.arg1 = insetsState;
10253         args.arg2 = activeControls;
10254         mHandler.obtainMessage(MSG_INSETS_CONTROL_CHANGED, args).sendToTarget();
10255     }
10256 
showInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)10257     private void showInsets(@InsetsType int types, boolean fromIme,
10258             @Nullable ImeTracker.Token statsToken) {
10259         mHandler.obtainMessage(MSG_SHOW_INSETS, types, fromIme ? 1 : 0, statsToken).sendToTarget();
10260     }
10261 
hideInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)10262     private void hideInsets(@InsetsType int types, boolean fromIme,
10263             @Nullable ImeTracker.Token statsToken) {
10264         mHandler.obtainMessage(MSG_HIDE_INSETS, types, fromIme ? 1 : 0, statsToken).sendToTarget();
10265     }
10266 
dispatchMoved(int newX, int newY)10267     public void dispatchMoved(int newX, int newY) {
10268         if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
10269         if (mTranslator != null) {
10270             PointF point = new PointF(newX, newY);
10271             mTranslator.translatePointInScreenToAppWindow(point);
10272             newX = (int) (point.x + 0.5);
10273             newY = (int) (point.y + 0.5);
10274         }
10275         Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
10276         mHandler.sendMessage(msg);
10277     }
10278 
10279     /**
10280      * Dispatches the statsToken and IME visibility to the ImeInsetsSourceProvider.
10281      *
10282      * @param visible {@code true} if it became visible, {@code false} otherwise.
10283      * @param statsToken the token tracking the current IME request.
10284      *
10285      * @hide
10286      */
notifyImeVisibilityChanged(boolean visible, @NonNull ImeTracker.Token statsToken)10287     public void notifyImeVisibilityChanged(boolean visible, @NonNull ImeTracker.Token statsToken) {
10288         ImeTracker.forLogging().onProgress(statsToken,
10289                 ImeTracker.PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED);
10290         try {
10291             mWindowSession.notifyImeWindowVisibilityChangedFromClient(mWindow, visible, statsToken);
10292         } catch (RemoteException e) {
10293             ImeTracker.forLogging().onFailed(statsToken,
10294                     ImeTracker.PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED);
10295             e.rethrowFromSystemServer();
10296         }
10297     }
10298 
10299     /**
10300      * Represents a pending input event that is waiting in a queue.
10301      *
10302      * Input events are processed in serial order by the timestamp specified by
10303      * {@link InputEvent#getEventTimeNanos()}.  In general, the input dispatcher delivers
10304      * one input event to the application at a time and waits for the application
10305      * to finish handling it before delivering the next one.
10306      *
10307      * However, because the application or IME can synthesize and inject multiple
10308      * key events at a time without going through the input dispatcher, we end up
10309      * needing a queue on the application's side.
10310      */
10311     private static final class QueuedInputEvent {
10312         public static final int FLAG_DELIVER_POST_IME = 1 << 0;
10313         public static final int FLAG_DEFERRED = 1 << 1;
10314         public static final int FLAG_FINISHED = 1 << 2;
10315         public static final int FLAG_FINISHED_HANDLED = 1 << 3;
10316         public static final int FLAG_RESYNTHESIZED = 1 << 4;
10317         public static final int FLAG_UNHANDLED = 1 << 5;
10318         public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6;
10319         public static final int FLAG_PRE_IME_ONLY = 1 << 7;
10320 
10321         public QueuedInputEvent mNext;
10322 
10323         public InputEvent mEvent;
10324         public InputEventReceiver mReceiver;
10325         public int mFlags;
10326 
forPreImeOnly()10327         public boolean forPreImeOnly() {
10328             if ((mFlags & FLAG_PRE_IME_ONLY) != 0) {
10329                 return true;
10330             }
10331             return false;
10332         }
10333 
shouldSkipIme()10334         public boolean shouldSkipIme() {
10335             if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
10336                 return true;
10337             }
10338             return mEvent instanceof MotionEvent
10339                     && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER));
10340         }
10341 
shouldSendToSynthesizer()10342         public boolean shouldSendToSynthesizer() {
10343             if ((mFlags & FLAG_UNHANDLED) != 0) {
10344                 return true;
10345             }
10346 
10347             return false;
10348         }
10349 
10350         @Override
toString()10351         public String toString() {
10352             StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
10353             boolean hasPrevious = false;
10354             hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
10355             hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
10356             hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
10357             hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
10358             hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
10359             hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
10360             hasPrevious = flagToString("FLAG_PRE_IME_ONLY", FLAG_PRE_IME_ONLY, hasPrevious, sb);
10361             if (!hasPrevious) {
10362                 sb.append("0");
10363             }
10364             sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
10365             sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
10366             sb.append(", mEvent=" + mEvent + "}");
10367             return sb.toString();
10368         }
10369 
flagToString(String name, int flag, boolean hasPrevious, StringBuilder sb)10370         private boolean flagToString(String name, int flag,
10371                 boolean hasPrevious, StringBuilder sb) {
10372             if ((mFlags & flag) != 0) {
10373                 if (hasPrevious) {
10374                     sb.append("|");
10375                 }
10376                 sb.append(name);
10377                 return true;
10378             }
10379             return hasPrevious;
10380         }
10381     }
10382 
obtainQueuedInputEvent(InputEvent event, InputEventReceiver receiver, int flags)10383     private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
10384             InputEventReceiver receiver, int flags) {
10385         QueuedInputEvent q = mQueuedInputEventPool;
10386         if (q != null) {
10387             mQueuedInputEventPoolSize -= 1;
10388             mQueuedInputEventPool = q.mNext;
10389             q.mNext = null;
10390         } else {
10391             q = new QueuedInputEvent();
10392         }
10393 
10394         q.mEvent = event;
10395         q.mReceiver = receiver;
10396         q.mFlags = flags;
10397         return q;
10398     }
10399 
recycleQueuedInputEvent(QueuedInputEvent q)10400     private void recycleQueuedInputEvent(QueuedInputEvent q) {
10401         q.mEvent = null;
10402         q.mReceiver = null;
10403 
10404         if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
10405             mQueuedInputEventPoolSize += 1;
10406             q.mNext = mQueuedInputEventPool;
10407             mQueuedInputEventPool = q;
10408         }
10409     }
10410 
10411     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
enqueueInputEvent(InputEvent event)10412     public void enqueueInputEvent(InputEvent event) {
10413         enqueueInputEvent(event, null, 0, false);
10414     }
10415 
10416     @UnsupportedAppUsage
enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately)10417     QueuedInputEvent enqueueInputEvent(InputEvent event,
10418             InputEventReceiver receiver, int flags, boolean processImmediately) {
10419         QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
10420 
10421         if (event instanceof MotionEvent) {
10422             MotionEvent me = (MotionEvent) event;
10423             if (me.getAction() == MotionEvent.ACTION_CANCEL) {
10424                 EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Motion - Cancel",
10425                         getTitle().toString());
10426             }
10427         } else if (event instanceof KeyEvent) {
10428             KeyEvent ke = (KeyEvent) event;
10429             if (ke.isCanceled()) {
10430                 EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Key - Cancel",
10431                         getTitle().toString());
10432             }
10433         }
10434         // Always enqueue the input event in order, regardless of its time stamp.
10435         // We do this because the application or the IME may inject key events
10436         // in response to touch events and we want to ensure that the injected keys
10437         // are processed in the order they were received and we cannot trust that
10438         // the time stamp of injected events are monotonic.
10439         QueuedInputEvent last = mPendingInputEventTail;
10440         if (last == null) {
10441             mPendingInputEventHead = q;
10442             mPendingInputEventTail = q;
10443         } else {
10444             last.mNext = q;
10445             mPendingInputEventTail = q;
10446         }
10447         mPendingInputEventCount += 1;
10448         Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
10449                 mPendingInputEventCount);
10450 
10451         if (processImmediately) {
10452             doProcessInputEvents();
10453         } else {
10454             scheduleProcessInputEvents();
10455         }
10456         return q;
10457     }
10458 
scheduleProcessInputEvents()10459     private void scheduleProcessInputEvents() {
10460         if (!mProcessInputEventsScheduled) {
10461             mProcessInputEventsScheduled = true;
10462             Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
10463             msg.setAsynchronous(true);
10464             mHandler.sendMessage(msg);
10465         }
10466     }
10467 
doProcessInputEvents()10468     void doProcessInputEvents() {
10469         // Deliver all pending input events in the queue.
10470         while (mPendingInputEventHead != null) {
10471             QueuedInputEvent q = mPendingInputEventHead;
10472             mPendingInputEventHead = q.mNext;
10473             if (mPendingInputEventHead == null) {
10474                 mPendingInputEventTail = null;
10475             }
10476             q.mNext = null;
10477 
10478             mPendingInputEventCount -= 1;
10479             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
10480                     mPendingInputEventCount);
10481 
10482             mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
10483 
10484             deliverInputEvent(q);
10485         }
10486 
10487         // We are done processing all input events that we can process right now
10488         // so we can clear the pending flag immediately.
10489         if (mProcessInputEventsScheduled) {
10490             mProcessInputEventsScheduled = false;
10491             mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
10492         }
10493     }
10494 
deliverInputEvent(QueuedInputEvent q)10495     private void deliverInputEvent(QueuedInputEvent q) {
10496         Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
10497                 q.mEvent.getId());
10498 
10499         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
10500             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x"
10501                     + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano="
10502                     + q.mEvent.getEventTimeNanos() + " id=0x"
10503                     + Integer.toHexString(q.mEvent.getId()));
10504         }
10505         try {
10506             if (mInputEventConsistencyVerifier != null) {
10507                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency");
10508                 try {
10509                     mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
10510                 } finally {
10511                     Trace.traceEnd(Trace.TRACE_TAG_VIEW);
10512                 }
10513             }
10514 
10515             InputStage stage;
10516             if (q.shouldSendToSynthesizer()) {
10517                 stage = mSyntheticInputStage;
10518             } else {
10519                 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
10520             }
10521 
10522             if (q.mEvent instanceof KeyEvent) {
10523                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager");
10524                 try {
10525                     mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
10526                 } finally {
10527                     Trace.traceEnd(Trace.TRACE_TAG_VIEW);
10528                 }
10529             }
10530 
10531             if (stage != null) {
10532                 handleWindowFocusChanged();
10533                 stage.deliver(q);
10534             } else {
10535                 finishInputEvent(q);
10536             }
10537         } finally {
10538             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
10539         }
10540     }
10541 
finishInputEvent(QueuedInputEvent q)10542     private void finishInputEvent(QueuedInputEvent q) {
10543         Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
10544                 q.mEvent.getId());
10545 
10546         if (q.mReceiver != null) {
10547             boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
10548             boolean modified = (q.mFlags & QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY) != 0;
10549             if (modified) {
10550                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventBeforeFinish");
10551                 InputEvent processedEvent;
10552                 try {
10553                     processedEvent =
10554                             mInputCompatProcessor.processInputEventBeforeFinish(q.mEvent);
10555                 } finally {
10556                     Trace.traceEnd(Trace.TRACE_TAG_VIEW);
10557                 }
10558                 if (processedEvent != null) {
10559                     q.mReceiver.finishInputEvent(processedEvent, handled);
10560                 }
10561             } else {
10562                 q.mReceiver.finishInputEvent(q.mEvent, handled);
10563             }
10564             if (q.mEvent instanceof KeyEvent) {
10565                 logHandledSystemKey((KeyEvent) q.mEvent, handled);
10566             }
10567         } else {
10568             q.mEvent.recycleIfNeededAfterDispatch();
10569         }
10570 
10571         recycleQueuedInputEvent(q);
10572     }
10573 
logHandledSystemKey(KeyEvent event, boolean handled)10574     private void logHandledSystemKey(KeyEvent event, boolean handled) {
10575         final int keyCode = event.getKeyCode();
10576         if (keyCode != KeyEvent.KEYCODE_STEM_PRIMARY) {
10577             return;
10578         }
10579         if (event.isDown() && event.getRepeatCount() == 0 && handled) {
10580             // Initial DOWN event is handled. Log the stem primary key press.
10581             Counter.logIncrementWithUid(
10582                     "input.value_app_handled_stem_primary_key_gestures_count",
10583                     Process.myUid());
10584         }
10585     }
10586 
isTerminalInputEvent(InputEvent event)10587     static boolean isTerminalInputEvent(InputEvent event) {
10588         if (event instanceof KeyEvent) {
10589             final KeyEvent keyEvent = (KeyEvent)event;
10590             return keyEvent.getAction() == KeyEvent.ACTION_UP;
10591         } else {
10592             final MotionEvent motionEvent = (MotionEvent)event;
10593             final int action = motionEvent.getAction();
10594             return action == MotionEvent.ACTION_UP
10595                     || action == MotionEvent.ACTION_CANCEL
10596                     || action == MotionEvent.ACTION_HOVER_EXIT;
10597         }
10598     }
10599 
scheduleConsumeBatchedInput()10600     void scheduleConsumeBatchedInput() {
10601         // If anything is currently scheduled to consume batched input then there's no point in
10602         // scheduling it again.
10603         if (!mConsumeBatchedInputScheduled && !mConsumeBatchedInputImmediatelyScheduled) {
10604             mConsumeBatchedInputScheduled = true;
10605             mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
10606                     mConsumedBatchedInputRunnable, null);
10607             if (mAttachInfo.mThreadedRenderer != null) {
10608                 mAttachInfo.mThreadedRenderer.notifyCallbackPending();
10609             }
10610         }
10611     }
10612 
unscheduleConsumeBatchedInput()10613     void unscheduleConsumeBatchedInput() {
10614         if (mConsumeBatchedInputScheduled) {
10615             mConsumeBatchedInputScheduled = false;
10616             mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
10617                     mConsumedBatchedInputRunnable, null);
10618         }
10619     }
10620 
scheduleConsumeBatchedInputImmediately()10621     void scheduleConsumeBatchedInputImmediately() {
10622         if (!mConsumeBatchedInputImmediatelyScheduled) {
10623             unscheduleConsumeBatchedInput();
10624             mConsumeBatchedInputImmediatelyScheduled = true;
10625             mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
10626         }
10627     }
10628 
doConsumeBatchedInput(long frameTimeNanos)10629     boolean doConsumeBatchedInput(long frameTimeNanos) {
10630         final boolean consumedBatches;
10631         if (mInputEventReceiver != null) {
10632             consumedBatches = mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos);
10633         } else {
10634             consumedBatches = false;
10635         }
10636         doProcessInputEvents();
10637         return consumedBatches;
10638     }
10639 
10640     final class TraversalRunnable implements Runnable {
10641         @Override
run()10642         public void run() {
10643             doTraversal();
10644         }
10645     }
10646     final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
10647 
10648     final class WindowInputEventReceiver extends InputEventReceiver {
WindowInputEventReceiver(InputChannel inputChannel, Looper looper)10649         public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
10650             super(inputChannel, looper);
10651         }
10652 
10653         @Override
onInputEvent(InputEvent event)10654         public void onInputEvent(InputEvent event) {
10655             processRawInputEvent(event);
10656         }
10657 
10658         @Override
onBatchedInputEventPending(int source)10659         public void onBatchedInputEventPending(int source) {
10660             final boolean unbuffered = mUnbufferedInputDispatch
10661                     || (source & mUnbufferedInputSource) != SOURCE_CLASS_NONE;
10662             if (unbuffered) {
10663                 if (mConsumeBatchedInputScheduled) {
10664                     unscheduleConsumeBatchedInput();
10665                 }
10666                 // Consume event immediately if unbuffered input dispatch has been requested.
10667                 consumeBatchedInputEvents(-1);
10668                 return;
10669             }
10670             scheduleConsumeBatchedInput();
10671         }
10672 
10673         @Override
onFocusEvent(boolean hasFocus)10674         public void onFocusEvent(boolean hasFocus) {
10675             windowFocusChanged(hasFocus);
10676         }
10677 
10678         @Override
onTouchModeChanged(boolean inTouchMode)10679         public void onTouchModeChanged(boolean inTouchMode) {
10680             touchModeChanged(inTouchMode);
10681         }
10682 
10683         @Override
onPointerCaptureEvent(boolean pointerCaptureEnabled)10684         public void onPointerCaptureEvent(boolean pointerCaptureEnabled) {
10685             dispatchPointerCaptureChanged(pointerCaptureEnabled);
10686         }
10687 
10688         @Override
onDragEvent(boolean isExiting, float x, float y, int displayId)10689         public void onDragEvent(boolean isExiting, float x, float y, int displayId) {
10690             // force DRAG_EXITED_EVENT if appropriate
10691             DragEvent event = DragEvent.obtain(
10692                     isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION, x, y,
10693                     0 /* offsetX */, 0 /* offsetY */, displayId, 0 /* flags */,
10694                     null/* localState */, null/* description */, null /* data */,
10695                     null /* dragSurface */, null /* dragAndDropPermissions */, false /* result */);
10696             dispatchDragEvent(event);
10697         }
10698 
10699         @Override
dispose()10700         public void dispose() {
10701             unscheduleConsumeBatchedInput();
10702             super.dispose();
10703         }
10704     }
10705     private WindowInputEventReceiver mInputEventReceiver;
10706 
10707     final class InputMetricsListener
10708             implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
10709         public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT];
10710 
10711         @Override
onFrameMetricsAvailable(int dropCountSinceLastInvocation)10712         public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
10713             final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID];
10714             if (inputEventId == INVALID_INPUT_EVENT_ID) {
10715                 return;
10716             }
10717             final long presentTime = data[FrameMetrics.Index.DISPLAY_PRESENT_TIME];
10718             if (presentTime <= 0) {
10719                 // Present time is not available for this frame. If the present time is not
10720                 // available, we cannot compute end-to-end input latency metrics.
10721                 return;
10722             }
10723             final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED];
10724             if (mInputEventReceiver == null) {
10725                 return;
10726             }
10727             if (gpuCompletedTime >= presentTime) {
10728                 final double discrepancyMs = (gpuCompletedTime - presentTime) * 1E-6;
10729                 final long vsyncId = data[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID];
10730                 Log.w(TAG, "Not reporting timeline because gpuCompletedTime is " + discrepancyMs
10731                         + "ms ahead of presentTime. FRAME_TIMELINE_VSYNC_ID=" + vsyncId
10732                         + ", INPUT_EVENT_ID=" + inputEventId);
10733                 // TODO(b/186664409): figure out why this sometimes happens
10734                 return;
10735             }
10736             mInputEventReceiver.reportTimeline(inputEventId, gpuCompletedTime, presentTime);
10737         }
10738     }
10739     HardwareRendererObserver mHardwareRendererObserver;
10740 
10741     final class ConsumeBatchedInputRunnable implements Runnable {
10742         @Override
run()10743         public void run() {
10744             Trace.traceBegin(TRACE_TAG_VIEW, mTag);
10745             try {
10746                 mConsumeBatchedInputScheduled = false;
10747                 if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) {
10748                     // If we consumed a batch here, we want to go ahead and schedule the
10749                     // consumption of batched input events on the next frame. Otherwise, we would
10750                     // wait until we have more input events pending and might get starved by other
10751                     // things occurring in the process.
10752                     scheduleConsumeBatchedInput();
10753                 }
10754             } finally {
10755                 Trace.traceEnd(TRACE_TAG_VIEW);
10756             }
10757         }
10758     }
10759     final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
10760             new ConsumeBatchedInputRunnable();
10761     boolean mConsumeBatchedInputScheduled;
10762 
10763     final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
10764         @Override
run()10765         public void run() {
10766             mConsumeBatchedInputImmediatelyScheduled = false;
10767             doConsumeBatchedInput(-1);
10768         }
10769     }
10770     final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
10771             new ConsumeBatchedInputImmediatelyRunnable();
10772     boolean mConsumeBatchedInputImmediatelyScheduled;
10773 
10774     final class InvalidateOnAnimationRunnable implements Runnable {
10775         private boolean mPosted;
10776         private final ArrayList<View> mViews = new ArrayList<View>();
10777         private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
10778                 new ArrayList<AttachInfo.InvalidateInfo>();
10779         private View[] mTempViews;
10780         private AttachInfo.InvalidateInfo[] mTempViewRects;
10781 
addView(View view)10782         public void addView(View view) {
10783             synchronized (this) {
10784                 mViews.add(view);
10785                 postIfNeededLocked();
10786             }
10787             if (mAttachInfo.mThreadedRenderer != null) {
10788                 mAttachInfo.mThreadedRenderer.notifyCallbackPending();
10789             }
10790         }
10791 
addViewRect(AttachInfo.InvalidateInfo info)10792         public void addViewRect(AttachInfo.InvalidateInfo info) {
10793             synchronized (this) {
10794                 mViewRects.add(info);
10795                 postIfNeededLocked();
10796             }
10797             if (mAttachInfo.mThreadedRenderer != null) {
10798                 mAttachInfo.mThreadedRenderer.notifyCallbackPending();
10799             }
10800         }
10801 
removeView(View view)10802         public void removeView(View view) {
10803             synchronized (this) {
10804                 mViews.remove(view);
10805 
10806                 for (int i = mViewRects.size(); i-- > 0; ) {
10807                     AttachInfo.InvalidateInfo info = mViewRects.get(i);
10808                     if (info.target == view) {
10809                         mViewRects.remove(i);
10810                         info.recycle();
10811                     }
10812                 }
10813 
10814                 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
10815                     mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
10816                     mPosted = false;
10817                 }
10818             }
10819         }
10820 
10821         @Override
run()10822         public void run() {
10823             final int viewCount;
10824             final int viewRectCount;
10825             synchronized (this) {
10826                 mPosted = false;
10827 
10828                 viewCount = mViews.size();
10829                 if (viewCount != 0) {
10830                     mTempViews = mViews.toArray(mTempViews != null
10831                             ? mTempViews : new View[viewCount]);
10832                     mViews.clear();
10833                 }
10834 
10835                 viewRectCount = mViewRects.size();
10836                 if (viewRectCount != 0) {
10837                     mTempViewRects = mViewRects.toArray(mTempViewRects != null
10838                             ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
10839                     mViewRects.clear();
10840                 }
10841             }
10842 
10843             for (int i = 0; i < viewCount; i++) {
10844                 mTempViews[i].invalidate();
10845                 mTempViews[i] = null;
10846             }
10847 
10848             for (int i = 0; i < viewRectCount; i++) {
10849                 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
10850                 info.target.invalidate(info.left, info.top, info.right, info.bottom);
10851                 info.recycle();
10852             }
10853         }
10854 
postIfNeededLocked()10855         private void postIfNeededLocked() {
10856             if (!mPosted) {
10857                 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
10858                 mPosted = true;
10859             }
10860         }
10861     }
10862     final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
10863             new InvalidateOnAnimationRunnable();
10864 
10865     /**
10866      * Handle the incoming event.
10867      *
10868      * <p>The event will be first sent to the compatibility processor, which could choose to handle
10869      * it. The compat processor could also choose to produce more synthetic events in response to
10870      * the incoming one. Events that are not consumed by the compat processor are added to the
10871      * {@link ViewRootImpl}'s queue for further processing inside ViewRootImpl.
10872      *
10873      * @hide
10874      */
10875     @VisibleForTesting
processRawInputEvent(InputEvent event)10876     public void processRawInputEvent(InputEvent event) {
10877         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
10878         List<InputEvent> processedEvents;
10879         try {
10880             processedEvents =
10881                     mInputCompatProcessor.processInputEventForCompatibility(event);
10882         } finally {
10883             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
10884         }
10885         if (processedEvents != null) {
10886             if (processedEvents.isEmpty()) {
10887                 // InputEvent consumed by mInputCompatProcessor
10888                 mInputEventReceiver.finishInputEvent(event, true);
10889             } else {
10890                 for (int i = 0; i < processedEvents.size(); i++) {
10891                     enqueueInputEvent(
10892                             processedEvents.get(i), mInputEventReceiver,
10893                             QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
10894                 }
10895             }
10896         } else {
10897             enqueueInputEvent(event, mInputEventReceiver, 0, true);
10898         }
10899     }
10900 
dispatchInvalidateDelayed(View view, long delayMilliseconds)10901     public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
10902         Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
10903         mHandler.sendMessageDelayed(msg, delayMilliseconds);
10904     }
10905 
dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, long delayMilliseconds)10906     public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
10907             long delayMilliseconds) {
10908         final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
10909         mHandler.sendMessageDelayed(msg, delayMilliseconds);
10910     }
10911 
dispatchInvalidateOnAnimation(View view)10912     public void dispatchInvalidateOnAnimation(View view) {
10913         mInvalidateOnAnimationRunnable.addView(view);
10914     }
10915 
dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info)10916     public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
10917         mInvalidateOnAnimationRunnable.addViewRect(info);
10918     }
10919 
10920     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
cancelInvalidate(View view)10921     public void cancelInvalidate(View view) {
10922         mHandler.removeMessages(MSG_INVALIDATE, view);
10923         // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
10924         // them to the pool
10925         mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
10926         mInvalidateOnAnimationRunnable.removeView(view);
10927     }
10928 
10929     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
dispatchInputEvent(InputEvent event)10930     public void dispatchInputEvent(InputEvent event) {
10931         dispatchInputEvent(event, null);
10932     }
10933 
10934     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
dispatchInputEvent(InputEvent event, InputEventReceiver receiver)10935     public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
10936         SomeArgs args = SomeArgs.obtain();
10937         args.arg1 = event;
10938         args.arg2 = receiver;
10939         Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
10940         msg.setAsynchronous(true);
10941         mHandler.sendMessage(msg);
10942     }
10943 
synthesizeInputEvent(InputEvent event)10944     public void synthesizeInputEvent(InputEvent event) {
10945         Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
10946         msg.setAsynchronous(true);
10947         mHandler.sendMessage(msg);
10948     }
10949 
10950     @UnsupportedAppUsage
dispatchKeyFromIme(KeyEvent event)10951     public void dispatchKeyFromIme(KeyEvent event) {
10952         Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
10953         msg.setAsynchronous(true);
10954         mHandler.sendMessage(msg);
10955     }
10956 
dispatchKeyFromAutofill(KeyEvent event)10957     public void dispatchKeyFromAutofill(KeyEvent event) {
10958         Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event);
10959         msg.setAsynchronous(true);
10960         mHandler.sendMessage(msg);
10961     }
10962 
10963     /**
10964      * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
10965      *
10966      * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
10967      * passes in.
10968      */
10969     @UnsupportedAppUsage
dispatchUnhandledInputEvent(InputEvent event)10970     public void dispatchUnhandledInputEvent(InputEvent event) {
10971         if (event instanceof MotionEvent) {
10972             event = MotionEvent.obtain((MotionEvent) event);
10973         }
10974         synthesizeInputEvent(event);
10975     }
10976 
dispatchAppVisibility(boolean visible)10977     public void dispatchAppVisibility(boolean visible) {
10978         Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
10979         msg.arg1 = visible ? 1 : 0;
10980         mHandler.sendMessage(msg);
10981     }
10982 
dispatchGetNewSurface()10983     public void dispatchGetNewSurface() {
10984         Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
10985         mHandler.sendMessage(msg);
10986     }
10987 
10988     /**
10989      * Notifies this {@link ViewRootImpl} object that window focus has changed.
10990      */
windowFocusChanged(boolean hasFocus)10991     public void windowFocusChanged(boolean hasFocus) {
10992         synchronized (this) {
10993             mWindowFocusChanged = true;
10994             mUpcomingWindowFocus = hasFocus;
10995         }
10996         Message msg = Message.obtain();
10997         msg.what = MSG_WINDOW_FOCUS_CHANGED;
10998         mHandler.sendMessage(msg);
10999     }
11000 
11001     /**
11002      * Notifies this {@link ViewRootImpl} object that touch mode state has changed.
11003      */
touchModeChanged(boolean inTouchMode)11004     public void touchModeChanged(boolean inTouchMode) {
11005         synchronized (this) {
11006             mUpcomingInTouchMode = inTouchMode;
11007         }
11008         Message msg = Message.obtain();
11009         msg.what = MSG_WINDOW_TOUCH_MODE_CHANGED;
11010         mHandler.sendMessage(msg);
11011     }
11012 
dispatchWindowShown()11013     public void dispatchWindowShown() {
11014         mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
11015     }
11016 
dispatchCloseSystemDialogs(String reason)11017     public void dispatchCloseSystemDialogs(String reason) {
11018         Message msg = Message.obtain();
11019         msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
11020         msg.obj = reason;
11021         mHandler.sendMessage(msg);
11022     }
11023 
dispatchDragEvent(DragEvent event)11024     public void dispatchDragEvent(DragEvent event) {
11025         final int what;
11026         if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
11027             what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
11028             mHandler.removeMessages(what);
11029         } else {
11030             what = MSG_DISPATCH_DRAG_EVENT;
11031         }
11032         Message msg = mHandler.obtainMessage(what, event);
11033         mHandler.sendMessage(msg);
11034     }
11035 
dispatchCheckFocus()11036     public void dispatchCheckFocus() {
11037         if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
11038             // This will result in a call to checkFocus() below.
11039             mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
11040         }
11041     }
11042 
dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)11043     public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
11044         mHandler.obtainMessage(
11045                 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
11046     }
11047 
dispatchPointerCaptureChanged(boolean on)11048     private void dispatchPointerCaptureChanged(boolean on) {
11049         final int what = MSG_POINTER_CAPTURE_CHANGED;
11050         mHandler.removeMessages(what);
11051         Message msg = mHandler.obtainMessage(what);
11052         msg.arg1 = on ? 1 : 0;
11053         mHandler.sendMessage(msg);
11054     }
11055 
11056     /**
11057      * Post a callback to send a
11058      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
11059      * This event is send at most once every
11060      * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
11061      */
postSendWindowContentChangedCallback(View source, int changeType)11062     private void postSendWindowContentChangedCallback(View source, int changeType) {
11063         if (mSendWindowContentChangedAccessibilityEvent == null) {
11064             mSendWindowContentChangedAccessibilityEvent =
11065                 new SendWindowContentChangedAccessibilityEvent();
11066         }
11067         mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
11068     }
11069 
11070     /**
11071      * Remove a posted callback to send a
11072      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
11073      */
removeSendWindowContentChangedCallback()11074     private void removeSendWindowContentChangedCallback() {
11075         if (mSendWindowContentChangedAccessibilityEvent != null) {
11076             mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
11077         }
11078     }
11079 
11080     /**
11081      * Return the connection ID for the {@link AccessibilityInteractionController} of this instance.
11082      * @see AccessibilityNodeInfo#setQueryFromAppProcessEnabled
11083      */
getDirectAccessibilityConnectionId()11084     public int getDirectAccessibilityConnectionId() {
11085         return mAccessibilityInteractionConnectionManager.ensureDirectConnection();
11086     }
11087 
11088     @Override
showContextMenuForChild(View originalView)11089     public boolean showContextMenuForChild(View originalView) {
11090         return false;
11091     }
11092 
11093     @Override
showContextMenuForChild(View originalView, float x, float y)11094     public boolean showContextMenuForChild(View originalView, float x, float y) {
11095         return false;
11096     }
11097 
11098     @Override
startActionModeForChild(View originalView, ActionMode.Callback callback)11099     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
11100         return null;
11101     }
11102 
11103     @Override
startActionModeForChild( View originalView, ActionMode.Callback callback, int type)11104     public ActionMode startActionModeForChild(
11105             View originalView, ActionMode.Callback callback, int type) {
11106         return null;
11107     }
11108 
11109     @Override
createContextMenu(ContextMenu menu)11110     public void createContextMenu(ContextMenu menu) {
11111     }
11112 
11113     @Override
childDrawableStateChanged(View child)11114     public void childDrawableStateChanged(View child) {
11115     }
11116 
11117     @Override
requestSendAccessibilityEvent(View child, AccessibilityEvent event)11118     public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
11119         if (mView == null || mStopped || mPausedForTransition) {
11120             return false;
11121         }
11122 
11123         // Immediately flush pending content changed event (if any) to preserve event order
11124         if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
11125                 && mSendWindowContentChangedAccessibilityEvent != null
11126                 && mSendWindowContentChangedAccessibilityEvent.mSource != null) {
11127             mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun();
11128         }
11129 
11130         // Intercept accessibility focus events fired by virtual nodes to keep
11131         // track of accessibility focus position in such nodes.
11132         final int eventType = event.getEventType();
11133         final View source = getSourceForAccessibilityEvent(event);
11134         switch (eventType) {
11135             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
11136                 if (source != null) {
11137                     AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
11138                     if (provider != null) {
11139                         final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
11140                                 event.getSourceNodeId());
11141                         final AccessibilityNodeInfo node;
11142                         node = provider.createAccessibilityNodeInfo(virtualNodeId);
11143                         setAccessibilityFocus(source, node);
11144                     }
11145                 }
11146             } break;
11147             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
11148                 if (source != null && source.getAccessibilityNodeProvider() != null) {
11149                     setAccessibilityFocus(null, null);
11150                 }
11151             } break;
11152 
11153 
11154             case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
11155                 handleWindowContentChangedEvent(event);
11156             } break;
11157         }
11158         mAccessibilityManager.sendAccessibilityEvent(event);
11159         return true;
11160     }
11161 
getSourceForAccessibilityEvent(AccessibilityEvent event)11162     private View getSourceForAccessibilityEvent(AccessibilityEvent event) {
11163         final long sourceNodeId = event.getSourceNodeId();
11164         final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
11165                 sourceNodeId);
11166         return AccessibilityNodeIdManager.getInstance().findView(accessibilityViewId);
11167     }
11168 
isAccessibilityFocusDirty()11169     private boolean isAccessibilityFocusDirty() {
11170         final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
11171         if (drawable != null) {
11172             final Rect bounds = mAttachInfo.mTmpInvalRect;
11173             final boolean hasFocus = getAccessibilityFocusedRect(bounds);
11174             if (!hasFocus) {
11175                 bounds.setEmpty();
11176             }
11177             if (!bounds.equals(drawable.getBounds())) {
11178                 return true;
11179             }
11180         }
11181         return false;
11182     }
11183 
11184     /**
11185      * Updates the focused virtual view, when necessary, in response to a
11186      * content changed event.
11187      * <p>
11188      * This is necessary to get updated bounds after a position change.
11189      *
11190      * @param event an accessibility event of type
11191      *              {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
11192      */
handleWindowContentChangedEvent(AccessibilityEvent event)11193     private void handleWindowContentChangedEvent(AccessibilityEvent event) {
11194         final View focusedHost = mAccessibilityFocusedHost;
11195         if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
11196             // No virtual view focused, nothing to do here.
11197             return;
11198         }
11199 
11200         final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
11201         if (provider == null) {
11202             // Error state: virtual view with no provider. Clear focus.
11203             mAccessibilityFocusedHost = null;
11204             mAccessibilityFocusedVirtualView = null;
11205             focusedHost.clearAccessibilityFocusNoCallbacks(0);
11206             return;
11207         }
11208 
11209         // We only care about change types that may affect the bounds of the
11210         // focused virtual view.
11211         final int changes = event.getContentChangeTypes();
11212         if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
11213                 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
11214             return;
11215         }
11216 
11217         final long eventSourceNodeId = event.getSourceNodeId();
11218         final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
11219 
11220         // Search up the tree for subtree containment.
11221         boolean hostInSubtree = false;
11222         View root = mAccessibilityFocusedHost;
11223         while (root != null && !hostInSubtree) {
11224             if (changedViewId == root.getAccessibilityViewId()) {
11225                 hostInSubtree = true;
11226             } else {
11227                 final ViewParent parent = root.getParent();
11228                 if (parent instanceof View) {
11229                     root = (View) parent;
11230                 } else {
11231                     root = null;
11232                 }
11233             }
11234         }
11235 
11236         // We care only about changes in subtrees containing the host view.
11237         if (!hostInSubtree) {
11238             return;
11239         }
11240 
11241         final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
11242         int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
11243 
11244         // Refresh the node for the focused virtual view.
11245         final Rect oldBounds = mTempRect;
11246         mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
11247         mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
11248         if (mAccessibilityFocusedVirtualView == null) {
11249             // Error state: The node no longer exists. Clear focus.
11250             mAccessibilityFocusedHost = null;
11251             focusedHost.clearAccessibilityFocusNoCallbacks(0);
11252 
11253             // This will probably fail, but try to keep the provider's internal
11254             // state consistent by clearing focus.
11255             provider.performAction(focusedChildId,
11256                     AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
11257             invalidateRectOnScreen(oldBounds);
11258         } else {
11259             // The node was refreshed, invalidate bounds if necessary.
11260             final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
11261             if (!oldBounds.equals(newBounds)) {
11262                 oldBounds.union(newBounds);
11263                 invalidateRectOnScreen(oldBounds);
11264             }
11265         }
11266     }
11267 
11268     @Override
notifySubtreeAccessibilityStateChanged(View child, View source, int changeType)11269     public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
11270         postSendWindowContentChangedCallback(Objects.requireNonNull(source), changeType);
11271     }
11272 
11273     @Override
canResolveLayoutDirection()11274     public boolean canResolveLayoutDirection() {
11275         return true;
11276     }
11277 
11278     @Override
isLayoutDirectionResolved()11279     public boolean isLayoutDirectionResolved() {
11280         return true;
11281     }
11282 
11283     @Override
getLayoutDirection()11284     public int getLayoutDirection() {
11285         return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
11286     }
11287 
11288     @Override
canResolveTextDirection()11289     public boolean canResolveTextDirection() {
11290         return true;
11291     }
11292 
11293     @Override
isTextDirectionResolved()11294     public boolean isTextDirectionResolved() {
11295         return true;
11296     }
11297 
11298     @Override
getTextDirection()11299     public int getTextDirection() {
11300         return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
11301     }
11302 
11303     @Override
canResolveTextAlignment()11304     public boolean canResolveTextAlignment() {
11305         return true;
11306     }
11307 
11308     @Override
isTextAlignmentResolved()11309     public boolean isTextAlignmentResolved() {
11310         return true;
11311     }
11312 
11313     @Override
getTextAlignment()11314     public int getTextAlignment() {
11315         return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
11316     }
11317 
getCommonPredecessor(View first, View second)11318     private View getCommonPredecessor(View first, View second) {
11319         if (mTempHashSet == null) {
11320             mTempHashSet = new HashSet<View>();
11321         }
11322         HashSet<View> seen = mTempHashSet;
11323         seen.clear();
11324         View firstCurrent = first;
11325         while (firstCurrent != null) {
11326             seen.add(firstCurrent);
11327             ViewParent firstCurrentParent = firstCurrent.mParent;
11328             if (firstCurrentParent instanceof View) {
11329                 firstCurrent = (View) firstCurrentParent;
11330             } else {
11331                 firstCurrent = null;
11332             }
11333         }
11334         View secondCurrent = second;
11335         while (secondCurrent != null) {
11336             if (seen.contains(secondCurrent)) {
11337                 seen.clear();
11338                 return secondCurrent;
11339             }
11340             ViewParent secondCurrentParent = secondCurrent.mParent;
11341             if (secondCurrentParent instanceof View) {
11342                 secondCurrent = (View) secondCurrentParent;
11343             } else {
11344                 secondCurrent = null;
11345             }
11346         }
11347         seen.clear();
11348         return null;
11349     }
11350 
checkThread()11351     void checkThread() {
11352         Thread current = Thread.currentThread();
11353         if (mThread != current) {
11354             throw new CalledFromWrongThreadException(
11355                     "Only the original thread that created a view hierarchy can touch its views."
11356                             + " Expected: " + mThread.getName()
11357                             + " Calling: " + current.getName());
11358         }
11359     }
11360 
11361     @Override
requestDisallowInterceptTouchEvent(boolean disallowIntercept)11362     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
11363         // ViewAncestor never intercepts touch event, so this can be a no-op
11364     }
11365 
11366     @Override
requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)11367     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
11368         if (rectangle == null) {
11369             return scrollToRectOrFocus(null, immediate);
11370         }
11371         rectangle.offset(child.getLeft() - child.getScrollX(),
11372                 child.getTop() - child.getScrollY());
11373         final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
11374         mTempRect.set(rectangle);
11375         mTempRect.offset(0, -mCurScrollY);
11376         mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
11377         try {
11378             mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
11379         } catch (RemoteException re) {
11380             /* ignore */
11381         }
11382         return scrolled;
11383     }
11384 
11385     @Override
childHasTransientStateChanged(View child, boolean hasTransientState)11386     public void childHasTransientStateChanged(View child, boolean hasTransientState) {
11387         // Do nothing.
11388     }
11389 
11390     @Override
onStartNestedScroll(View child, View target, int nestedScrollAxes)11391     public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
11392         return false;
11393     }
11394 
11395     @Override
onStopNestedScroll(View target)11396     public void onStopNestedScroll(View target) {
11397     }
11398 
11399     @Override
onNestedScrollAccepted(View child, View target, int nestedScrollAxes)11400     public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
11401     }
11402 
11403     @Override
onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)11404     public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
11405             int dxUnconsumed, int dyUnconsumed) {
11406     }
11407 
11408     @Override
onNestedPreScroll(View target, int dx, int dy, int[] consumed)11409     public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
11410     }
11411 
11412     @Override
onNestedFling(View target, float velocityX, float velocityY, boolean consumed)11413     public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
11414         return false;
11415     }
11416 
11417     @Override
onNestedPreFling(View target, float velocityX, float velocityY)11418     public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
11419         return false;
11420     }
11421 
11422     @Override
onNestedPrePerformAccessibilityAction(View target, int action, Bundle args)11423     public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
11424         return false;
11425     }
11426 
11427     /**
11428      * Checks the input event receiver for input availability.
11429      * May return false negatives.
11430      * @hide
11431      */
probablyHasInput()11432     public boolean probablyHasInput() {
11433         if (mInputEventReceiver == null) {
11434             return false;
11435         }
11436         return mInputEventReceiver.probablyHasInput();
11437     }
11438 
11439     /**
11440      * Adds a scroll capture callback to this window.
11441      *
11442      * @param callback the callback to add
11443      */
addScrollCaptureCallback(ScrollCaptureCallback callback)11444     public void addScrollCaptureCallback(ScrollCaptureCallback callback) {
11445         if (mRootScrollCaptureCallbacks == null) {
11446             mRootScrollCaptureCallbacks = new HashSet<>();
11447         }
11448         mRootScrollCaptureCallbacks.add(callback);
11449     }
11450 
11451     /**
11452      * Removes a scroll capture callback from this window.
11453      *
11454      * @param callback the callback to remove
11455      */
removeScrollCaptureCallback(ScrollCaptureCallback callback)11456     public void removeScrollCaptureCallback(ScrollCaptureCallback callback) {
11457         if (mRootScrollCaptureCallbacks != null) {
11458             mRootScrollCaptureCallbacks.remove(callback);
11459             if (mRootScrollCaptureCallbacks.isEmpty()) {
11460                 mRootScrollCaptureCallbacks = null;
11461             }
11462         }
11463     }
11464 
11465     /**
11466      * Dispatches a scroll capture request to the view hierarchy on the ui thread.
11467      *
11468      * @param listener for the response
11469      */
dispatchScrollCaptureRequest(@onNull IScrollCaptureResponseListener listener)11470     public void dispatchScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) {
11471         mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, listener).sendToTarget();
11472     }
11473 
11474     /**
11475      * Collect and include any ScrollCaptureCallback instances registered with the window.
11476      *
11477      * @see #addScrollCaptureCallback(ScrollCaptureCallback)
11478      * @param results an object to collect the results of the search
11479      */
collectRootScrollCaptureTargets(ScrollCaptureSearchResults results)11480     private void collectRootScrollCaptureTargets(ScrollCaptureSearchResults results) {
11481         if (mRootScrollCaptureCallbacks == null) {
11482             return;
11483         }
11484         for (ScrollCaptureCallback cb : mRootScrollCaptureCallbacks) {
11485             // Add to the list for consideration
11486             Point offset = new Point(mView.getLeft(), mView.getTop());
11487             Rect rect = new Rect(0, 0, mView.getWidth(), mView.getHeight());
11488             results.addTarget(new ScrollCaptureTarget(mView, rect, offset, cb));
11489         }
11490     }
11491 
11492     /**
11493      * Update the timeout for scroll capture requests. Only affects this view root.
11494      * The default value is {@link #SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS}.
11495      *
11496      * @param timeMillis the new timeout in milliseconds
11497      */
setScrollCaptureRequestTimeout(int timeMillis)11498     public void setScrollCaptureRequestTimeout(int timeMillis) {
11499         mScrollCaptureRequestTimeout = timeMillis;
11500     }
11501 
11502     /**
11503      * Get the current timeout for scroll capture requests.
11504      *
11505      * @return the timeout in milliseconds
11506      */
getScrollCaptureRequestTimeout()11507     public long getScrollCaptureRequestTimeout() {
11508         return mScrollCaptureRequestTimeout;
11509     }
11510 
11511     /**
11512      * Handles an inbound request for scroll capture from the system. A search will be
11513      * dispatched through the view tree to locate scrolling content.
11514      * <p>
11515      * A call to
11516      * {@link IScrollCaptureResponseListener#onScrollCaptureResponse} will follow.
11517      *
11518      * @param listener to receive responses
11519      * @see ScrollCaptureSearchResults
11520      */
handleScrollCaptureRequest(@onNull IScrollCaptureResponseListener listener)11521     public void handleScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) {
11522         ScrollCaptureSearchResults results =
11523                 new ScrollCaptureSearchResults(mContext.getMainExecutor());
11524 
11525         // Window (root) level callbacks
11526         collectRootScrollCaptureTargets(results);
11527 
11528         // Search through View-tree
11529         View rootView = getView();
11530         if (rootView == null) {
11531             ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
11532             response.setWindowTitle(getTitle().toString());
11533             response.setPackageName(mContext.getPackageName());
11534             response.setDescription("The root view was null");
11535             try {
11536                 listener.onScrollCaptureResponse(response.build());
11537             } catch (RemoteException e) {
11538                 Log.e(TAG, "Failed to send scroll capture search result", e);
11539             }
11540             return;
11541         }
11542 
11543         Point point = new Point();
11544         Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight());
11545         getChildVisibleRect(rootView, rect, point);
11546         rootView.dispatchScrollCaptureSearch(rect, point, results::addTarget);
11547 
11548         Runnable onComplete = () -> dispatchScrollCaptureSearchResponse(listener, results);
11549         results.setOnCompleteListener(onComplete);
11550         if (!results.isComplete()) {
11551             mHandler.postDelayed(results::finish, getScrollCaptureRequestTimeout());
11552         }
11553     }
11554 
11555     /** Called by {@link #handleScrollCaptureRequest} when a result is returned */
dispatchScrollCaptureSearchResponse( @onNull IScrollCaptureResponseListener listener, @NonNull ScrollCaptureSearchResults results)11556     private void dispatchScrollCaptureSearchResponse(
11557             @NonNull IScrollCaptureResponseListener listener,
11558             @NonNull ScrollCaptureSearchResults results) {
11559 
11560         ScrollCaptureTarget selectedTarget = results.getTopResult();
11561 
11562         ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
11563         response.setWindowTitle(getTitle().toString());
11564         response.setPackageName(mContext.getPackageName());
11565 
11566         StringWriter writer =  new StringWriter();
11567         IndentingPrintWriter pw = new IndentingPrintWriter(writer);
11568         results.dump(pw);
11569         pw.flush();
11570         response.addMessage(writer.toString());
11571 
11572         if (mView == null) {
11573             response.setDescription("The root view disappeared!");
11574             try {
11575                 listener.onScrollCaptureResponse(response.build());
11576             } catch (RemoteException e) {
11577                 Log.e(TAG, "Failed to send scroll capture search result", e);
11578             }
11579             return;
11580         }
11581 
11582         if (selectedTarget == null) {
11583             response.setDescription("No scrollable targets found in window");
11584             try {
11585                 listener.onScrollCaptureResponse(response.build());
11586             } catch (RemoteException e) {
11587                 Log.e(TAG, "Failed to send scroll capture search result", e);
11588             }
11589             return;
11590         }
11591 
11592         response.setDescription("Connected");
11593 
11594         // Compute area covered by scrolling content within window
11595         Rect boundsInWindow = new Rect();
11596         View containingView = selectedTarget.getContainingView();
11597         containingView.getLocationInWindow(mAttachInfo.mTmpLocation);
11598         boundsInWindow.set(selectedTarget.getScrollBounds());
11599         boundsInWindow.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]);
11600         response.setBoundsInWindow(boundsInWindow);
11601 
11602         // Compute the area on screen covered by the window
11603         Rect boundsOnScreen = new Rect();
11604         mView.getLocationOnScreen(mAttachInfo.mTmpLocation);
11605         boundsOnScreen.set(0, 0, mView.getWidth(), mView.getHeight());
11606         boundsOnScreen.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]);
11607         response.setWindowBounds(boundsOnScreen);
11608         Log.d(TAG, "ScrollCaptureSearchResponse: " + response);
11609 
11610         // Create a connection and return it to the caller
11611         ScrollCaptureConnection connection = new ScrollCaptureConnection(
11612                 mView.getContext().getMainExecutor(), selectedTarget);
11613         response.setConnection(connection);
11614 
11615         try {
11616             listener.onScrollCaptureResponse(response.build());
11617         } catch (RemoteException e) {
11618             if (DEBUG_SCROLL_CAPTURE) {
11619                 Log.w(TAG, "Failed to send scroll capture search response.", e);
11620             }
11621             connection.close();
11622         }
11623     }
11624 
reportNextDraw(String reason)11625     private void reportNextDraw(String reason) {
11626         if (DEBUG_BLAST) {
11627             Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
11628         }
11629         mReportNextDraw = true;
11630         mLastReportNextDrawReason = reason;
11631     }
11632 
11633     /**
11634      * Force the window to report its next draw.
11635      * <p>
11636      * This method is only supposed to be used to speed up the interaction from SystemUI and window
11637      * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
11638      * unless you fully understand this interaction.
11639      *
11640      * @param syncBuffer If true, the transaction that contains the buffer from the draw should be
11641      *                   sent to system to be synced. If false, VRI will not try to sync the buffer,
11642      *                   but only report back that a buffer was drawn.
11643      * @param reason A debug string indicating the reason for reporting the next draw
11644      * @hide
11645      */
setReportNextDraw(boolean syncBuffer, String reason)11646     public void setReportNextDraw(boolean syncBuffer, String reason) {
11647         mSyncBuffer = syncBuffer;
11648         reportNextDraw(reason);
11649         invalidate();
11650     }
11651 
changeCanvasOpacity(boolean opaque)11652     void changeCanvasOpacity(boolean opaque) {
11653         Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
11654         opaque = opaque & ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0);
11655         if (mAttachInfo.mThreadedRenderer != null) {
11656             mAttachInfo.mThreadedRenderer.setOpaque(opaque);
11657         }
11658     }
11659 
11660     /**
11661      * Dispatches a KeyEvent to all registered key fallback handlers.
11662      *
11663      * @param event
11664      * @return {@code true} if the event was handled, {@code false} otherwise.
11665      */
dispatchUnhandledKeyEvent(KeyEvent event)11666     public boolean dispatchUnhandledKeyEvent(KeyEvent event) {
11667         return mUnhandledKeyManager.dispatch(mView, event);
11668     }
11669 
11670     class TakenSurfaceHolder extends BaseSurfaceHolder {
11671         @Override
onAllowLockCanvas()11672         public boolean onAllowLockCanvas() {
11673             return mDrawingAllowed;
11674         }
11675 
11676         @Override
onRelayoutContainer()11677         public void onRelayoutContainer() {
11678             // Not currently interesting -- from changing between fixed and layout size.
11679         }
11680 
11681         @Override
setFormat(int format)11682         public void setFormat(int format) {
11683             ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
11684         }
11685 
11686         @Override
setType(int type)11687         public void setType(int type) {
11688             ((RootViewSurfaceTaker)mView).setSurfaceType(type);
11689         }
11690 
11691         @Override
onUpdateSurface()11692         public void onUpdateSurface() {
11693             // We take care of format and type changes on our own.
11694             throw new IllegalStateException("Shouldn't be here");
11695         }
11696 
11697         @Override
isCreating()11698         public boolean isCreating() {
11699             return mIsCreating;
11700         }
11701 
11702         @Override
setFixedSize(int width, int height)11703         public void setFixedSize(int width, int height) {
11704             throw new UnsupportedOperationException(
11705                     "Currently only support sizing from layout");
11706         }
11707 
11708         @Override
setKeepScreenOn(boolean screenOn)11709         public void setKeepScreenOn(boolean screenOn) {
11710             ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
11711         }
11712     }
11713 
11714     static class W extends IWindow.Stub implements WindowStateTransactionItem.TransactionListener {
11715         private final WeakReference<ViewRootImpl> mViewAncestor;
11716         private final IWindowSession mWindowSession;
11717         private boolean mIsFromTransactionItem;
11718 
W(ViewRootImpl viewAncestor)11719         W(ViewRootImpl viewAncestor) {
11720             mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
11721             mWindowSession = viewAncestor.mWindowSession;
11722         }
11723 
11724         @Override
onExecutingWindowStateTransactionItem()11725         public void onExecutingWindowStateTransactionItem() {
11726             mIsFromTransactionItem = true;
11727         }
11728 
11729         @Override
resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo)11730         public void resized(ClientWindowFrames frames, boolean reportDraw,
11731                 MergedConfiguration mergedConfiguration, InsetsState insetsState,
11732                 boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
11733                 boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo) {
11734             final boolean isFromResizeItem = mIsFromTransactionItem;
11735             mIsFromTransactionItem = false;
11736             // Although this is a AIDL method, it will only be triggered in local process through
11737             // either WindowStateResizeItem or WindowlessWindowManager.
11738             final ViewRootImpl viewAncestor = mViewAncestor.get();
11739             if (viewAncestor == null) {
11740                 return;
11741             }
11742             if (insetsState.isSourceOrDefaultVisible(ID_IME, Type.ime())) {
11743                 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#resized",
11744                         viewAncestor.getInsetsController().getHost().getInputMethodManager(),
11745                         null /* icProto */);
11746             }
11747             // If the UI thread is the same as the current thread that is dispatching
11748             // WindowStateResizeItem, then it can run directly.
11749             if (isFromResizeItem && viewAncestor.mHandler.getLooper()
11750                     == ActivityThread.currentActivityThread().getLooper()) {
11751                 viewAncestor.handleResized(frames, reportDraw, mergedConfiguration, insetsState,
11752                         forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing,
11753                         activityWindowInfo);
11754                 return;
11755             }
11756             // The the parameters from WindowStateResizeItem are already copied.
11757             final boolean needsCopy =
11758                     !isFromResizeItem && (Binder.getCallingPid() == Process.myPid());
11759             if (needsCopy) {
11760                 insetsState = new InsetsState(insetsState, true /* copySource */);
11761                 frames = new ClientWindowFrames(frames);
11762                 mergedConfiguration = new MergedConfiguration(mergedConfiguration);
11763             }
11764             viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState,
11765                     forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing,
11766                     activityWindowInfo);
11767         }
11768 
11769         @Override
insetsControlChanged(InsetsState insetsState, InsetsSourceControl.Array activeControls)11770         public void insetsControlChanged(InsetsState insetsState,
11771                 InsetsSourceControl.Array activeControls) {
11772             final boolean isFromInsetsControlChangeItem;
11773             isFromInsetsControlChangeItem = mIsFromTransactionItem;
11774             mIsFromTransactionItem = false;
11775             final ViewRootImpl viewAncestor = mViewAncestor.get();
11776             if (viewAncestor == null) {
11777                 if (isFromInsetsControlChangeItem) {
11778                     activeControls.release();
11779                 }
11780                 return;
11781             }
11782             if (insetsState.isSourceOrDefaultVisible(ID_IME, Type.ime())) {
11783                 ImeTracing.getInstance().triggerClientDump(
11784                         "ViewRootImpl#dispatchInsetsControlChanged",
11785                         viewAncestor.getInsetsController().getHost().getInputMethodManager(),
11786                         null /* icProto */);
11787             }
11788             // If the UI thread is the same as the current thread that is dispatching
11789             // WindowStateInsetsControlChangeItem, then it can run directly.
11790             if (isFromInsetsControlChangeItem && viewAncestor.mHandler.getLooper()
11791                     == ActivityThread.currentActivityThread().getLooper()) {
11792                 viewAncestor.handleInsetsControlChanged(insetsState, activeControls);
11793                 return;
11794             }
11795             // The parameters from WindowStateInsetsControlChangeItem are already copied.
11796             final boolean needsCopy =
11797                     !isFromInsetsControlChangeItem && (Binder.getCallingPid() == Process.myPid());
11798             if (needsCopy) {
11799                 insetsState = new InsetsState(insetsState, true /* copySource */);
11800                 activeControls = new InsetsSourceControl.Array(
11801                         activeControls, true /* copyControls */);
11802             }
11803 
11804             viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls);
11805         }
11806 
11807         @Override
showInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)11808         public void showInsets(@InsetsType int types, boolean fromIme,
11809                 @Nullable ImeTracker.Token statsToken) {
11810             final ViewRootImpl viewAncestor = mViewAncestor.get();
11811             if (fromIme) {
11812                 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#showInsets",
11813                         viewAncestor.getInsetsController().getHost().getInputMethodManager(),
11814                         null /* icProto */);
11815             }
11816             if (viewAncestor != null) {
11817                 ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
11818                 viewAncestor.showInsets(types, fromIme, statsToken);
11819             } else {
11820                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
11821             }
11822         }
11823 
11824         @Override
hideInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)11825         public void hideInsets(@InsetsType int types, boolean fromIme,
11826                 @Nullable ImeTracker.Token statsToken) {
11827             final ViewRootImpl viewAncestor = mViewAncestor.get();
11828             if (fromIme) {
11829                 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#hideInsets",
11830                         viewAncestor.getInsetsController().getHost().getInputMethodManager(),
11831                         null /* icProto */);
11832             }
11833             if (viewAncestor != null) {
11834                 ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
11835                 viewAncestor.hideInsets(types, fromIme, statsToken);
11836             } else {
11837                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
11838             }
11839         }
11840 
11841         @Override
moved(int newX, int newY)11842         public void moved(int newX, int newY) {
11843             final ViewRootImpl viewAncestor = mViewAncestor.get();
11844             if (viewAncestor != null) {
11845                 viewAncestor.dispatchMoved(newX, newY);
11846             }
11847         }
11848 
11849         @Override
dispatchAppVisibility(boolean visible)11850         public void dispatchAppVisibility(boolean visible) {
11851             final ViewRootImpl viewAncestor = mViewAncestor.get();
11852             if (viewAncestor != null) {
11853                 viewAncestor.dispatchAppVisibility(visible);
11854             }
11855         }
11856 
11857         @Override
dispatchGetNewSurface()11858         public void dispatchGetNewSurface() {
11859             final ViewRootImpl viewAncestor = mViewAncestor.get();
11860             if (viewAncestor != null) {
11861                 viewAncestor.dispatchGetNewSurface();
11862             }
11863         }
11864 
checkCallingPermission(String permission)11865         private static int checkCallingPermission(String permission) {
11866             try {
11867                 return ActivityManager.getService().checkPermission(
11868                         permission, Binder.getCallingPid(), Binder.getCallingUid());
11869             } catch (RemoteException e) {
11870                 return PackageManager.PERMISSION_DENIED;
11871             }
11872         }
11873 
11874         @Override
executeCommand(String command, String parameters, ParcelFileDescriptor out)11875         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
11876             final ViewRootImpl viewAncestor = mViewAncestor.get();
11877             if (viewAncestor != null) {
11878                 final View view = viewAncestor.mView;
11879                 if (view != null) {
11880                     if (checkCallingPermission(Manifest.permission.DUMP) !=
11881                             PackageManager.PERMISSION_GRANTED) {
11882                         throw new SecurityException("Insufficient permissions to invoke"
11883                                 + " executeCommand() from pid=" + Binder.getCallingPid()
11884                                 + ", uid=" + Binder.getCallingUid());
11885                     }
11886 
11887                     OutputStream clientStream = null;
11888                     try {
11889                         clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
11890                         ViewDebug.dispatchCommand(view, command, parameters, clientStream);
11891                     } catch (IOException e) {
11892                         e.printStackTrace();
11893                     } finally {
11894                         if (clientStream != null) {
11895                             try {
11896                                 clientStream.close();
11897                             } catch (IOException e) {
11898                                 e.printStackTrace();
11899                             }
11900                         }
11901                     }
11902                 }
11903             }
11904         }
11905 
11906         @Override
closeSystemDialogs(String reason)11907         public void closeSystemDialogs(String reason) {
11908             final ViewRootImpl viewAncestor = mViewAncestor.get();
11909             if (viewAncestor != null) {
11910                 viewAncestor.dispatchCloseSystemDialogs(reason);
11911             }
11912         }
11913 
11914         @Override
dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom, boolean sync)11915         public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
11916                 float zoom, boolean sync) {
11917             if (sync) {
11918                 try {
11919                     mWindowSession.wallpaperOffsetsComplete(asBinder());
11920                 } catch (RemoteException e) {
11921                 }
11922             }
11923         }
11924 
11925         @Override
dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync)11926         public void dispatchWallpaperCommand(String action, int x, int y,
11927                 int z, Bundle extras, boolean sync) {
11928             if (sync) {
11929                 try {
11930                     mWindowSession.wallpaperCommandComplete(asBinder(), null);
11931                 } catch (RemoteException e) {
11932                 }
11933             }
11934         }
11935 
11936         /* Drag/drop */
11937         @Override
dispatchDragEvent(DragEvent event)11938         public void dispatchDragEvent(DragEvent event) {
11939             final ViewRootImpl viewAncestor = mViewAncestor.get();
11940             if (viewAncestor != null) {
11941                 viewAncestor.dispatchDragEvent(event);
11942             }
11943         }
11944 
11945         @Override
dispatchWindowShown()11946         public void dispatchWindowShown() {
11947             final ViewRootImpl viewAncestor = mViewAncestor.get();
11948             if (viewAncestor != null) {
11949                 viewAncestor.dispatchWindowShown();
11950             }
11951         }
11952 
11953         @Override
requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId)11954         public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
11955             ViewRootImpl viewAncestor = mViewAncestor.get();
11956             if (viewAncestor != null) {
11957                 viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
11958             }
11959         }
11960 
11961         @Override
requestScrollCapture(IScrollCaptureResponseListener listener)11962         public void requestScrollCapture(IScrollCaptureResponseListener listener) {
11963             final ViewRootImpl viewAncestor = mViewAncestor.get();
11964             if (viewAncestor != null) {
11965                 viewAncestor.dispatchScrollCaptureRequest(listener);
11966             }
11967         }
11968 
11969         @Override
dumpWindow(ParcelFileDescriptor pfd)11970         public void dumpWindow(ParcelFileDescriptor pfd) {
11971             final ViewRootImpl viewAncestor = mViewAncestor.get();
11972             if (viewAncestor == null) {
11973                 return;
11974             }
11975             viewAncestor.mHandler.postAtFrontOfQueue(() -> {
11976                 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
11977                 try {
11978                     PrintWriter pw = new FastPrintWriter(new FileOutputStream(
11979                             pfd.getFileDescriptor()));
11980                     viewAncestor.dump("", pw);
11981                     pw.flush();
11982                 } finally {
11983                     IoUtils.closeQuietly(pfd);
11984                     StrictMode.setThreadPolicy(oldPolicy);
11985                 }
11986             });
11987         }
11988     }
11989 
11990     public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
11991         @UnsupportedAppUsage
CalledFromWrongThreadException(String msg)11992         public CalledFromWrongThreadException(String msg) {
11993             super(msg);
11994         }
11995     }
11996 
getRunQueue()11997     static HandlerActionQueue getRunQueue() {
11998         HandlerActionQueue rq = sRunQueues.get();
11999         if (rq != null) {
12000             return rq;
12001         }
12002         rq = new HandlerActionQueue();
12003         sRunQueues.set(rq);
12004         return rq;
12005     }
12006 
12007     /**
12008      * Start a drag resizing which will inform all listeners that a window resize is taking place.
12009      */
startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, Rect stableInsets)12010     private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
12011             Rect stableInsets) {
12012         if (!mDragResizing) {
12013             mDragResizing = true;
12014             if (mUseMTRenderer) {
12015                 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
12016                     mWindowCallbacks.get(i).onWindowDragResizeStart(
12017                             initialBounds, fullscreen, systemInsets, stableInsets);
12018                 }
12019             }
12020             mFullRedrawNeeded = true;
12021         }
12022     }
12023 
12024     /**
12025      * End a drag resize which will inform all listeners that a window resize has ended.
12026      */
endDragResizing()12027     private void endDragResizing() {
12028         if (mDragResizing) {
12029             mDragResizing = false;
12030             if (mUseMTRenderer) {
12031                 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
12032                     mWindowCallbacks.get(i).onWindowDragResizeEnd();
12033                 }
12034             }
12035             mFullRedrawNeeded = true;
12036         }
12037     }
12038 
updateContentDrawBounds()12039     private boolean updateContentDrawBounds() {
12040         boolean updated = false;
12041         if (mUseMTRenderer) {
12042             for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
12043                 updated |=
12044                         mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left,
12045                                 mWindowAttributes.surfaceInsets.top, mWidth, mHeight);
12046             }
12047         }
12048         return updated | (mDragResizing && mReportNextDraw);
12049     }
12050 
requestDrawWindow()12051     private void requestDrawWindow() {
12052         if (!mUseMTRenderer) {
12053             return;
12054         }
12055         // Only wait if it will report next draw.
12056         if (mReportNextDraw) {
12057             mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
12058         }
12059         for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
12060             mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
12061         }
12062     }
12063 
getSurfaceControl()12064     public SurfaceControl getSurfaceControl() {
12065         return mSurfaceControl;
12066     }
12067 
12068     /**
12069      * @return Returns a token used to identify the windows input channel.
12070      */
getInputToken()12071     public IBinder getInputToken() {
12072         if (mInputEventReceiver == null) {
12073             return null;
12074         }
12075         return mInputEventReceiver.getToken();
12076     }
12077 
12078     /**
12079      * {@inheritDoc}
12080      */
12081     @NonNull
12082     @Override
getInputTransferToken()12083     public InputTransferToken getInputTransferToken() {
12084         IBinder inputToken = getInputToken();
12085         if (inputToken == null) {
12086             throw new IllegalStateException(
12087                     "Called getInputTransferToken for Window with no input channel");
12088         }
12089         return new InputTransferToken(inputToken);
12090     }
12091     @NonNull
getWindowToken()12092     public IBinder getWindowToken() {
12093         return mAttachInfo.mWindowToken;
12094     }
12095 
12096     /**
12097      * {@inheritDoc}
12098      */
12099     @NonNull
12100     @Override
12101     @FlaggedApi(com.android.window.flags.Flags.FLAG_JANK_API)
registerOnJankDataListener( @onNull @allbackExecutor Executor executor, @NonNull SurfaceControl.OnJankDataListener listener)12102     public SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener(
12103             @NonNull @CallbackExecutor Executor executor,
12104             @NonNull SurfaceControl.OnJankDataListener listener) {
12105         SurfaceControl.OnJankDataListener wrapped = (data) ->
12106                 executor.execute(() -> listener.onJankDataAvailable(data));
12107         return mSurfaceControl.addOnJankDataListener(wrapped);
12108     }
12109 
12110     /**
12111      * Class for managing the accessibility interaction connection
12112      * based on the global accessibility state.
12113      */
12114     final class AccessibilityInteractionConnectionManager
12115             implements AccessibilityStateChangeListener {
12116         private int mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID;
12117 
12118         @Override
onAccessibilityStateChanged(boolean enabled)12119         public void onAccessibilityStateChanged(boolean enabled) {
12120             if (enabled) {
12121                 ensureConnection();
12122                 setAccessibilityWindowAttributesIfNeeded();
12123                 if (mAttachInfo.mHasWindowFocus && (mView != null)) {
12124                     mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
12125                     View focusedView = mView.findFocus();
12126                     if (focusedView != null && focusedView != mView) {
12127                         focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
12128                     }
12129                 }
12130                 if (mAttachInfo.mLeashedParentToken != null) {
12131                     mAccessibilityManager.associateEmbeddedHierarchy(
12132                             mAttachInfo.mLeashedParentToken, mLeashToken);
12133                 }
12134             } else {
12135                 ensureNoConnection();
12136                 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
12137             }
12138         }
12139 
ensureConnection()12140         public void ensureConnection() {
12141             final boolean registered = mAttachInfo.mAccessibilityWindowId
12142                     != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
12143             if (!registered) {
12144                 mAttachInfo.mAccessibilityWindowId =
12145                         mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
12146                                 mLeashToken,
12147                                 mContext.getPackageName(),
12148                                 new AccessibilityInteractionConnection(ViewRootImpl.this));
12149             }
12150         }
12151 
ensureNoConnection()12152         public void ensureNoConnection() {
12153             final boolean registered = mAttachInfo.mAccessibilityWindowId
12154                     != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
12155             if (registered) {
12156                 mAttachInfo.mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
12157                 mAccessibilityWindowAttributes = null;
12158                 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
12159             }
12160         }
12161 
ensureDirectConnection()12162         public int ensureDirectConnection() {
12163             if (mDirectConnectionId == AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) {
12164                 mDirectConnectionId = AccessibilityInteractionClient.addDirectConnection(
12165                         new AccessibilityInteractionConnection(ViewRootImpl.this),
12166                         mAccessibilityManager);
12167                 // Notify listeners in the app process.
12168                 mAccessibilityManager.notifyAccessibilityStateChanged();
12169             }
12170             return mDirectConnectionId;
12171         }
12172 
ensureNoDirectConnection()12173         public void ensureNoDirectConnection() {
12174             if (mDirectConnectionId != AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) {
12175                 AccessibilityInteractionClient.removeConnection(mDirectConnectionId);
12176                 mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID;
12177                 // Notify listeners in the app process.
12178                 mAccessibilityManager.notifyAccessibilityStateChanged();
12179             }
12180         }
12181     }
12182 
12183     final class HighContrastTextManager implements HighContrastTextStateChangeListener {
HighContrastTextManager()12184         HighContrastTextManager() {
12185             ThreadedRenderer.setHighContrastText(mAccessibilityManager.isHighContrastTextEnabled());
12186         }
12187         @Override
onHighContrastTextStateChanged(boolean enabled)12188         public void onHighContrastTextStateChanged(boolean enabled) {
12189             ThreadedRenderer.setHighContrastText(enabled);
12190 
12191             destroyAndInvalidate();
12192         }
12193     }
12194 
12195     /**
12196      * Destroy Displaylists so they can be recreated with new recordings, in case you are changing
12197      * the way things are rendered (e.g. high contrast, force dark), then invalidate to trigger a
12198      * redraw.
12199      */
destroyAndInvalidate()12200     private void destroyAndInvalidate() {
12201         destroyHardwareResources();
12202 
12203         // Schedule redraw, which will rerecord + redraw all text
12204         invalidate();
12205     }
12206 
12207     /**
12208      * This class is an interface this ViewAncestor provides to the
12209      * AccessibilityManagerService to the latter can interact with
12210      * the view hierarchy in this ViewAncestor.
12211      */
12212     static final class AccessibilityInteractionConnection
12213             extends IAccessibilityInteractionConnection.Stub {
12214         private final WeakReference<ViewRootImpl> mViewRootImpl;
12215 
AccessibilityInteractionConnection(ViewRootImpl viewRootImpl)12216         AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
12217             mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
12218         }
12219 
12220         @Override
findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix, Bundle args)12221         public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
12222                 Region interactiveRegion, int interactionId,
12223                 IAccessibilityInteractionConnectionCallback callback, int flags,
12224                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix,
12225                 Bundle args) {
12226             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12227             if (viewRootImpl != null && viewRootImpl.mView != null) {
12228                 viewRootImpl.getAccessibilityInteractionController()
12229                     .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
12230                             interactiveRegion, interactionId, callback, flags, interrogatingPid,
12231                             interrogatingTid, spec, matrix, args);
12232             } else {
12233                 // We cannot make the call and notify the caller so it does not wait.
12234                 try {
12235                     callback.setFindAccessibilityNodeInfosResult(null, interactionId);
12236                 } catch (RemoteException re) {
12237                     /* best effort - ignore */
12238                 }
12239             }
12240         }
12241 
12242         @Override
performAccessibilityAction(long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)12243         public void performAccessibilityAction(long accessibilityNodeId, int action,
12244                 Bundle arguments, int interactionId,
12245                 IAccessibilityInteractionConnectionCallback callback, int flags,
12246                 int interrogatingPid, long interrogatingTid) {
12247             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12248             if (viewRootImpl != null && viewRootImpl.mView != null) {
12249                 viewRootImpl.getAccessibilityInteractionController()
12250                     .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
12251                             interactionId, callback, flags, interrogatingPid, interrogatingTid);
12252             } else {
12253                 // We cannot make the call and notify the caller so it does not wait.
12254                 try {
12255                     callback.setPerformAccessibilityActionResult(false, interactionId);
12256                 } catch (RemoteException re) {
12257                     /* best effort - ignore */
12258                 }
12259             }
12260         }
12261 
12262         @Override
findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)12263         public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
12264                 String viewId, Region interactiveRegion, int interactionId,
12265                 IAccessibilityInteractionConnectionCallback callback, int flags,
12266                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
12267                 float[] matrix) {
12268             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12269             if (viewRootImpl != null && viewRootImpl.mView != null) {
12270                 viewRootImpl.getAccessibilityInteractionController()
12271                     .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
12272                             viewId, interactiveRegion, interactionId, callback, flags,
12273                             interrogatingPid, interrogatingTid, spec, matrix);
12274             } else {
12275                 // We cannot make the call and notify the caller so it does not wait.
12276                 try {
12277                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
12278                 } catch (RemoteException re) {
12279                     /* best effort - ignore */
12280                 }
12281             }
12282         }
12283 
12284         @Override
findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)12285         public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
12286                 Region interactiveRegion, int interactionId,
12287                 IAccessibilityInteractionConnectionCallback callback, int flags,
12288                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
12289                 float[] matrix) {
12290             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12291             if (viewRootImpl != null && viewRootImpl.mView != null) {
12292                 viewRootImpl.getAccessibilityInteractionController()
12293                     .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
12294                             interactiveRegion, interactionId, callback, flags, interrogatingPid,
12295                             interrogatingTid, spec, matrix);
12296             } else {
12297                 // We cannot make the call and notify the caller so it does not wait.
12298                 try {
12299                     callback.setFindAccessibilityNodeInfosResult(null, interactionId);
12300                 } catch (RemoteException re) {
12301                     /* best effort - ignore */
12302                 }
12303             }
12304         }
12305 
12306         @Override
findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)12307         public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
12308                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
12309                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
12310                 float[] matrix) {
12311             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12312             if (viewRootImpl != null && viewRootImpl.mView != null) {
12313                 viewRootImpl.getAccessibilityInteractionController()
12314                     .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
12315                             interactionId, callback, flags, interrogatingPid, interrogatingTid,
12316                             spec, matrix);
12317             } else {
12318                 // We cannot make the call and notify the caller so it does not wait.
12319                 try {
12320                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
12321                 } catch (RemoteException re) {
12322                     /* best effort - ignore */
12323                 }
12324             }
12325         }
12326 
12327         @Override
focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)12328         public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
12329                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
12330                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
12331                 float[] matrix) {
12332             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12333             if (viewRootImpl != null && viewRootImpl.mView != null) {
12334                 viewRootImpl.getAccessibilityInteractionController()
12335                     .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
12336                             interactionId, callback, flags, interrogatingPid, interrogatingTid,
12337                             spec, matrix);
12338             } else {
12339                 // We cannot make the call and notify the caller so it does not wait.
12340                 try {
12341                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
12342                 } catch (RemoteException re) {
12343                     /* best effort - ignore */
12344                 }
12345             }
12346         }
12347 
12348         @Override
clearAccessibilityFocus()12349         public void clearAccessibilityFocus() {
12350             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12351             if (viewRootImpl != null && viewRootImpl.mView != null) {
12352                 viewRootImpl.getAccessibilityInteractionController()
12353                         .clearAccessibilityFocusClientThread();
12354             }
12355         }
12356 
12357         @Override
notifyOutsideTouch()12358         public void notifyOutsideTouch() {
12359             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12360             if (viewRootImpl != null && viewRootImpl.mView != null) {
12361                 viewRootImpl.getAccessibilityInteractionController()
12362                         .notifyOutsideTouchClientThread();
12363             }
12364         }
12365 
12366         @Override
takeScreenshotOfWindow(int interactionId, ScreenCapture.ScreenCaptureListener listener, IAccessibilityInteractionConnectionCallback callback)12367         public void takeScreenshotOfWindow(int interactionId,
12368                 ScreenCapture.ScreenCaptureListener listener,
12369                 IAccessibilityInteractionConnectionCallback callback) {
12370             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12371             if (viewRootImpl != null && viewRootImpl.mView != null) {
12372                 viewRootImpl.getAccessibilityInteractionController()
12373                         .takeScreenshotOfWindowClientThread(interactionId, listener, callback);
12374             } else {
12375                 try {
12376                     callback.sendTakeScreenshotOfWindowError(
12377                             AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR,
12378                             interactionId);
12379                 } catch (RemoteException re) {
12380                     /* best effort - ignore */
12381                 }
12382             }
12383         }
12384 
12385         @Override
getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback)12386         public void getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback) {
12387             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12388             if (viewRootImpl != null && viewRootImpl.mView != null) {
12389                 viewRootImpl.getAccessibilityInteractionController()
12390                         .getWindowSurfaceInfoClientThread(callback);
12391             }
12392         }
12393 
attachAccessibilityOverlayToWindow( SurfaceControl sc, int interactionId, IAccessibilityInteractionConnectionCallback callback)12394         public void attachAccessibilityOverlayToWindow(
12395                 SurfaceControl sc,
12396                 int interactionId,
12397                 IAccessibilityInteractionConnectionCallback callback) {
12398             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12399             if (viewRootImpl != null) {
12400                 viewRootImpl
12401                         .getAccessibilityInteractionController()
12402                         .attachAccessibilityOverlayToWindowClientThread(
12403                                 sc, interactionId, callback);
12404             }
12405         }
12406     }
12407 
12408     /**
12409      * Gets an accessibility embedded connection interface for this ViewRootImpl.
12410      * @hide
12411      */
getAccessibilityEmbeddedConnection()12412     public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
12413         if (mAccessibilityEmbeddedConnection == null) {
12414             mAccessibilityEmbeddedConnection = new AccessibilityEmbeddedConnection(
12415                     ViewRootImpl.this);
12416         }
12417         return mAccessibilityEmbeddedConnection;
12418     }
12419 
12420     private class SendWindowContentChangedAccessibilityEvent implements Runnable {
12421         private int mChangeTypes = 0;
12422 
12423         public View mSource;
12424         public long mLastEventTimeMillis;
12425         /**
12426          * Keep track of action that caused the event.
12427          * This is empty if there's no performing actions for pending events.
12428          * This is zero if there're multiple events performed for pending events.
12429          */
12430         @NonNull public OptionalInt mAction = OptionalInt.empty();
12431         /**
12432          * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace
12433          * of the original {@link #runOrPost} call instead of one for sending the delayed event
12434          * from a looper.
12435          */
12436         public StackTraceElement[] mOrigin;
12437 
12438         @Override
run()12439         public void run() {
12440             // Protect against re-entrant code and attempt to do the right thing in the case that
12441             // we're multithreaded.
12442             View source = mSource;
12443             mSource = null;
12444             if (source == null) {
12445                 Log.e(TAG, "Accessibility content change has no source");
12446                 return;
12447             }
12448             // The accessibility may be turned off while we were waiting so check again.
12449             if (mAccessibilityManager.isEnabled()) {
12450                 mLastEventTimeMillis = SystemClock.uptimeMillis();
12451                 AccessibilityEvent event = AccessibilityEvent.obtain();
12452                 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
12453                 event.setContentChangeTypes(mChangeTypes);
12454                 if (mAction.isPresent()) event.setAction(mAction.getAsInt());
12455                 if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin;
12456                 source.sendAccessibilityEventUnchecked(event);
12457             } else {
12458                 mLastEventTimeMillis = 0;
12459             }
12460             // In any case reset to initial state.
12461             source.resetSubtreeAccessibilityStateChanged();
12462             mChangeTypes = 0;
12463             mAction = OptionalInt.empty();
12464             if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null;
12465         }
12466 
runOrPost(View source, int changeType)12467         public void runOrPost(View source, int changeType) {
12468             if (mHandler.getLooper() != Looper.myLooper()) {
12469                 CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the "
12470                         + "original thread that created a view hierarchy can touch its views.");
12471                 // TODO: Throw the exception
12472                 Log.e(TAG, "Accessibility content change on non-UI thread. Future Android "
12473                         + "versions will throw an exception.", e);
12474                 // Attempt to recover. This code does not eliminate the thread safety issue, but
12475                 // it should force any issues to happen near the above log.
12476                 mHandler.removeCallbacks(this);
12477                 if (mSource != null) {
12478                     // Dispatch whatever was pending. It's still possible that the runnable started
12479                     // just before we removed the callbacks, and bad things will happen, but at
12480                     // least they should happen very close to the logged error.
12481                     run();
12482                 }
12483             }
12484 
12485             if (!canContinueThrottle(source, changeType)) {
12486                 removeCallbacksAndRun();
12487             }
12488 
12489             if (mSource != null) {
12490                 View newSource = getCommonPredecessor(mSource, source);
12491                 if (newSource != null) {
12492                     newSource = newSource.getSelfOrParentImportantForA11y();
12493                 }
12494                 if (newSource == null) {
12495                     // If there is no common predecessor, then mSource points to
12496                     // a removed view, hence in this case always prefer the source.
12497                     newSource = source;
12498                 }
12499 
12500                 mChangeTypes |= changeType;
12501                 if (mSource != newSource) {
12502                     mChangeTypes |= AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
12503                     mSource = newSource;
12504                 }
12505 
12506                 final int performingAction = mAccessibilityManager.getPerformingAction();
12507                 if (performingAction != 0) {
12508                     if (mAction.isEmpty()) {
12509                         mAction = OptionalInt.of(performingAction);
12510                     } else if (mAction.getAsInt() != performingAction) {
12511                         // Multiple actions are performed for pending events. We cannot decide one
12512                         // action here.
12513                         // We're doing best effort to set action value, and it's fine to set
12514                         // no action this case.
12515                         mAction = OptionalInt.of(0);
12516                     }
12517                 }
12518 
12519                 return;
12520             }
12521             mSource = source;
12522             mChangeTypes = changeType;
12523             if (mAccessibilityManager.getPerformingAction() != 0) {
12524                 mAction = OptionalInt.of(mAccessibilityManager.getPerformingAction());
12525             }
12526             if (AccessibilityEvent.DEBUG_ORIGIN) {
12527                 mOrigin = Thread.currentThread().getStackTrace();
12528             }
12529             final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
12530             final long minEventIntervalMillis =
12531                     ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
12532             if (timeSinceLastMillis >= minEventIntervalMillis) {
12533                 removeCallbacksAndRun();
12534             } else {
12535                 mHandler.postDelayed(this, minEventIntervalMillis - timeSinceLastMillis);
12536             }
12537         }
12538 
removeCallbacksAndRun()12539         public void removeCallbacksAndRun() {
12540             mHandler.removeCallbacks(this);
12541             run();
12542         }
12543 
canContinueThrottle(View source, int changeType)12544         private boolean canContinueThrottle(View source, int changeType) {
12545             if (!reduceWindowContentChangedEventThrottle()) {
12546                 // Old behavior. Always throttle.
12547                 return true;
12548             }
12549             if (mSource == null) {
12550                 // We don't have a pending event.
12551                 return true;
12552             }
12553             if (mSource == source) {
12554                 // We can merge a new event with a pending event from the same source.
12555                 return true;
12556             }
12557             // We can merge subtree change events.
12558             return changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE
12559                     && mChangeTypes == AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
12560         }
12561     }
12562 
12563     private static class UnhandledKeyManager {
12564         // This is used to ensure that unhandled events are only dispatched once. We attempt
12565         // to dispatch more than once in order to achieve a certain order. Specifically, if we
12566         // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should
12567         // be dispatched after the view hierarchy, but before the Callback. However, if we aren't
12568         // in an activity, we still want unhandled keys to be dispatched.
12569         private boolean mDispatched = true;
12570 
12571         // Keeps track of which Views have unhandled key focus for which keys. This doesn't
12572         // include modifiers.
12573         private final SparseArray<WeakReference<View>> mCapturedKeys = new SparseArray<>();
12574 
12575         // The current receiver. This value is transient and used between the pre-dispatch and
12576         // pre-view phase to ensure that other input-stages don't interfere with tracking.
12577         private WeakReference<View> mCurrentReceiver = null;
12578 
dispatch(View root, KeyEvent event)12579         boolean dispatch(View root, KeyEvent event) {
12580             if (mDispatched) {
12581                 return false;
12582             }
12583             View consumer;
12584             try {
12585                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "UnhandledKeyEvent dispatch");
12586                 mDispatched = true;
12587 
12588                 consumer = root.dispatchUnhandledKeyEvent(event);
12589 
12590                 // If an unhandled listener handles one, then keep track of it so that the
12591                 // consuming view is first to receive its repeats and release as well.
12592                 if (event.getAction() == KeyEvent.ACTION_DOWN) {
12593                     int keycode = event.getKeyCode();
12594                     if (consumer != null && !KeyEvent.isModifierKey(keycode)) {
12595                         mCapturedKeys.put(keycode, new WeakReference<>(consumer));
12596                     }
12597                 }
12598             } finally {
12599                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
12600             }
12601             return consumer != null;
12602         }
12603 
12604         /**
12605          * Called before the event gets dispatched to anything
12606          */
preDispatch(KeyEvent event)12607         void preDispatch(KeyEvent event) {
12608             // Always clean-up 'up' events since it's possible for earlier dispatch stages to
12609             // consume them without consuming the corresponding 'down' event.
12610             mCurrentReceiver = null;
12611             if (event.getAction() == KeyEvent.ACTION_UP) {
12612                 int idx = mCapturedKeys.indexOfKey(event.getKeyCode());
12613                 if (idx >= 0) {
12614                     mCurrentReceiver = mCapturedKeys.valueAt(idx);
12615                     mCapturedKeys.removeAt(idx);
12616                 }
12617             }
12618         }
12619 
12620         /**
12621          * Called before the event gets dispatched to the view hierarchy
12622          * @return {@code true} if an unhandled handler has focus and consumed the event
12623          */
preViewDispatch(KeyEvent event)12624         boolean preViewDispatch(KeyEvent event) {
12625             mDispatched = false;
12626             if (mCurrentReceiver == null) {
12627                 mCurrentReceiver = mCapturedKeys.get(event.getKeyCode());
12628             }
12629             if (mCurrentReceiver != null) {
12630                 View target = mCurrentReceiver.get();
12631                 if (event.getAction() == KeyEvent.ACTION_UP) {
12632                     mCurrentReceiver = null;
12633                 }
12634                 if (target != null && target.isAttachedToWindow()) {
12635                     target.onUnhandledKeyEvent(event);
12636                 }
12637                 // consume anyways so that we don't feed uncaptured key events to other views
12638                 return true;
12639             }
12640             return false;
12641         }
12642     }
12643 
12644     /**
12645      * @hide
12646      */
setDisplayDecoration(boolean displayDecoration)12647     public void setDisplayDecoration(boolean displayDecoration) {
12648         if (displayDecoration == mDisplayDecorationCached) return;
12649 
12650         mDisplayDecorationCached = displayDecoration;
12651 
12652         if (mSurfaceControl.isValid()) {
12653             updateDisplayDecoration();
12654         }
12655     }
12656 
updateDisplayDecoration()12657     private void updateDisplayDecoration() {
12658         mTransaction.setDisplayDecoration(mSurfaceControl, mDisplayDecorationCached).apply();
12659     }
12660 
12661     /**
12662      * Sends a list of blur regions to SurfaceFlinger, tagged with a frame.
12663      *
12664      * @param regionCopy List of regions
12665      * @param frameNumber Frame where it should be applied (or current when using BLAST)
12666      */
dispatchBlurRegions(float[][] regionCopy, long frameNumber)12667     public void dispatchBlurRegions(float[][] regionCopy, long frameNumber) {
12668         final SurfaceControl surfaceControl = getSurfaceControl();
12669         if (!surfaceControl.isValid()) {
12670             return;
12671         }
12672 
12673         SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
12674         transaction.setBlurRegions(surfaceControl, regionCopy);
12675 
12676         if (mBlastBufferQueue != null) {
12677             transaction.onMergeWithNextTransaction(getTitle());
12678             mBlastBufferQueue.mergeWithNextTransaction(transaction, frameNumber);
12679         }
12680     }
12681 
12682     /**
12683      * Creates a background blur drawable for the backing {@link Surface}.
12684      */
createBackgroundBlurDrawable()12685     public BackgroundBlurDrawable createBackgroundBlurDrawable() {
12686         return mBlurRegionAggregator.createBackgroundBlurDrawable(mContext);
12687     }
12688 
12689     @Override
onDescendantUnbufferedRequested()12690     public void onDescendantUnbufferedRequested() {
12691         mUnbufferedInputSource = mView.mUnbufferedInputSource;
12692     }
12693 
getSurfaceSequenceId()12694     int getSurfaceSequenceId() {
12695         return mSurfaceSequenceId;
12696     }
12697 
12698     /**
12699      * Merges the transaction passed in with the next transaction in BLASTBufferQueue. This ensures
12700      * you can add transactions to the upcoming frame.
12701      */
mergeWithNextTransaction(Transaction t, long frameNumber)12702     public void mergeWithNextTransaction(Transaction t, long frameNumber) {
12703         if (mBlastBufferQueue != null) {
12704             if (t != null) {
12705                 t.onMergeWithNextTransaction(getTitle());
12706             }
12707             mBlastBufferQueue.mergeWithNextTransaction(t, frameNumber);
12708         } else {
12709             t.apply();
12710         }
12711     }
12712 
12713     @Override
buildReparentTransaction( @onNull SurfaceControl child)12714     @Nullable public SurfaceControl.Transaction buildReparentTransaction(
12715         @NonNull SurfaceControl child) {
12716         if (mSurfaceControl.isValid()) {
12717             Transaction t = new Transaction();
12718             return t.reparent(child, updateAndGetBoundsLayer(t));
12719         }
12720         return null;
12721     }
12722 
12723     @Override
applyTransactionOnDraw(@onNull SurfaceControl.Transaction t)12724     public boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t) {
12725         if (mRemoved || !isHardwareEnabled()) {
12726             logAndTrace("applyTransactionOnDraw applyImmediately");
12727             t.apply();
12728         } else {
12729             Trace.instant(Trace.TRACE_TAG_VIEW, "applyTransactionOnDraw-" + mTag);
12730             // Copy and clear the passed in transaction for thread safety. The new transaction is
12731             // accessed on the render thread.
12732             mPendingTransaction.merge(t);
12733             mHasPendingTransactions = true;
12734         }
12735         return true;
12736     }
12737 
12738     @Override
getBufferTransformHint()12739     public @SurfaceControl.BufferTransform int getBufferTransformHint() {
12740         // TODO(b/326482114) We use mPreviousTransformHint (calculated using mDisplay's rotation)
12741         // instead of mSurfaceControl#getTransformHint because there's a race where SurfaceFlinger
12742         // can set an incorrect transform hint for a few frames before it is aware of the updated
12743         // display rotation.
12744         if (enableBufferTransformHintFromDisplay()) {
12745             return mPreviousTransformHint;
12746         }
12747 
12748         if (mSurfaceControl.isValid()) {
12749             return mSurfaceControl.getTransformHint();
12750         } else {
12751             return SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
12752         }
12753     }
12754 
12755     @Override
addOnBufferTransformHintChangedListener( OnBufferTransformHintChangedListener listener)12756     public void addOnBufferTransformHintChangedListener(
12757             OnBufferTransformHintChangedListener listener) {
12758         Objects.requireNonNull(listener);
12759         if (mTransformHintListeners.contains(listener)) {
12760             throw new IllegalArgumentException(
12761                     "attempt to call addOnBufferTransformHintChangedListener() "
12762                             + "with a previously registered listener");
12763         }
12764         mTransformHintListeners.add(listener);
12765     }
12766 
12767     @Override
removeOnBufferTransformHintChangedListener( OnBufferTransformHintChangedListener listener)12768     public void removeOnBufferTransformHintChangedListener(
12769             OnBufferTransformHintChangedListener listener) {
12770         Objects.requireNonNull(listener);
12771         mTransformHintListeners.remove(listener);
12772     }
12773 
dispatchTransformHintChanged(@urfaceControl.BufferTransform int hint)12774     private void dispatchTransformHintChanged(@SurfaceControl.BufferTransform int hint) {
12775         if (mTransformHintListeners.isEmpty()) {
12776             return;
12777         }
12778         ArrayList<OnBufferTransformHintChangedListener> listeners =
12779                 (ArrayList<OnBufferTransformHintChangedListener>) mTransformHintListeners.clone();
12780         for (int i = 0; i < listeners.size(); i++) {
12781             OnBufferTransformHintChangedListener listener = listeners.get(i);
12782             listener.onBufferTransformHintChanged(hint);
12783         }
12784     }
12785 
wasRelayoutRequested()12786     boolean wasRelayoutRequested() {
12787         return mRelayoutRequested;
12788     }
12789 
forceWmRelayout()12790     void forceWmRelayout() {
12791        mForceNextWindowRelayout = true;
12792        scheduleTraversals();
12793     }
12794 
12795     /**
12796      * Returns the {@link OnBackInvokedDispatcher} on the decor view if one exists, or the
12797      * fallback {@link OnBackInvokedDispatcher} instance.
12798      */
12799     @NonNull
getOnBackInvokedDispatcher()12800     public WindowOnBackInvokedDispatcher getOnBackInvokedDispatcher() {
12801         return mOnBackInvokedDispatcher;
12802     }
12803 
12804     @NonNull
12805     @Override
findOnBackInvokedDispatcherForChild( @onNull View child, @NonNull View requester)12806     public OnBackInvokedDispatcher findOnBackInvokedDispatcherForChild(
12807             @NonNull View child, @NonNull View requester) {
12808         return getOnBackInvokedDispatcher();
12809     }
12810 
12811     /**
12812      * When this ViewRootImpl is added to the window manager, transfers the first
12813      * {@link OnBackInvokedCallback} to be called to the server.
12814      */
registerBackCallbackOnWindow()12815     private void registerBackCallbackOnWindow() {
12816         if (OnBackInvokedDispatcher.DEBUG) {
12817             Log.d(OnBackInvokedDispatcher.TAG, TextUtils.formatSimple(
12818                     "ViewRootImpl.registerBackCallbackOnWindow. Dispatcher:%s Package:%s "
12819                             + "IWindow:%s Session:%s",
12820                     mOnBackInvokedDispatcher, mBasePackageName, mWindow, mWindowSession));
12821         }
12822         mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow, this,
12823                 mImeBackAnimationController);
12824     }
12825 
12826     /**
12827      * Sends {@link KeyEvent#ACTION_DOWN ACTION_DOWN} and {@link KeyEvent#ACTION_UP ACTION_UP}
12828      * back key events
12829      *
12830      * @param preImeOnly whether the back events should be sent to the pre-ime stage only
12831      * @return whether the event was handled (i.e. onKeyPreIme consumed it if preImeOnly=true)
12832      */
injectBackKeyEvents(boolean preImeOnly)12833     public boolean injectBackKeyEvents(boolean preImeOnly) {
12834         sendBackKeyEvent(KeyEvent.ACTION_DOWN, preImeOnly);
12835         return sendBackKeyEvent(KeyEvent.ACTION_UP, preImeOnly);
12836     }
12837 
sendBackKeyEvent(int action, boolean preImeOnly)12838     private boolean sendBackKeyEvent(int action, boolean preImeOnly) {
12839         long when = SystemClock.uptimeMillis();
12840         final KeyEvent ev = new KeyEvent(when, when, action,
12841                 KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
12842                 KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
12843                 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
12844                 InputDevice.SOURCE_KEYBOARD);
12845         int flags = preImeOnly ? QueuedInputEvent.FLAG_PRE_IME_ONLY : 0;
12846         QueuedInputEvent q = enqueueInputEvent(ev, null /* receiver */, flags,
12847                 true /* processImmediately */);
12848         return (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
12849     }
12850 
registerCompatOnBackInvokedCallback()12851     private void registerCompatOnBackInvokedCallback() {
12852         mCompatOnBackInvokedCallback = () -> {
12853             injectBackKeyEvents(/* preImeOnly */ false);
12854         };
12855         if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) {
12856             Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher");
12857             return;
12858         }
12859         mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
12860                 OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatOnBackInvokedCallback);
12861     }
12862 
12863     @Override
setTouchableRegion(Region r)12864     public void setTouchableRegion(Region r) {
12865         if (r != null) {
12866             mTouchableRegion = new Region(r);
12867         } else {
12868             mTouchableRegion = null;
12869         }
12870         mLastGivenInsets.reset();
12871         requestLayout();
12872     }
12873 
getWindowSession()12874     IWindowSession getWindowSession() {
12875         return mWindowSession;
12876     }
12877 
registerCallbacksForSync(boolean syncBuffer, final SurfaceSyncGroup surfaceSyncGroup)12878     private void registerCallbacksForSync(boolean syncBuffer,
12879             final SurfaceSyncGroup surfaceSyncGroup) {
12880         if (!isHardwareEnabled()) {
12881             return;
12882         }
12883 
12884         if (DEBUG_BLAST) {
12885             Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer);
12886         }
12887 
12888         final Transaction t;
12889         if (mHasPendingTransactions) {
12890             t = new Transaction();
12891             t.merge(mPendingTransaction);
12892             mHasPendingTransactions = false;
12893         } else {
12894             t = null;
12895         }
12896 
12897         mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
12898             @Override
12899             public void onFrameDraw(long frame) {
12900             }
12901 
12902             @Override
12903             public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
12904                 if (DEBUG_BLAST) {
12905                     Log.d(mTag,
12906                             "Received frameDrawingCallback syncResult=" + syncResult + " frameNum="
12907                                     + frame + ".");
12908                 }
12909                 if (t != null) {
12910                     mergeWithNextTransaction(t, frame);
12911                 }
12912 
12913                 // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
12914                 // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
12915                 // any blast sync or commit callback, and the code should directly call
12916                 // pendingDrawFinished.
12917                 if ((syncResult
12918                         & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
12919                     surfaceSyncGroup.addTransaction(
12920                             mBlastBufferQueue.gatherPendingTransactions(frame));
12921                     surfaceSyncGroup.markSyncReady();
12922                     return null;
12923                 }
12924 
12925                 if (DEBUG_BLAST) {
12926                     Log.d(mTag, "Setting up sync and frameCommitCallback");
12927                 }
12928 
12929                 if (syncBuffer) {
12930                     boolean result = mBlastBufferQueue.syncNextTransaction(transaction -> {
12931                         Runnable timeoutRunnable = () -> Log.e(mTag,
12932                                 "Failed to submit the sync transaction after 4s. Likely to ANR "
12933                                         + "soon");
12934                         mHandler.postDelayed(timeoutRunnable, 4000L * Build.HW_TIMEOUT_MULTIPLIER);
12935                         transaction.addTransactionCommittedListener(mSimpleExecutor,
12936                                 () -> mHandler.removeCallbacks(timeoutRunnable));
12937                         surfaceSyncGroup.addTransaction(transaction);
12938                         surfaceSyncGroup.markSyncReady();
12939                     });
12940                     if (!result) {
12941                         // syncNextTransaction can only return false if something is already trying
12942                         // to sync the same frame in the same BBQ. That shouldn't be possible, but
12943                         // if it did happen, invoke markSyncReady so the active SSG doesn't get
12944                         // stuck.
12945                         Log.w(mTag, "Unable to syncNextTransaction. Possibly something else is"
12946                                 + " trying to sync?");
12947                         surfaceSyncGroup.markSyncReady();
12948                     }
12949                 }
12950 
12951                 return didProduceBuffer -> {
12952                     if (DEBUG_BLAST) {
12953                         Log.d(mTag, "Received frameCommittedCallback"
12954                                 + " lastAttemptedDrawFrameNum=" + frame
12955                                 + " didProduceBuffer=" + didProduceBuffer);
12956                     }
12957 
12958                     // If frame wasn't drawn, clear out the next transaction so it doesn't affect
12959                     // the next draw attempt. The next transaction and transaction complete callback
12960                     // were only set for the current draw attempt.
12961                     if (!didProduceBuffer) {
12962                         mBlastBufferQueue.clearSyncTransaction();
12963 
12964                         // Gather the transactions that were sent to mergeWithNextTransaction
12965                         // since the frame didn't draw on this vsync. It's possible the frame will
12966                         // draw later, but it's better to not be sync than to block on a frame that
12967                         // may never come.
12968                         surfaceSyncGroup.addTransaction(
12969                                 mBlastBufferQueue.gatherPendingTransactions(frame));
12970                         surfaceSyncGroup.markSyncReady();
12971                         return;
12972                     }
12973 
12974                     // If we didn't request to sync a buffer, then we won't get the
12975                     // syncNextTransaction callback. Instead, just report back to the Syncer so it
12976                     // knows that this sync request is complete.
12977                     if (!syncBuffer) {
12978                         surfaceSyncGroup.markSyncReady();
12979                     }
12980                 };
12981             }
12982         });
12983     }
12984 
12985     /**
12986      * This code will ensure that if multiple SurfaceSyncGroups are created for the same
12987      * ViewRootImpl the SurfaceSyncGroups will maintain an order. The scenario that could occur
12988      * is the following:
12989      * <p>
12990      * 1. SSG1 is created that includes the target VRI. There could be other VRIs in SSG1
12991      * 2. The target VRI draws its frame and marks its own active SSG as ready, but SSG1 is still
12992      *    waiting on other things in the SSG
12993      * 3. Another SSG2 is created for the target VRI. The second frame renders and marks its own
12994      *    second SSG as complete. SSG2 has nothing else to wait on, so it will apply at this point,
12995      *    even though SSG1 has not finished.
12996      * 4. Frame2 will get to SF first and Frame1 will later get to SF when SSG1 completes.
12997      * <p>
12998      * The code below ensures the SSGs that contains the VRI maintain an order. We create a new SSG
12999      * that's a safeguard SSG. Its only job is to prevent the next active SSG from completing.
13000      * The current active SSG for VRI will add a transaction committed callback and when that's
13001      * invoked, it will mark the safeguard SSG as ready. If a new request to create a SSG comes
13002      * in and the safeguard SSG is not null, it's added as part of the new active SSG. A new
13003      * safeguard SSG is created to correspond to the new active SSG. This creates a chain to
13004      * ensure the latter SSG always waits for the former SSG's transaction to get to SF.
13005      */
safeguardOverlappingSyncs(SurfaceSyncGroup activeSurfaceSyncGroup)13006     private void safeguardOverlappingSyncs(SurfaceSyncGroup activeSurfaceSyncGroup) {
13007         SurfaceSyncGroup safeguardSsg = new SurfaceSyncGroup("Safeguard-" + mTag);
13008         // Always disable timeout on the safeguard sync
13009         safeguardSsg.toggleTimeout(false /* enable */);
13010         synchronized (mPreviousSyncSafeguardLock) {
13011             if (mPreviousSyncSafeguard != null) {
13012                 activeSurfaceSyncGroup.add(mPreviousSyncSafeguard, null /* runnable */);
13013                 // Temporarily disable the timeout on the SSG that will contain the buffer. This
13014                 // is to ensure we don't timeout the active SSG before the previous one completes to
13015                 // ensure the order is maintained. The previous SSG has a timeout on its own SSG
13016                 // so it's guaranteed to complete.
13017                 activeSurfaceSyncGroup.toggleTimeout(false /* enable */);
13018                 mPreviousSyncSafeguard.addSyncCompleteCallback(mSimpleExecutor, () -> {
13019                     // Once we receive that the previous sync guard has been invoked, we can re-add
13020                     // the timeout on the active sync to ensure we eventually complete so it's not
13021                     // stuck permanently.
13022                     activeSurfaceSyncGroup.toggleTimeout(true /*enable */);
13023                 });
13024             }
13025             mPreviousSyncSafeguard = safeguardSsg;
13026         }
13027 
13028         Transaction t = new Transaction();
13029         t.addTransactionCommittedListener(mSimpleExecutor, () -> {
13030             safeguardSsg.markSyncReady();
13031             synchronized (mPreviousSyncSafeguardLock) {
13032                 if (mPreviousSyncSafeguard == safeguardSsg) {
13033                     mPreviousSyncSafeguard = null;
13034                 }
13035             }
13036         });
13037         activeSurfaceSyncGroup.addTransaction(t);
13038     }
13039 
13040     /**
13041      * Resume rendering after being paused for sync due to a timeout.
13042      */
resumeAfterSyncTimeout()13043     private void resumeAfterSyncTimeout() {
13044         Log.e(mTag, "Timedout waiting to unpause for sync mNumPausedForSync=" + mNumPausedForSync);
13045         mNumPausedForSync = 0;
13046         scheduleTraversals();
13047     }
13048 
13049     @Override
getOrCreateSurfaceSyncGroup()13050     public SurfaceSyncGroup getOrCreateSurfaceSyncGroup() {
13051         boolean newSyncGroup = false;
13052         if (mActiveSurfaceSyncGroup == null) {
13053             mActiveSurfaceSyncGroup = new SurfaceSyncGroup(mTag);
13054             mActiveSurfaceSyncGroup.setAddedToSyncListener(() -> {
13055                 Runnable runnable = () -> {
13056                     // Check if it's already 0 because the timeout could have reset the count to
13057                     // 0 and we don't want to go negative.
13058                     if (mNumPausedForSync > 0) {
13059                         mNumPausedForSync--;
13060                     }
13061                     if (mNumPausedForSync == 0) {
13062                         mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
13063                         if (!mIsInTraversal) {
13064                             scheduleTraversals();
13065                         }
13066                     }
13067                 };
13068 
13069                 if (Thread.currentThread() == mThread) {
13070                     runnable.run();
13071                 } else {
13072                     mHandler.post(runnable);
13073                 }
13074             });
13075             newSyncGroup = true;
13076 
13077             // If the sync group is marked ready by a timeout, check if rendering is paused and
13078             // if it is, resume rendering and trigger a traversal.
13079             mActiveSurfaceSyncGroup.addSyncCompleteCallback(mExecutor, () -> {
13080                 if (mActiveSurfaceSyncGroup != null
13081                         && mActiveSurfaceSyncGroup.isComplete() && mNumPausedForSync > 0) {
13082                     mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
13083                     resumeAfterSyncTimeout();
13084                 }
13085             });
13086         }
13087 
13088         Trace.instant(Trace.TRACE_TAG_VIEW,
13089                 "getOrCreateSurfaceSyncGroup isNew=" + newSyncGroup + " " + mTag);
13090 
13091         if (DEBUG_BLAST) {
13092             if (newSyncGroup) {
13093                 Log.d(mTag, "Creating new active sync group " + mActiveSurfaceSyncGroup.getName());
13094             } else {
13095                 Log.d(mTag, "Return already created active sync group "
13096                         + mActiveSurfaceSyncGroup.getName());
13097             }
13098         }
13099 
13100         // The sync group can be marked ready by a timeout. This makes incrementing
13101         // mNumPausedForSync racy. Here we check if the sync group is complete and
13102         // if it is then we don't pause for syncing.
13103         if (!mActiveSurfaceSyncGroup.isComplete()) {
13104             mNumPausedForSync++;
13105             mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
13106             mHandler.sendEmptyMessageDelayed(MSG_PAUSED_FOR_SYNC_TIMEOUT,
13107                     1000 * Build.HW_TIMEOUT_MULTIPLIER);
13108         } else {
13109             Log.d(mTag, "Active sync group is already completed "
13110                     + mActiveSurfaceSyncGroup.getName());
13111         }
13112         return mActiveSurfaceSyncGroup;
13113     }
13114 
13115     private final Executor mSimpleExecutor = Runnable::run;
13116 
updateSyncInProgressCount(SurfaceSyncGroup syncGroup)13117     private void updateSyncInProgressCount(SurfaceSyncGroup syncGroup) {
13118         if (mAttachInfo.mThreadedRenderer == null) {
13119             return;
13120         }
13121 
13122         synchronized (sSyncProgressLock) {
13123             if (sNumSyncsInProgress++ == 0) {
13124                 HardwareRenderer.setRtAnimationsEnabled(false);
13125             }
13126         }
13127 
13128         syncGroup.addSyncCompleteCallback(mSimpleExecutor, () -> {
13129             synchronized (sSyncProgressLock) {
13130                 if (--sNumSyncsInProgress == 0) {
13131                     HardwareRenderer.setRtAnimationsEnabled(true);
13132                 }
13133             }
13134         });
13135     }
13136 
addToSync(SurfaceSyncGroup syncable)13137     void addToSync(SurfaceSyncGroup syncable) {
13138         if (mActiveSurfaceSyncGroup == null) {
13139             return;
13140         }
13141         mActiveSurfaceSyncGroup.add(syncable, null /* Runnable */);
13142     }
13143 
13144     @Override
setChildBoundingInsets(@onNull Rect insets)13145     public void setChildBoundingInsets(@NonNull Rect insets) {
13146         if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) {
13147             throw new IllegalArgumentException("Negative insets passed to setChildBoundingInsets.");
13148         }
13149         mChildBoundingInsets.set(insets);
13150         mChildBoundingInsetsChanged = true;
13151         scheduleTraversals();
13152     }
13153 
13154 
logAndTrace(String msg)13155     private void logAndTrace(String msg) {
13156         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
13157             Trace.instant(Trace.TRACE_TAG_VIEW, mTag + "-" + msg);
13158         }
13159         if (DEBUG_BLAST) {
13160             Log.d(mTag, msg);
13161         }
13162         EventLog.writeEvent(LOGTAG_VIEWROOT_DRAW_EVENT, mTag, msg);
13163     }
13164 
13165     /**
13166      * Views that are animating with the ThreadedRenderer don't use the normal invalidation
13167      * path, so the value won't be updated through performTraversals. This reads the votes
13168      * from those views.
13169      */
updateFrameRateFromThreadedRendererViews()13170     private void updateFrameRateFromThreadedRendererViews() {
13171         ArrayList<View> views = mThreadedRendererViews;
13172         for (int i = views.size() - 1; i >= 0; i--) {
13173             View view = views.get(i);
13174             View.AttachInfo attachInfo = view.mAttachInfo;
13175             if (attachInfo == null || attachInfo.mViewRootImpl != this) {
13176                 views.remove(i);
13177             } else {
13178                 view.votePreferredFrameRate();
13179             }
13180         }
13181     }
13182 
13183     /**
13184      * Sets the mPreferredFrameRateCategory from the high, high_hint, normal, and low counts.
13185      */
setCategoryFromCategoryCounts()13186     private void setCategoryFromCategoryCounts() {
13187         switch (mPreferredFrameRateCategory) {
13188             case FRAME_RATE_CATEGORY_LOW -> mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT;
13189             case FRAME_RATE_CATEGORY_NORMAL ->
13190                     mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT;
13191             case FRAME_RATE_CATEGORY_HIGH_HINT ->
13192                     mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT;
13193             case FRAME_RATE_CATEGORY_HIGH ->
13194                     mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
13195         }
13196 
13197 
13198         if (mFrameRateCategoryHighCount > 0) {
13199             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
13200         } else if (mFrameRateCategoryHighHintCount > 0) {
13201             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT;
13202         } else if (mFrameRateCategoryNormalCount > 0) {
13203             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NORMAL;
13204         } else if (mFrameRateCategoryLowCount > 0) {
13205             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW;
13206         }
13207     }
13208 
setPreferredFrameRateCategory(int preferredFrameRateCategory)13209     private void setPreferredFrameRateCategory(int preferredFrameRateCategory) {
13210         if (!shouldSetFrameRateCategory()) {
13211             return;
13212         }
13213 
13214         int frameRateCategory;
13215         int frameRateReason;
13216         String view;
13217 
13218         if (mIsFrameRateBoosting || mInsetsAnimationRunning) {
13219             frameRateCategory = FRAME_RATE_CATEGORY_HIGH;
13220             frameRateReason = FRAME_RATE_CATEGORY_REASON_BOOST;
13221             view = null;
13222         } else if (mIsTouchBoosting && preferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH_HINT) {
13223             frameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT;
13224             frameRateReason = FRAME_RATE_CATEGORY_REASON_TOUCH;
13225             view = null;
13226         } else {
13227             frameRateCategory = preferredFrameRateCategory;
13228             frameRateReason = mFrameRateCategoryChangeReason;
13229             view = mFrameRateCategoryView;
13230         }
13231 
13232         boolean traceFrameRateCategory = false;
13233         try {
13234             if ((frameRateCategory != FRAME_RATE_CATEGORY_DEFAULT
13235                     && mLastPreferredFrameRateCategory != frameRateCategory)
13236                     || mSurfaceReplaced) {
13237                 traceFrameRateCategory = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
13238                 if (traceFrameRateCategory) {
13239                     String reason = reasonToString(frameRateReason);
13240                     String sourceView = view == null ? "-" : view;
13241                     String category = categoryToString(frameRateCategory);
13242                     Trace.traceBegin(
13243                             Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRateCategory "
13244                                     + category + ", reason " + reason + ", "
13245                                     + sourceView);
13246                 }
13247                 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) {
13248                     mFrameRateTransaction.setFrameRateCategory(mSurfaceControl,
13249                         frameRateCategory, false).applyAsyncUnsafe();
13250 
13251                     if (sToolkitFrameRateDebugFlagValue) {
13252                         Log.v(mTag, "### ViewRootImpl setFrameRateCategory '"
13253                                 + categoryToString(frameRateCategory) + "'");
13254                     }
13255                 }
13256                 mLastPreferredFrameRateCategory = frameRateCategory;
13257             }
13258         } catch (Exception e) {
13259             Log.e(mTag, "Unable to set frame rate category", e);
13260         } finally {
13261             if (traceFrameRateCategory) {
13262                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
13263             }
13264         }
13265     }
13266 
categoryToString(int frameRateCategory)13267     static String categoryToString(int frameRateCategory) {
13268         String category;
13269         switch (frameRateCategory) {
13270             case FRAME_RATE_CATEGORY_NO_PREFERENCE -> category = "no preference";
13271             case FRAME_RATE_CATEGORY_LOW -> category = "low";
13272             case FRAME_RATE_CATEGORY_NORMAL -> category = "normal";
13273             case FRAME_RATE_CATEGORY_HIGH_HINT -> category = "high hint";
13274             case FRAME_RATE_CATEGORY_HIGH -> category = "high";
13275             default -> category = "default";
13276         }
13277         return category;
13278     }
13279 
reasonToString(int reason)13280     private static String reasonToString(int reason) {
13281         String str;
13282         switch (reason) {
13283             case FRAME_RATE_CATEGORY_REASON_INTERMITTENT -> str = "intermittent";
13284             case FRAME_RATE_CATEGORY_REASON_SMALL -> str = "small";
13285             case FRAME_RATE_CATEGORY_REASON_LARGE -> str = "large";
13286             case FRAME_RATE_CATEGORY_REASON_REQUESTED -> str = "requested";
13287             case FRAME_RATE_CATEGORY_REASON_INVALID -> str = "invalid frame rate";
13288             case FRAME_RATE_CATEGORY_REASON_VELOCITY -> str = "velocity";
13289             case FRAME_RATE_CATEGORY_REASON_UNKNOWN -> str = "unknown";
13290             case FRAME_RATE_CATEGORY_REASON_BOOST -> str = "boost";
13291             case FRAME_RATE_CATEGORY_REASON_TOUCH -> str = "touch";
13292             case FRAME_RATE_CATEGORY_REASON_CONFLICTED -> str = "conflicted";
13293             default -> str = String.valueOf(reason);
13294         }
13295         return str;
13296     }
13297 
setPreferredFrameRate(float preferredFrameRate)13298     private void setPreferredFrameRate(float preferredFrameRate) {
13299         if (!shouldSetFrameRate() || preferredFrameRate < 0) {
13300             return;
13301         }
13302 
13303         boolean traceFrameRate = false;
13304         try {
13305             if (mLastPreferredFrameRate != preferredFrameRate || mSurfaceReplaced) {
13306                 traceFrameRate = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
13307                 if (traceFrameRate) {
13308                     Trace.traceBegin(
13309                             Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate "
13310                                 + preferredFrameRate + " compatibility "
13311                                 + mFrameRateCompatibility);
13312                 }
13313                 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) {
13314                     if (preferredFrameRate > 0) {
13315                         mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate,
13316                                 mFrameRateCompatibility);
13317                         if (sToolkitFrameRateDebugFlagValue) {
13318                             Log.v(mTag, "### ViewRootImpl setFrameRate '"
13319                                     + preferredFrameRate + "'");
13320                         }
13321                     } else {
13322                         mFrameRateTransaction.clearFrameRate(mSurfaceControl);
13323                         if (sToolkitFrameRateDebugFlagValue) {
13324                             Log.v(mTag, "### ViewRootImpl setFrameRate 0 Hz");
13325                         }
13326                     }
13327                     mFrameRateTransaction.applyAsyncUnsafe();
13328                 }
13329                 mLastPreferredFrameRate = preferredFrameRate;
13330             }
13331         } catch (Exception e) {
13332             Log.e(mTag, "Unable to set frame rate", e);
13333         } finally {
13334             if (traceFrameRate) {
13335                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
13336             }
13337         }
13338     }
13339 
shouldSetFrameRateCategory()13340     private boolean shouldSetFrameRateCategory() {
13341         // use toolkitSetFrameRate flag to gate the change
13342         return shouldEnableDvrr() && mSurface.isValid();
13343     }
13344 
shouldSetFrameRate()13345     private boolean shouldSetFrameRate() {
13346         // use toolkitSetFrameRate flag to gate the change
13347         return shouldEnableDvrr() && mSurface.isValid() && mPreferredFrameRate >= 0
13348                 && !mIsFrameRateConflicted;
13349     }
13350 
shouldTouchBoost(int motionEventAction, int windowType)13351     private boolean shouldTouchBoost(int motionEventAction, int windowType) {
13352         // boost for almost all input
13353         boolean desiredAction = motionEventAction != MotionEvent.ACTION_OUTSIDE;
13354         boolean undesiredType = windowType == TYPE_INPUT_METHOD
13355                 && sToolkitFrameRateTypingReadOnlyFlagValue;
13356 
13357         // don't suppress touch boost for TYPE_INPUT_METHOD in ViewRootImpl
13358         if (toolkitFrameRateTouchBoost25q1()) {
13359             return desiredAction && shouldEnableDvrr() && getFrameRateBoostOnTouchEnabled();
13360         }
13361         // use toolkitSetFrameRate flag to gate the change
13362         return desiredAction && !undesiredType && shouldEnableDvrr()
13363                 && getFrameRateBoostOnTouchEnabled();
13364     }
13365 
13366     /**
13367      * Allow Views to vote for the preferred frame rate category
13368      *
13369      * @param frameRateCategory the preferred frame rate category of a View
13370      */
13371     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
votePreferredFrameRateCategory(int frameRateCategory, int reason, View view)13372     public void votePreferredFrameRateCategory(int frameRateCategory, int reason, View view) {
13373         if (frameRateCategory > mPreferredFrameRateCategory) {
13374             mPreferredFrameRateCategory = frameRateCategory;
13375             mFrameRateCategoryChangeReason = reason;
13376             // mFrameRateCategoryView = view == null ? "-" : view.getClass().getSimpleName();
13377         }
13378         mDrawnThisFrame = true;
13379 
13380         if (sToolkitFrameRateDebugFlagValue) {
13381             String viewName = view == null ? "-" : view.getClass().getSimpleName();
13382             Log.v(mTag, "### View: " + viewName +  " votes '"
13383                     + categoryToString(frameRateCategory) + "'");
13384         }
13385     }
13386 
13387     /**
13388      * Mark a View as having an active ThreadedRenderer animation. This is used for
13389      * RenderNodeAnimators and AnimatedVectorDrawables. When the animation stops,
13390      * {@link #removeThreadedRendererView(View)} must be called.
13391      * @param view The View with the ThreadedRenderer animation that started.
13392      */
addThreadedRendererView(View view)13393     public void addThreadedRendererView(View view) {
13394         if (shouldEnableDvrr() && !mThreadedRendererViews.contains(view)) {
13395             mThreadedRendererViews.add(view);
13396         }
13397     }
13398 
13399     /**
13400      * When a ThreadedRenderer animation ends, the View that is associated with it using
13401      * {@link #addThreadedRendererView(View)} must be removed with a call to this method.
13402      * @param view The View whose ThreadedRender animation has stopped.
13403      */
removeThreadedRendererView(View view)13404     public void removeThreadedRendererView(View view) {
13405         mThreadedRendererViews.remove(view);
13406         if (shouldEnableDvrr()
13407                 && !mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) {
13408             mInvalidationIdleMessagePosted = true;
13409             mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS);
13410         }
13411     }
13412 
13413     /**
13414      * Returns {@link #INTERMITTENT_STATE_INTERMITTENT} when the ViewRootImpl has only been
13415      * updated intermittently, {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} when it is
13416      * not updated intermittently, and {@link #INTERMITTENT_STATE_IN_TRANSITION} when it
13417      * is transitioning between {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} and
13418      * {@link #INTERMITTENT_STATE_INTERMITTENT}.
13419      */
intermittentUpdateState()13420     int intermittentUpdateState() {
13421         if (mMinusOneFrameIntervalMillis + mMinusTwoFrameIntervalMillis
13422                 < INFREQUENT_UPDATE_INTERVAL_MILLIS) {
13423             return INTERMITTENT_STATE_NOT_INTERMITTENT;
13424         }
13425         if (mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS) {
13426             return INTERMITTENT_STATE_INTERMITTENT;
13427         }
13428         return INTERMITTENT_STATE_IN_TRANSITION;
13429     }
13430 
13431     /**
13432      * Returns whether a View should vote for frame rate category. When the category is HIGH
13433      * already, there's no need to calculate the category on the View and vote.
13434      */
shouldCheckFrameRateCategory()13435     public boolean shouldCheckFrameRateCategory() {
13436         return mPreferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH;
13437     }
13438 
13439     /**
13440      * Returns whether a View should vote for frame rate. When the maximum frame rate has already
13441      * been voted for, there's no point in calculating and voting for the frame rate. When
13442      * isDirect is false, then it will return false when the velocity-calculated frame rate
13443      * can be avoided.
13444      * @param isDirect true when the frame rate has been set directly on the View or false if
13445      *                 the calculation is based only on velocity.
13446      */
shouldCheckFrameRate(boolean isDirect)13447     public boolean shouldCheckFrameRate(boolean isDirect) {
13448         return mPreferredFrameRate < MAX_FRAME_RATE
13449                 || (!isDirect && !sToolkitFrameRateVelocityMappingReadOnlyFlagValue
13450                 && mPreferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH);
13451     }
13452 
13453     /**
13454      * Allow Views to vote for the preferred frame rate and compatibility.
13455      * When determining the preferred frame rate value,
13456      * we follow this logic: If no preferred frame rate has been set yet,
13457      * we assign the value of frameRate as the preferred frame rate.
13458      * IF there are multiple frame rates are voted:
13459      * 1. There is a frame rate is a multiple of all other frame rates.
13460      * We choose this frmae rate to be the one to be set.
13461      * 2. There is no frame rate can be a multiple of others
13462      * We set category to HIGH if the maximum frame rate is greater than 60.
13463      * Otherwise, we set category to NORMAL.
13464      *
13465      * Use FRAME_RATE_COMPATIBILITY_AT_LEAST for velocity and FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
13466      * for TextureView video play and user requested frame rate.
13467      *
13468      * @param frameRate the preferred frame rate of a View
13469      * @param frameRateCompatibility the preferred frame rate compatibility of a View
13470      */
13471     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
votePreferredFrameRate(float frameRate, int frameRateCompatibility)13472     public void votePreferredFrameRate(float frameRate, int frameRateCompatibility) {
13473         if (frameRate <= 0) {
13474             return;
13475         }
13476         if (frameRateCompatibility == FRAME_RATE_COMPATIBILITY_AT_LEAST && !mIsPressedGesture) {
13477             mIsTouchBoosting = false;
13478             mIsFrameRateBoosting = false;
13479             if (!sToolkitFrameRateVelocityMappingReadOnlyFlagValue) {
13480                 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
13481                 mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
13482                 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_VELOCITY;
13483                 mFrameRateCategoryView = null;
13484                 mDrawnThisFrame = true;
13485                 return;
13486             }
13487         }
13488         float nextFrameRate;
13489         int nextFrameRateCompatibility;
13490         if (frameRate > mPreferredFrameRate) {
13491             nextFrameRate = frameRate;
13492             nextFrameRateCompatibility = frameRateCompatibility;
13493         } else {
13494             nextFrameRate = mPreferredFrameRate;
13495             nextFrameRateCompatibility = mFrameRateCompatibility;
13496         }
13497 
13498         if (mPreferredFrameRate > 0 && mPreferredFrameRate % frameRate != 0
13499                 && frameRate % mPreferredFrameRate != 0) {
13500             mIsFrameRateConflicted = true;
13501             if (nextFrameRate > 60 && mFrameRateCategoryHighCount != FRAME_RATE_CATEGORY_COUNT) {
13502                 mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
13503                 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_CONFLICTED;
13504                 mFrameRateCategoryView = null;
13505             } else if (mFrameRateCategoryHighCount == 0 && mFrameRateCategoryHighHintCount == 0
13506                     && mFrameRateCategoryNormalCount < FRAME_RATE_CATEGORY_COUNT) {
13507                 mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT;
13508                 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_CONFLICTED;
13509                 mFrameRateCategoryView = null;
13510             }
13511         }
13512 
13513         mPreferredFrameRate = nextFrameRate;
13514         mFrameRateCompatibility = nextFrameRateCompatibility;
13515         mDrawnThisFrame = true;
13516     }
13517 
13518     /**
13519      * Get the value of mPreferredFrameRateCategory
13520      */
13521     @VisibleForTesting
getPreferredFrameRateCategory()13522     public int getPreferredFrameRateCategory() {
13523         return mPreferredFrameRateCategory;
13524     }
13525 
13526     /**
13527      * Get the value of mLastPreferredFrameRateCategory
13528      */
13529     @VisibleForTesting
getLastPreferredFrameRateCategory()13530     public int getLastPreferredFrameRateCategory() {
13531         return mLastPreferredFrameRateCategory;
13532     }
13533 
13534     /**
13535      * Get the value of mPreferredFrameRate
13536      */
13537     @VisibleForTesting
getPreferredFrameRate()13538     public float getPreferredFrameRate() {
13539         return mPreferredFrameRate >= 0 ? mPreferredFrameRate : mLastPreferredFrameRate;
13540     }
13541 
13542     /**
13543      * Get the value of mLastPreferredFrameRate
13544      */
13545     @VisibleForTesting
getLastPreferredFrameRate()13546     public float getLastPreferredFrameRate() {
13547         return mLastPreferredFrameRate;
13548     }
13549 
13550     /**
13551      * Returns whether touch boost is currently enabled.
13552      */
13553     @VisibleForTesting
getIsTouchBoosting()13554     public boolean getIsTouchBoosting() {
13555         return mIsTouchBoosting;
13556     }
13557 
13558     /**
13559      * Get the value of mFrameRateCompatibility
13560      */
13561     @VisibleForTesting
getFrameRateCompatibility()13562     public int getFrameRateCompatibility() {
13563         return mFrameRateCompatibility;
13564     }
13565 
13566     /**
13567      * Get the value of mIsFrameRateBoosting
13568      */
13569     @VisibleForTesting
getIsFrameRateBoosting()13570     public boolean getIsFrameRateBoosting() {
13571         return mIsFrameRateBoosting;
13572     }
13573 
13574     /**
13575      * Get the value of mFrameRateBoostOnTouchEnabled
13576      * Can be used to checked if touch boost is enabled. The default value is true.
13577      */
13578     @VisibleForTesting
getFrameRateBoostOnTouchEnabled()13579     public boolean getFrameRateBoostOnTouchEnabled() {
13580         return mWindowAttributes.getFrameRateBoostOnTouchEnabled();
13581     }
13582 
boostFrameRate(int boostTimeOut)13583     private void boostFrameRate(int boostTimeOut) {
13584         mIsFrameRateBoosting = true;
13585         mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT);
13586         mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT,
13587                 boostTimeOut);
13588     }
13589 
13590     /**
13591      * Set the default back key callback for windowless window, to forward the back key event
13592      * to host app.
13593      * MUST NOT call this method for normal window.
13594      */
setBackKeyCallbackForWindowlessWindow(@onNull Predicate<KeyEvent> callback)13595     void setBackKeyCallbackForWindowlessWindow(@NonNull Predicate<KeyEvent> callback) {
13596         mWindowlessBackKeyCallback = callback;
13597     }
13598 
recordViewPercentage(float percentage)13599     void recordViewPercentage(float percentage) {
13600         if (!Trace.isEnabled()) return;
13601         // Record the largest view of percentage to the display size.
13602         mLargestChildPercentage = Math.max(percentage, mLargestChildPercentage);
13603     }
13604 
13605     /**
13606      * Get the value of mIsFrameRatePowerSavingsBalanced
13607      * Can be used to checked if toolkit dVRR feature is enabled. The default value is true.
13608      */
13609     @VisibleForTesting
isFrameRatePowerSavingsBalanced()13610     public boolean isFrameRatePowerSavingsBalanced() {
13611         if (sToolkitSetFrameRateReadOnlyFlagValue) {
13612             return mWindowAttributes.isFrameRatePowerSavingsBalanced();
13613         }
13614         return true;
13615     }
13616 
13617     /**
13618      * Get the value of mIsFrameRateConflicted
13619      * Can be used to checked if there is a conflict of frame rate votes.
13620      */
13621     @VisibleForTesting
isFrameRateConflicted()13622     public boolean isFrameRateConflicted() {
13623         return mIsFrameRateConflicted;
13624     }
13625 
shouldEnableDvrr()13626     private boolean shouldEnableDvrr() {
13627         // uncomment this when we are ready for enabling dVRR
13628         if (sEnableVrr && sToolkitFrameRateViewEnablingReadOnlyFlagValue) {
13629             return sToolkitSetFrameRateReadOnlyFlagValue && isFrameRatePowerSavingsBalanced();
13630         }
13631         return false;
13632     }
13633 
removeVrrMessages()13634     private void removeVrrMessages() {
13635         mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT);
13636         mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
13637         mHandler.removeMessages(MSG_SURFACE_REPLACED_TIMEOUT);
13638         if (mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) {
13639             mInvalidationIdleMessagePosted = false;
13640             mHandler.removeMessages(MSG_CHECK_INVALIDATION_IDLE);
13641         }
13642     }
13643 
13644     /**
13645      * This function is mainly used for migrating infrequent layer logic
13646      * from SurfaceFlinger to Toolkit.
13647      * The infrequent layer logic includes:
13648      * - NORMAL for infrequent update: FT2-FT1 > 100 && FT3-FT2 > 100.
13649      * - HIGH/NORMAL based on size for frequent update: (FT3-FT2) + (FT2 - FT1) < 100.
13650      * - otherwise, use the previous category value.
13651      */
updateInfrequentCount()13652     private void updateInfrequentCount() {
13653         long currentTimeMillis = mAttachInfo.mDrawingTime;
13654         int timeIntervalMillis =
13655                 (int) Math.min(Integer.MAX_VALUE, currentTimeMillis - mLastUpdateTimeMillis);
13656         mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis;
13657         mMinusOneFrameIntervalMillis = timeIntervalMillis;
13658 
13659         mLastUpdateTimeMillis = currentTimeMillis;
13660         if (mThreadedRendererViews.isEmpty() && timeIntervalMillis + mMinusTwoFrameIntervalMillis
13661                 >= INFREQUENT_UPDATE_INTERVAL_MILLIS) {
13662             int infrequentUpdateCount = mInfrequentUpdateCount;
13663             mInfrequentUpdateCount = infrequentUpdateCount == INFREQUENT_UPDATE_COUNTS
13664                     ? infrequentUpdateCount : infrequentUpdateCount + 1;
13665         } else {
13666             mInfrequentUpdateCount = 0;
13667         }
13668     }
13669 
logColorMode(@ctivityInfo.ColorMode int colorMode, boolean windowStopped)13670     private void logColorMode(@ActivityInfo.ColorMode int colorMode, boolean windowStopped) {
13671         if (mColorModeLastSetMillis == -1 && windowStopped) {
13672             Log.d(TAG, "Skipping stats log for color mode");
13673             return;
13674         }
13675 
13676         long currentTimeMillis = System.currentTimeMillis();
13677 
13678         if (windowStopped) {
13679             HwuiStatsLog.write(HwuiStatsLog.HARDWARE_RENDERER_EVENT, Process.myUid(),
13680                     currentTimeMillis - mColorModeLastSetMillis, mCurrentColorMode);
13681             mColorModeLastSetMillis = -1;
13682         } else {
13683             if (mColorModeLastSetMillis > 0) {
13684                 HwuiStatsLog.write(HwuiStatsLog.HARDWARE_RENDERER_EVENT, Process.myUid(),
13685                         currentTimeMillis - mColorModeLastSetMillis, mCurrentColorMode);
13686             }
13687             mColorModeLastSetMillis = currentTimeMillis;
13688         }
13689 
13690         mCurrentColorMode = colorMode;
13691     }
13692 
13693     private static boolean sProtoLogInitialized = false;
13694 
initializeProtoLogInProcess()13695     private void initializeProtoLogInProcess() {
13696         if (!sProtoLogInitialized) {
13697             ProtoLog.init(ViewProtoLogGroups.ALL_GROUPS);
13698             sProtoLogInitialized = true;
13699         }
13700     }
13701 
preInitBufferAllocator()13702     private void preInitBufferAllocator() {
13703         if (com.android.graphics.hwui.flags.Flags.earlyPreinitBufferAllocator()) {
13704             ThreadedRenderer.preInitBufferAllocator();
13705         }
13706     }
13707 
13708     /**
13709      * @hide
13710      */
getChoreographer()13711     public Choreographer getChoreographer() {
13712         return mChoreographer;
13713     }
13714 }
13715