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.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
20 import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS;
21 import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED;
22 import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND;
23 import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID;
24 import static android.os.Trace.TRACE_TAG_VIEW;
25 import static android.view.Display.DEFAULT_DISPLAY;
26 import static android.view.Display.INVALID_DISPLAY;
27 import static android.view.DragEvent.ACTION_DRAG_LOCATION;
28 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED;
29 import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix;
30 import static android.view.InputDevice.SOURCE_CLASS_NONE;
31 import static android.view.InsetsSource.ID_IME;
32 import static android.view.Surface.FRAME_RATE_CATEGORY_DEFAULT;
33 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
34 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT;
35 import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
36 import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
37 import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
38 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
39 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE;
40 import static android.view.View.FRAME_RATE_CATEGORY_REASON_BOOST;
41 import static android.view.View.FRAME_RATE_CATEGORY_REASON_CONFLICTED;
42 import static android.view.View.FRAME_RATE_CATEGORY_REASON_INTERMITTENT;
43 import static android.view.View.FRAME_RATE_CATEGORY_REASON_INVALID;
44 import static android.view.View.FRAME_RATE_CATEGORY_REASON_LARGE;
45 import static android.view.View.FRAME_RATE_CATEGORY_REASON_REQUESTED;
46 import static android.view.View.FRAME_RATE_CATEGORY_REASON_SMALL;
47 import static android.view.View.FRAME_RATE_CATEGORY_REASON_TOUCH;
48 import static android.view.View.FRAME_RATE_CATEGORY_REASON_UNKNOWN;
49 import static android.view.View.FRAME_RATE_CATEGORY_REASON_VELOCITY;
50 import static android.view.View.MAX_FRAME_RATE;
51 import static android.view.View.PFLAG_DRAW_ANIMATION;
52 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
53 import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
54 import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
55 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
56 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
57 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
58 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
59 import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
60 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
61 import static android.view.ViewRootImplProto.ADDED;
62 import static android.view.ViewRootImplProto.APP_VISIBLE;
63 import static android.view.ViewRootImplProto.CUR_SCROLL_Y;
64 import static android.view.ViewRootImplProto.DISPLAY_ID;
65 import static android.view.ViewRootImplProto.HEIGHT;
66 import static android.view.ViewRootImplProto.IS_ANIMATING;
67 import static android.view.ViewRootImplProto.IS_DRAWING;
68 import static android.view.ViewRootImplProto.LAST_WINDOW_INSETS;
69 import static android.view.ViewRootImplProto.REMOVED;
70 import static android.view.ViewRootImplProto.SCROLL_Y;
71 import static android.view.ViewRootImplProto.SOFT_INPUT_MODE;
72 import static android.view.ViewRootImplProto.VIEW;
73 import static android.view.ViewRootImplProto.VISIBLE_RECT;
74 import static android.view.ViewRootImplProto.WIDTH;
75 import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
76 import static android.view.ViewRootImplProto.WIN_FRAME;
77 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
78 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
79 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
80 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
81 import static android.view.WindowInsetsController.Appearance;
82 import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
83 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
84 import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
85 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
86 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
87 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
88 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
89 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
90 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
91 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
92 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
93 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED;
94 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
95 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
96 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
97 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
98 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
99 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE;
100 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
101 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
102 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
103 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
104 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
105 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
106 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
107 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
108 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS;
109 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
110 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
111 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
112 import static android.view.accessibility.Flags.fixMergedContentChangeEventV2;
113 import static android.view.accessibility.Flags.forceInvertColor;
114 import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle;
115 import static android.view.flags.Flags.addSchandleToVriSurface;
116 import static android.view.flags.Flags.sensitiveContentAppProtection;
117 import static android.view.flags.Flags.toolkitFrameRateFunctionEnablingReadOnly;
118 import static android.view.flags.Flags.toolkitFrameRateTypingReadOnly;
119 import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly;
120 import static android.view.flags.Flags.toolkitFrameRateViewEnablingReadOnly;
121 import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
122 import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
123 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
124 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
125 
126 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
127 import static com.android.window.flags.Flags.activityWindowInfoFlag;
128 import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
129 import static com.android.window.flags.Flags.insetsControlChangedItem;
130 import static com.android.window.flags.Flags.setScPropertiesInClient;
131 import static com.android.window.flags.Flags.windowSessionRelayoutInfo;
132 import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
133 
134 import android.Manifest;
135 import android.accessibilityservice.AccessibilityService;
136 import android.animation.AnimationHandler;
137 import android.animation.LayoutTransition;
138 import android.annotation.AnyThread;
139 import android.annotation.NonNull;
140 import android.annotation.Nullable;
141 import android.annotation.Size;
142 import android.annotation.UiContext;
143 import android.app.ActivityManager;
144 import android.app.ActivityThread;
145 import android.app.ICompatCameraControlCallback;
146 import android.app.ResourcesManager;
147 import android.app.WindowConfiguration;
148 import android.app.compat.CompatChanges;
149 import android.app.servertransaction.WindowStateTransactionItem;
150 import android.compat.annotation.UnsupportedAppUsage;
151 import android.content.ClipData;
152 import android.content.ClipDescription;
153 import android.content.Context;
154 import android.content.pm.ActivityInfo;
155 import android.content.pm.PackageManager;
156 import android.content.res.CompatibilityInfo;
157 import android.content.res.Configuration;
158 import android.content.res.Resources;
159 import android.content.res.TypedArray;
160 import android.database.ContentObserver;
161 import android.graphics.BLASTBufferQueue;
162 import android.graphics.Canvas;
163 import android.graphics.Color;
164 import android.graphics.ForceDarkType;
165 import android.graphics.FrameInfo;
166 import android.graphics.HardwareRenderer;
167 import android.graphics.HardwareRenderer.FrameDrawingCallback;
168 import android.graphics.HardwareRendererObserver;
169 import android.graphics.Matrix;
170 import android.graphics.Paint;
171 import android.graphics.PixelFormat;
172 import android.graphics.Point;
173 import android.graphics.PointF;
174 import android.graphics.PorterDuff;
175 import android.graphics.RecordingCanvas;
176 import android.graphics.Rect;
177 import android.graphics.RectF;
178 import android.graphics.Region;
179 import android.graphics.RenderNode;
180 import android.graphics.drawable.Drawable;
181 import android.graphics.drawable.GradientDrawable;
182 import android.hardware.SyncFence;
183 import android.hardware.display.DisplayManager;
184 import android.hardware.display.DisplayManager.DisplayListener;
185 import android.hardware.display.DisplayManagerGlobal;
186 import android.hardware.input.InputManagerGlobal;
187 import android.hardware.input.InputSettings;
188 import android.media.AudioManager;
189 import android.os.Binder;
190 import android.os.Build;
191 import android.os.Bundle;
192 import android.os.Debug;
193 import android.os.Handler;
194 import android.os.IBinder;
195 import android.os.Looper;
196 import android.os.Message;
197 import android.os.ParcelFileDescriptor;
198 import android.os.Process;
199 import android.os.RemoteException;
200 import android.os.ServiceManager;
201 import android.os.StrictMode;
202 import android.os.SystemClock;
203 import android.os.SystemProperties;
204 import android.os.Trace;
205 import android.os.UserHandle;
206 import android.provider.Settings;
207 import android.sysprop.DisplayProperties;
208 import android.sysprop.ViewProperties;
209 import android.text.TextUtils;
210 import android.util.AndroidRuntimeException;
211 import android.util.DisplayMetrics;
212 import android.util.EventLog;
213 import android.util.IndentingPrintWriter;
214 import android.util.Log;
215 import android.util.LongArray;
216 import android.util.MergedConfiguration;
217 import android.util.Slog;
218 import android.util.SparseArray;
219 import android.util.TimeUtils;
220 import android.util.TypedValue;
221 import android.util.proto.ProtoOutputStream;
222 import android.view.InputDevice.InputSourceClass;
223 import android.view.Surface.OutOfResourcesException;
224 import android.view.SurfaceControl.Transaction;
225 import android.view.SurfaceControl.TransactionStats;
226 import android.view.View.AttachInfo;
227 import android.view.View.FocusDirection;
228 import android.view.View.MeasureSpec;
229 import android.view.Window.OnContentApplyWindowInsetsListener;
230 import android.view.WindowInsets.Type;
231 import android.view.WindowInsets.Type.InsetsType;
232 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
233 import android.view.accessibility.AccessibilityEvent;
234 import android.view.accessibility.AccessibilityInteractionClient;
235 import android.view.accessibility.AccessibilityManager;
236 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
237 import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
238 import android.view.accessibility.AccessibilityNodeIdManager;
239 import android.view.accessibility.AccessibilityNodeInfo;
240 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
241 import android.view.accessibility.AccessibilityNodeProvider;
242 import android.view.accessibility.AccessibilityWindowAttributes;
243 import android.view.accessibility.AccessibilityWindowInfo;
244 import android.view.accessibility.IAccessibilityEmbeddedConnection;
245 import android.view.accessibility.IAccessibilityInteractionConnection;
246 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
247 import android.view.animation.AccelerateDecelerateInterpolator;
248 import android.view.animation.Interpolator;
249 import android.view.autofill.AutofillManager;
250 import android.view.contentcapture.ContentCaptureManager;
251 import android.view.contentcapture.ContentCaptureSession;
252 import android.view.flags.Flags;
253 import android.view.inputmethod.ImeTracker;
254 import android.view.inputmethod.InputMethodManager;
255 import android.widget.Scroller;
256 import android.window.ActivityWindowInfo;
257 import android.window.BackEvent;
258 import android.window.ClientWindowFrames;
259 import android.window.CompatOnBackInvokedCallback;
260 import android.window.InputTransferToken;
261 import android.window.OnBackAnimationCallback;
262 import android.window.OnBackInvokedCallback;
263 import android.window.OnBackInvokedDispatcher;
264 import android.window.ScreenCapture;
265 import android.window.SurfaceSyncGroup;
266 import android.window.WindowOnBackInvokedDispatcher;
267 
268 import com.android.internal.R;
269 import com.android.internal.annotations.GuardedBy;
270 import com.android.internal.annotations.VisibleForTesting;
271 import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
272 import com.android.internal.inputmethod.ImeTracing;
273 import com.android.internal.inputmethod.InputMethodDebug;
274 import com.android.internal.os.IResultReceiver;
275 import com.android.internal.os.SomeArgs;
276 import com.android.internal.policy.DecorView;
277 import com.android.internal.policy.PhoneFallbackEventHandler;
278 import com.android.internal.util.FastPrintWriter;
279 import com.android.internal.view.BaseSurfaceHolder;
280 import com.android.internal.view.RootViewSurfaceTaker;
281 import com.android.internal.view.SurfaceCallbackHelper;
282 import com.android.modules.expresslog.Counter;
283 
284 import libcore.io.IoUtils;
285 
286 import java.io.FileOutputStream;
287 import java.io.IOException;
288 import java.io.OutputStream;
289 import java.io.PrintWriter;
290 import java.io.StringWriter;
291 import java.lang.ref.WeakReference;
292 import java.util.ArrayDeque;
293 import java.util.ArrayList;
294 import java.util.HashSet;
295 import java.util.List;
296 import java.util.Objects;
297 import java.util.OptionalInt;
298 import java.util.Queue;
299 import java.util.concurrent.CountDownLatch;
300 import java.util.concurrent.Executor;
301 import java.util.function.Consumer;
302 import java.util.function.Predicate;
303 /**
304  * The top of a view hierarchy, implementing the needed protocol between View
305  * and the WindowManager.  This is for the most part an internal implementation
306  * detail of {@link WindowManagerGlobal}.
307  *
308  * {@hide}
309  */
310 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
311 public final class ViewRootImpl implements ViewParent,
312         View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
313         AttachedSurfaceControl {
314     private static final String TAG = "ViewRootImpl";
315     private static final boolean DBG = false;
316     private static final boolean LOCAL_LOGV = false;
317     /** @noinspection PointlessBooleanExpression*/
318     private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
319     private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
320     private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
321     private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
322     private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
323     private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
324     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
325     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
326     private static final boolean DEBUG_FPS = false;
327     private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
328     private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
329     private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV;
330     private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV;
331     private static final boolean DEBUG_TOUCH_NAVIGATION = false || LOCAL_LOGV;
332     private static final boolean DEBUG_BLAST = false || LOCAL_LOGV;
333     private static final boolean DEBUG_SENSITIVE_CONTENT = false || LOCAL_LOGV;
334     private static final int LOGTAG_INPUT_FOCUS = 62001;
335     private static final int LOGTAG_VIEWROOT_DRAW_EVENT = 60004;
336 
337     /**
338      * Set to false if we do not want to use the multi threaded renderer even though
339      * threaded renderer (aka hardware renderering) is used. Note that by disabling
340      * this, WindowCallbacks will not fire.
341      */
342     private static final boolean MT_RENDERER_AVAILABLE = true;
343 
344     /**
345      * Whether or not to report end-to-end input latency. Can be disabled temporarily as a
346      * risk mitigation against potential jank caused by acquiring a weak reference
347      * per frame.
348      */
349     private static final boolean ENABLE_INPUT_LATENCY_TRACKING = true;
350 
351     /**
352      * Controls whether to use the new oneway performHapticFeedback call. This returns
353      * true in a few more conditions, but doesn't affect which haptics happen. Notably, it
354      * makes the call to performHapticFeedback non-blocking, which reduces potential UI jank.
355      * This is intended as a temporary flag, ultimately becoming permanently 'true'.
356      */
357     private static final boolean USE_ASYNC_PERFORM_HAPTIC_FEEDBACK = true;
358 
359     /**
360      * Whether the client (system UI) is handling the transient gesture and the corresponding
361      * animation.
362      * @hide
363      */
364     public static final boolean CLIENT_TRANSIENT =
365             SystemProperties.getBoolean("persist.wm.debug.client_transient", false);
366 
367     /**
368      * Whether the client (system UI) is handling the immersive confirmation window. If
369      * {@link CLIENT_TRANSIENT} is set to true, the immersive confirmation window will always be the
370      * client instance and this flag will be ignored. Otherwise, the immersive confirmation window
371      * can be switched freely by this flag.
372      * @hide
373      */
374     public static final boolean CLIENT_IMMERSIVE_CONFIRMATION =
375             SystemProperties.getBoolean("persist.wm.debug.client_immersive_confirmation", false);
376 
377     /**
378      * Set this system property to true to force the view hierarchy to render
379      * at 60 Hz. This can be used to measure the potential framerate.
380      */
381     private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
382 
383     /**
384      * Maximum time we allow the user to roll the trackball enough to generate
385      * a key event, before resetting the counters.
386      */
387     static final int MAX_TRACKBALL_DELAY = 250;
388 
389     /**
390      * Initial value for {@link #mContentCaptureEnabled}.
391      */
392     private static final int CONTENT_CAPTURE_ENABLED_NOT_CHECKED = 0;
393 
394     /**
395      * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code true}.
396      */
397     private static final int CONTENT_CAPTURE_ENABLED_TRUE = 1;
398 
399     /**
400      * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code false}.
401      */
402     private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2;
403 
404     /**
405      * Maximum time to wait for {@link View#dispatchScrollCaptureSearch} to complete.
406      */
407     private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500;
408 
409     private static final int UNSET_SYNC_ID = -1;
410 
411     private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100;
412     private static final int INFREQUENT_UPDATE_COUNTS = 2;
413 
414     /**
415      * The {@link #intermittentUpdateState()} value when the ViewRootImpl isn't intermittent.
416      */
417     public static final int INTERMITTENT_STATE_NOT_INTERMITTENT = 1;
418 
419     /**
420      * The {@link #intermittentUpdateState()} value when the ViewRootImpl is transitioning either
421      * to or from intermittent to not intermittent. This indicates that the frame rate shouldn't
422      * change.
423      */
424     public static final int INTERMITTENT_STATE_IN_TRANSITION = -1;
425 
426     /**
427      * The {@link #intermittentUpdateState()} value when the ViewRootImpl is intermittent.
428      */
429     public static final int INTERMITTENT_STATE_INTERMITTENT = 0;
430 
431     /**
432      * Minimum time to wait before reporting changes to keep clear areas.
433      */
434     private static final int KEEP_CLEAR_AREA_REPORT_RATE_MILLIS = 100;
435 
436     private static final long NANOS_PER_SEC = 1000000000;
437 
438     // If the ViewRootImpl has been idle for more than 750ms, clear the preferred
439     // frame rate category and frame rate.
440     private static final int IDLE_TIME_MILLIS = 750;
441 
442     private static final long NANOS_PER_MILLI = 1_000_000;
443 
444     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
445     static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
446 
447     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<>();
448     static boolean sFirstDrawComplete = false;
449 
450     private ArrayList<OnBufferTransformHintChangedListener> mTransformHintListeners =
451             new ArrayList<>();
452     private @SurfaceControl.BufferTransform
453             int mPreviousTransformHint = SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
454     /**
455      * The top level {@link OnBackInvokedDispatcher}.
456      */
457     private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
458     /**
459      * Compatibility {@link OnBackInvokedCallback} that dispatches KEYCODE_BACK events
460      * to view root for apps using legacy back behavior.
461      */
462     private CompatOnBackInvokedCallback mCompatOnBackInvokedCallback;
463 
464     @Nullable
465     private ContentObserver mForceInvertObserver;
466 
467     private static final int INVALID_VALUE = Integer.MIN_VALUE;
468     private int mForceInvertEnabled = INVALID_VALUE;
469     /**
470      * Callback for notifying about global configuration changes.
471      */
472     public interface ConfigChangedCallback {
473 
474         /** Notifies about global config change. */
onConfigurationChanged(Configuration globalConfig)475         void onConfigurationChanged(Configuration globalConfig);
476     }
477 
478     private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>();
479 
480     /**
481      * Callback for notifying activities.
482      */
483     public interface ActivityConfigCallback {
484         /**
485          * Notifies about override config change and/or move to different display.
486          * @param overrideConfig New override config to apply to activity.
487          * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed.
488          */
onConfigurationChanged(@onNull Configuration overrideConfig, int newDisplayId)489         default void onConfigurationChanged(@NonNull Configuration overrideConfig,
490                 int newDisplayId) {
491             // Must override one of the #onConfigurationChanged.
492             throw new IllegalStateException("Not implemented");
493         }
494 
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          * @param activityWindowInfo New ActivityWindowInfo to apply to activity.
500          */
onConfigurationChanged(@onNull Configuration overrideConfig, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo)501         default void onConfigurationChanged(@NonNull Configuration overrideConfig,
502                 int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) {
503             onConfigurationChanged(overrideConfig, newDisplayId);
504         }
505 
506         /**
507          * Notify the corresponding activity about the request to show or hide a camera compat
508          * control for stretched issues in the viewfinder.
509          *
510          * @param showControl Whether the control should be shown or hidden.
511          * @param transformationApplied Whether the treatment is already applied.
512          * @param callback The callback executed when the user clicks on a control.
513          */
requestCompatCameraControl(boolean showControl, boolean transformationApplied, ICompatCameraControlCallback callback)514         void requestCompatCameraControl(boolean showControl, boolean transformationApplied,
515                 ICompatCameraControlCallback callback);
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      * This list must only be modified by the main thread.
550      */
551     final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
552     @UnsupportedAppUsage
553     @UiContext
554     public final Context mContext;
555 
556     @UnsupportedAppUsage
557     final IWindowSession mWindowSession;
558     @NonNull Display mDisplay;
559     final String mBasePackageName;
560 
561     // If we would like to keep a particular eye on the corresponding package.
562     final boolean mExtraDisplayListenerLogging;
563 
564     final int[] mTmpLocation = new int[2];
565 
566     final TypedValue mTmpValue = new TypedValue();
567 
568     final Thread mThread;
569 
570     final WindowLeaked mLocation;
571 
572     public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
573 
574     final W mWindow;
575 
576     final IBinder mLeashToken;
577 
578     final int mTargetSdkVersion;
579 
580     @UnsupportedAppUsage
581     View mView;
582 
583     View mAccessibilityFocusedHost;
584     // Accessibility-focused virtual view. The bounds and sourceNodeId of
585     // mAccessibilityFocusedVirtualView is up-to-date while other fields may be stale.
586     AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
587 
588     // True if the window currently has pointer capture enabled.
589     boolean mPointerCapture;
590 
591     int mViewVisibility;
592     boolean mAppVisible = true;
593     // For recents to freeform transition we need to keep drawing after the app receives information
594     // that it became invisible. This will ignore that information and depend on the decor view
595     // visibility to control drawing. The decor view visibility will get adjusted when the app get
596     // stopped and that's when the app will stop drawing further frames.
597     private boolean mForceDecorViewVisibility = false;
598     // Used for tracking app visibility updates separately in case we get double change. This will
599     // make sure that we always call relayout for the corresponding window.
600     private boolean mAppVisibilityChanged;
601     int mOrigWindowType = -1;
602 
603     // Set to true if the owner of this window is in the stopped state,
604     // so the window should no longer be active.
605     @UnsupportedAppUsage
606     boolean mStopped = false;
607 
608     // Set to true if the owner of this window is in ambient mode,
609     // which means it won't receive input events.
610     boolean mIsAmbientMode = false;
611 
612     // Set to true to stop input during an Activity Transition.
613     boolean mPausedForTransition = false;
614 
615     SurfaceHolder.Callback2 mSurfaceHolderCallback;
616     BaseSurfaceHolder mSurfaceHolder;
617     boolean mIsCreating;
618     boolean mDrawingAllowed;
619 
620     final Region mTransparentRegion;
621     final Region mPreviousTransparentRegion;
622 
623     Region mTouchableRegion;
624     Region mPreviousTouchableRegion;
625 
626     private int mMeasuredWidth;
627     private int mMeasuredHeight;
628 
629     // This indicates that we've already known the window size but without measuring the views.
630     // If this is true, we must measure the views before laying out them.
631     private boolean mViewMeasureDeferred;
632 
633     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
634     int mWidth;
635     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
636     int mHeight;
637     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
638     private Rect mDirty;
639     public boolean mIsAnimating;
640 
641     private boolean mUseMTRenderer;
642     private boolean mPendingDragResizing;
643     private boolean mDragResizing;
644     private boolean mInvalidateRootRequested;
645     private int mCanvasOffsetX;
646     private int mCanvasOffsetY;
647     CompatibilityInfo.Translator mTranslator;
648 
649     @UnsupportedAppUsage
650     final View.AttachInfo mAttachInfo;
651     final SystemUiVisibilityInfo mCompatibleVisibilityInfo;
652     int mDispatchedSystemUiVisibility;
653     int mDispatchedSystemBarAppearance;
654     InputQueue.Callback mInputQueueCallback;
655     InputQueue mInputQueue;
656     @UnsupportedAppUsage
657     FallbackEventHandler mFallbackEventHandler;
658     final Choreographer mChoreographer;
659     protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo();
660     private final InputEventAssigner mInputEventAssigner = new InputEventAssigner();
661 
662     // Whether to draw this surface as DISPLAY_DECORATION.
663     boolean mDisplayDecorationCached = false;
664 
665     // Is the stylus pointer icon enabled
666     private final boolean mIsStylusPointerIconEnabled;
667 
668     // VRR check for number of infrequent updates
669     private int mInfrequentUpdateCount = 0;
670     // VRR time of last update
671     private long mLastUpdateTimeMillis = 0;
672     // VRR interval since the previous
673     private int mMinusOneFrameIntervalMillis = 0;
674     // VRR interval between the previous and the frame before
675     private int mMinusTwoFrameIntervalMillis = 0;
676     // VRR has the invalidation idle message been posted?
677     private boolean mInvalidationIdleMessagePosted = false;
678     // VRR: List of all Views that are animating with the threaded render
679     private ArrayList<View> mThreadedRendererViews = new ArrayList();
680 
681     /**
682      * Update the Choreographer's FrameInfo object with the timing information for the current
683      * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next
684      * frame.
685      * @return the updated FrameInfo object
686      */
getUpdatedFrameInfo()687     protected @NonNull FrameInfo getUpdatedFrameInfo() {
688         // Since Choreographer is a thread-local singleton while we can have multiple
689         // ViewRootImpl's, populate the frame information from the current viewRootImpl before
690         // starting the draw
691         FrameInfo frameInfo = mChoreographer.mFrameInfo;
692         mViewFrameInfo.populateFrameInfo(frameInfo);
693         mViewFrameInfo.reset();
694         mInputEventAssigner.notifyFrameProcessed();
695         return frameInfo;
696     }
697 
698     // used in relayout to get SurfaceControl size
699     // for BLAST adapter surface setup
700     private final Point mSurfaceSize = new Point();
701     private final Point mLastSurfaceSize = new Point();
702 
703     private final Rect mVisRect = new Rect(); // used to retrieve visible rect of focused view.
704     private final Rect mTempRect = new Rect();
705 
706     private final WindowLayout mWindowLayout;
707 
708     // This is used to reduce the race between window focus changes being dispatched from
709     // the window manager and input events coming through the input system.
710     @GuardedBy("this")
711     boolean mWindowFocusChanged;
712     @GuardedBy("this")
713     boolean mUpcomingWindowFocus;
714     @GuardedBy("this")
715     boolean mUpcomingInTouchMode;
716     // While set, allow this VRI to handle back key without drop it.
717     private boolean mProcessingBackKey;
718     /**
719      * Compatibility {@link OnBackInvokedCallback} for windowless window, to forward the back
720      * key event host app.
721      */
722     private Predicate<KeyEvent> mWindowlessBackKeyCallback;
723 
724     public boolean mTraversalScheduled;
725     int mTraversalBarrier;
726     boolean mWillDrawSoon;
727     /** Set to true while in performTraversals for detecting when die(true) is called from internal
728      * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
729     boolean mIsInTraversal;
730     boolean mApplyInsetsRequested;
731     boolean mLayoutRequested;
732     boolean mFirst;
733 
734     @Nullable
735     int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
736     boolean mPerformContentCapture;
737 
738     boolean mReportNextDraw;
739     /** Set only while mReportNextDraw=true, indicating the last reason that was triggered */
740     String mLastReportNextDrawReason;
741     /** The reaason the last call to performDraw() returned false */
742     String mLastPerformDrawSkippedReason;
743     /** The reason the last call to performTraversals() returned without drawing */
744     String mLastPerformTraversalsSkipDrawReason;
745     /** The state of the WMS requested sync, if one is in progress. Can be one of the states
746      * below. */
747     int mWmsRequestSyncGroupState;
748 
749     // The possible states of the WMS requested sync, see createSyncIfNeeded()
750     private static final int WMS_SYNC_NONE = 0;
751     private static final int WMS_SYNC_PENDING = 1;
752     private static final int WMS_SYNC_RETURNED = 2;
753     private static final int WMS_SYNC_MERGED = 3;
754 
755     /**
756      * Set whether the requested SurfaceSyncGroup should sync the buffer. When set to true, VRI will
757      * create a sync transaction with BBQ and send the resulting buffer back to the
758      * SurfaceSyncGroup. If false, VRI will not try to sync a buffer in BBQ, but still report when a
759      * draw occurred.
760      */
761     private boolean mSyncBuffer = false;
762 
763     /**
764      * Flag to determine whether the client needs to check with WMS if it can draw. WMS will notify
765      * the client that it can't draw if we're still in the middle of a sync set that includes this
766      * window. Once the sync is complete, the window can resume drawing. This is to ensure we don't
767      * deadlock the client by trying to request draws when there may not be any buffers available.
768      */
769     private boolean mCheckIfCanDraw = false;
770 
771     private boolean mWasLastDrawCanceled;
772     private boolean mLastTraversalWasVisible = true;
773     private boolean mLastDrawScreenOff;
774 
775     private boolean mDrewOnceForSync = false;
776 
777     int mSyncSeqId = 0;
778     int mLastSyncSeqId = 0;
779 
780     private boolean mUpdateSurfaceNeeded;
781     boolean mFullRedrawNeeded;
782     boolean mNewSurfaceNeeded;
783     boolean mForceNextWindowRelayout;
784     CountDownLatch mWindowDrawCountDown;
785 
786     /**
787      * Value to indicate whether someone has called {@link #applyTransactionOnDraw}before the
788      * traversal. This is used to determine whether a RT frame callback needs to be registered to
789      * merge the transaction with the next frame. The value is cleared after the VRI has run a
790      * traversal pass.
791      */
792     boolean mHasPendingTransactions;
793     /**
794      * The combined transactions passed in from {@link #applyTransactionOnDraw}
795      */
796     private Transaction mPendingTransaction = new Transaction();
797 
798 
799     boolean mIsDrawing;
800     int mLastSystemUiVisibility;
801     int mClientWindowLayoutFlags;
802 
803     // Pool of queued input events.
804     private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
805     private QueuedInputEvent mQueuedInputEventPool;
806     private int mQueuedInputEventPoolSize;
807 
808     /* Input event queue.
809      * Pending input events are input events waiting to be delivered to the input stages
810      * and handled by the application.
811      */
812     QueuedInputEvent mPendingInputEventHead;
813     QueuedInputEvent mPendingInputEventTail;
814     int mPendingInputEventCount;
815     boolean mProcessInputEventsScheduled;
816     boolean mUnbufferedInputDispatch;
817     @InputSourceClass
818     int mUnbufferedInputSource = SOURCE_CLASS_NONE;
819 
820     String mPendingInputEventQueueLengthCounterName = "pq";
821 
822     InputStage mFirstInputStage;
823     InputStage mFirstPostImeInputStage;
824     InputStage mSyntheticInputStage;
825 
826     private final UnhandledKeyManager mUnhandledKeyManager = new UnhandledKeyManager();
827 
828     boolean mWindowAttributesChanged = false;
829 
830     // These can be accessed by any thread, must be protected with a lock.
831     // Surface can never be reassigned or cleared (use Surface.clear()).
832     @UnsupportedAppUsage
833     public final Surface mSurface = new Surface();
834     private final SurfaceControl mSurfaceControl = new SurfaceControl();
835 
836     private BLASTBufferQueue mBlastBufferQueue;
837 
838     private final HdrRenderState mHdrRenderState = new HdrRenderState(this);
839 
840     /**
841      * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to
842      * the surface insets. This surface is created only if a client requests it via
843      * {@link #updateAndGetBoundsLayer(Transaction)}. By parenting to this bounds surface, child
844      * surfaces can ensure they do not draw into the surface inset region set by the parent window.
845      */
846     private SurfaceControl mBoundsLayer;
847     private final SurfaceSession mSurfaceSession = new SurfaceSession();
848     private final Transaction mTransaction = new Transaction();
849     private final Transaction mFrameRateTransaction = new Transaction();
850 
851     @UnsupportedAppUsage
852     boolean mAdded;
853     boolean mAddedTouchMode;
854 
855     /**
856      * It usually keeps the latest layout result from {@link IWindow#resized} or
857      * {@link IWindowSession#relayout}.
858      */
859     private final ClientWindowFrames mTmpFrames = new ClientWindowFrames();
860 
861     // These are accessed by multiple threads.
862     final Rect mWinFrame; // frame given by window manager.
863     private final Rect mLastLayoutFrame;
864     Rect mOverrideInsetsFrame;
865 
866     final Rect mPendingBackDropFrame = new Rect();
867 
868     boolean mPendingAlwaysConsumeSystemBars;
869     private int mRelayoutSeq;
870     private final Rect mWinFrameInScreen = new Rect();
871     private final InsetsState mTempInsets = new InsetsState();
872     private final InsetsSourceControl.Array mTempControls = new InsetsSourceControl.Array();
873     private final WindowConfiguration mTempWinConfig = new WindowConfiguration();
874     private float mInvCompatScale = 1f;
875     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
876             = new ViewTreeObserver.InternalInsetsInfo();
877 
878     private WindowInsets mLastWindowInsets;
879 
880     // Insets types hidden by legacy window flags or system UI flags.
881     private @InsetsType int mTypesHiddenByFlags = 0;
882 
883     /** Last applied configuration obtained from resources. */
884     private final Configuration mLastConfigurationFromResources = new Configuration();
885     /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */
886     private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration();
887     /** Configurations waiting to be applied. */
888     private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration();
889 
890     /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */
891     @Nullable
892     private ActivityWindowInfo mPendingActivityWindowInfo;
893     /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */
894     @Nullable
895     private ActivityWindowInfo mLastReportedActivityWindowInfo;
896 
897     boolean mScrollMayChange;
898     @SoftInputModeFlags
899     int mSoftInputMode;
900     @UnsupportedAppUsage
901     WeakReference<View> mLastScrolledFocus;
902     int mScrollY;
903     int mCurScrollY;
904     Scroller mScroller;
905     static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
906     private ArrayList<LayoutTransition> mPendingTransitions;
907 
908     final ViewConfiguration mViewConfiguration;
909 
910     /* Drag/drop */
911     ClipDescription mDragDescription;
912     View mCurrentDragView;
913     View mStartedDragViewForA11y;
914     volatile Object mLocalDragState;
915     final PointF mDragPoint = new PointF();
916     final PointF mLastTouchPoint = new PointF();
917     int mLastTouchSource;
918     int mLastTouchDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
919     int mLastTouchPointerId;
920     /** Tracks last {@link MotionEvent#getToolType(int)} with {@link MotionEvent#ACTION_UP}. **/
921     private int mLastClickToolType;
922 
923     private boolean mProfileRendering;
924     private Choreographer.FrameCallback mRenderProfiler;
925     private boolean mRenderProfilingEnabled;
926 
927     // Variables to track frames per second, enabled via DEBUG_FPS flag
928     private long mFpsStartTime = -1;
929     private long mFpsPrevTime = -1;
930     private int mFpsNumFrames;
931 
932     private boolean mInsetsAnimationRunning;
933 
934     private long mPreviousFrameDrawnTime = -1;
935     // The largest view size percentage to the display size. Used on trace to collect metric.
936     private float mLargestChildPercentage = 0.0f;
937     // The reason the category was changed.
938     private int mFrameRateCategoryChangeReason = 0;
939     private String mFrameRateCategoryView;
940 
941     /**
942      * The resolved pointer icon requested by this window.
943      * A null value indicates the resolved pointer icon has not yet been calculated.
944      */
945     @Nullable
946     private PointerIcon mResolvedPointerIcon = null;
947 
948     /**
949      * see {@link #playSoundEffect(int)}
950      */
951     AudioManager mAudioManager;
952 
953     final AccessibilityManager mAccessibilityManager;
954 
955     AccessibilityInteractionController mAccessibilityInteractionController;
956 
957     Paint mRoundDisplayAccessibilityHighlightPaint;
958 
959     final AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager =
960             new AccessibilityInteractionConnectionManager();
961     final HighContrastTextManager mHighContrastTextManager;
962 
963     SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
964 
965     HashSet<View> mTempHashSet;
966 
967     private final int mDensity;
968     private final int mNoncompatDensity;
969 
970     private boolean mInLayout = false;
971     ArrayList<View> mLayoutRequesters = new ArrayList<View>();
972     boolean mHandlingLayoutInLayoutRequest = false;
973 
974     private int mViewLayoutDirectionInitial;
975 
976     /** Set to true once doDie() has been called. */
977     private boolean mRemoved;
978 
979     private boolean mNeedsRendererSetup;
980 
981     private final InputEventCompatProcessor mInputCompatProcessor;
982 
983     /**
984      * Consistency verifier for debugging purposes.
985      */
986     protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
987             InputEventConsistencyVerifier.isInstrumentationEnabled() ?
988                     new InputEventConsistencyVerifier(this, 0) : null;
989 
990     private final InsetsController mInsetsController;
991     private final ImeBackAnimationController mImeBackAnimationController;
992     private final ImeFocusController mImeFocusController;
993 
994     private boolean mIsSurfaceOpaque;
995 
996     private final BackgroundBlurDrawable.Aggregator mBlurRegionAggregator =
997             new BackgroundBlurDrawable.Aggregator(this);
998 
999     /**
1000      * @return {@link ImeFocusController} for this instance.
1001      */
1002     @NonNull
getImeFocusController()1003     public ImeFocusController getImeFocusController() {
1004         return mImeFocusController;
1005     }
1006 
1007     private final ViewRootRectTracker mGestureExclusionTracker =
1008             new ViewRootRectTracker(v -> v.getSystemGestureExclusionRects());
1009     private final ViewRootRectTracker mKeepClearRectsTracker =
1010             new ViewRootRectTracker(v -> v.collectPreferKeepClearRects());
1011     private final ViewRootRectTracker mUnrestrictedKeepClearRectsTracker =
1012             new ViewRootRectTracker(v -> v.collectUnrestrictedPreferKeepClearRects());
1013     private boolean mHasPendingKeepClearAreaChange;
1014     private Rect mKeepClearAccessibilityFocusRect;
1015 
1016     private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
1017 
1018     private final ISensitiveContentProtectionManager mSensitiveContentProtectionService;
1019 
1020     static final class SystemUiVisibilityInfo {
1021         int globalVisibility;
1022         int localValue;
1023         int localChanges;
1024     }
1025 
1026     private final HandwritingInitiator mHandwritingInitiator;
1027 
1028     /**
1029      * Used by InputMethodManager.
1030      * @hide
1031      */
1032     @NonNull
getHandwritingInitiator()1033     public HandwritingInitiator getHandwritingInitiator() {
1034         return mHandwritingInitiator;
1035     }
1036 
1037     /**
1038      * A SurfaceSyncGroup that is created when WMS requested to sync the buffer
1039      */
1040     private SurfaceSyncGroup mWmsRequestSyncGroup;
1041 
1042     /**
1043      * The SurfaceSyncGroup that represents the active VRI SurfaceSyncGroup. This is non null if
1044      * anyone requested the SurfaceSyncGroup for this VRI to ensure that anyone trying to sync with
1045      * this VRI are collected together. The SurfaceSyncGroup is cleared when the VRI draws since
1046      * that is the stop point where all changes are have been applied. A new SurfaceSyncGroup is
1047      * created after that point when something wants to sync VRI again.
1048      */
1049     private SurfaceSyncGroup mActiveSurfaceSyncGroup;
1050 
1051 
1052     private final Object mPreviousSyncSafeguardLock = new Object();
1053 
1054     /**
1055      * Wraps the TransactionCommitted callback for the previous SSG so it can be added to the next
1056      * SSG if started before previous has completed.
1057      */
1058     @GuardedBy("mPreviousSyncSafeguardLock")
1059     private SurfaceSyncGroup mPreviousSyncSafeguard;
1060 
1061     private static final Object sSyncProgressLock = new Object();
1062     // The count needs to be static since it's used to enable or disable RT animations which is
1063     // done at a global level per process. If any VRI syncs are in progress, we can't enable RT
1064     // animations until all are done.
1065     private static int sNumSyncsInProgress = 0;
1066 
1067     private int mNumPausedForSync = 0;
1068 
1069     private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
1070 
1071     private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
1072 
1073     /**
1074      * Increment this value when the surface has been replaced.
1075      */
1076     private int mSurfaceSequenceId = 0;
1077 
1078     private boolean mRelayoutRequested;
1079 
1080     /**
1081      * Whether sandboxing of {@link android.view.View#getBoundsOnScreen},
1082      * {@link android.view.View#getLocationOnScreen(int[])},
1083      * {@link android.view.View#getWindowDisplayFrame} and
1084      * {@link android.view.View#getWindowVisibleDisplayFrame}
1085      * within Activity bounds is enabled for the current application.
1086      */
1087     private final boolean mViewBoundsSandboxingEnabled;
1088 
1089     private AccessibilityWindowAttributes mAccessibilityWindowAttributes;
1090 
1091     /*
1092      * for Variable Refresh Rate project
1093      */
1094 
1095     // The preferred frame rate category of the view that
1096     // could be updated on a frame-by-frame basis.
1097     private int mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT;
1098     // The preferred frame rate category of the last frame that
1099     // could be used to lower frame rate after touch boost
1100     private int mLastPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT;
1101     // The preferred frame rate of the view that is mainly used for
1102     // touch boosting, view velocity handling, and TextureView.
1103     private float mPreferredFrameRate = 0;
1104     // The last preferred frame rate of the view that is mainly used to
1105     // track the difference between the current preferred frame rate and the previous value.
1106     private float mLastPreferredFrameRate = 0;
1107     // Used to check if it is in the frame rate boosting period.
1108     private boolean mIsFrameRateBoosting = false;
1109     // Used to check if it is in touch boosting period.
1110     private boolean mIsTouchBoosting = false;
1111     private boolean mDrawnThisFrame = false;
1112     // Used to check if there is a conflict between different frame rate voting.
1113     // Take 24 and 30 as an example, 24 is not a divisor of 30.
1114     // We consider there is a conflict.
1115     private boolean mIsFrameRateConflicted = false;
1116     // Used to set frame rate compatibility.
1117     @Surface.FrameRateCompatibility int mFrameRateCompatibility =
1118             FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
1119     // time for touch boost period.
1120     private static final int FRAME_RATE_TOUCH_BOOST_TIME = 3000;
1121     // Timeout for the other frame rate boosts other than touch boost.
1122     private static final int FRAME_RATE_BOOST_TIME = 3000;
1123     // time for evaluating the interval between current time and
1124     // the time when frame rate was set previously.
1125     private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100;
1126 
1127     /*
1128      * The variables below are used to update frame rate category
1129      */
1130     private static final int FRAME_RATE_CATEGORY_COUNT = 5;
1131     private int mFrameRateCategoryHighCount = 0;
1132     private int mFrameRateCategoryHighHintCount = 0;
1133     private int mFrameRateCategoryNormalCount = 0;
1134     private int mFrameRateCategoryLowCount = 0;
1135 
1136     /*
1137      * the variables below are used to determine whther a dVRR feature should be enabled
1138      */
1139 
1140     /**
1141      * A temporary object used so relayoutWindow can return the latest SyncSeqId
1142      * system. The SyncSeqId system was designed to work without synchronous relayout
1143      * window, and actually synchronous relayout window presents a problem.  We could have
1144      * a sequence like this:
1145      *    1. We send MSG_RESIZED to the client with a new syncSeqId to begin a new sync
1146      *    2. Due to scheduling the client executes performTraversals before calling MSG_RESIZED
1147      *    3. Coincidentally for some random reason it also calls relayout
1148      *    4. It observes the new state from relayout, and so the next frame will contain the state
1149      * However it hasn't received the seqId yet, and so under the designed operation of
1150      * seqId flowing through MSG_RESIZED, the next frame wouldn't be synced. Since it
1151      * contains our target sync state, we need to sync it! This problem won't come up once
1152      * we get rid of synchronous relayout, until then, we use this bundle to channel the
1153      * integer back over relayout.
1154      */
1155     private final Bundle mRelayoutBundle = windowSessionRelayoutInfo()
1156             ? null
1157             : new Bundle();
1158 
1159     private final WindowRelayoutResult mRelayoutResult = windowSessionRelayoutInfo()
1160             ? new WindowRelayoutResult(mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
1161                     mTempInsets, mTempControls)
1162             : null;
1163 
1164     private static volatile boolean sAnrReported = false;
1165     static BLASTBufferQueue.TransactionHangCallback sTransactionHangCallback =
1166         new BLASTBufferQueue.TransactionHangCallback() {
1167             @Override
1168             public void onTransactionHang(String reason) {
1169                 if (sAnrReported) {
1170                     return;
1171                 }
1172 
1173                 sAnrReported = true;
1174                 // If we're making an in-process call to ActivityManagerService
1175                 // and the previous binder call on this thread was oneway, the
1176                 // calling PID will be 0. Clearing the calling identity fixes
1177                 // this and ensures ActivityManager gets the correct calling
1178                 // pid.
1179                 final long identityToken = Binder.clearCallingIdentity();
1180                 try {
1181                     ActivityManager.getService().appNotResponding(reason);
1182                 } catch (RemoteException e) {
1183                     // We asked the system to crash us, but the system
1184                     // already crashed. Unfortunately things may be
1185                     // out of control.
1186                 } finally {
1187                     Binder.restoreCallingIdentity(identityToken);
1188                 }
1189             }
1190         };
1191     private final Rect mChildBoundingInsets = new Rect();
1192     private boolean mChildBoundingInsetsChanged = false;
1193 
1194     private String mTag = TAG;
1195     private String mFpsTraceName;
1196     private String mLargestViewTraceName;
1197 
1198     private final boolean mAppStartInfoTimestampsFlagValue;
1199     @GuardedBy("this")
1200     private boolean mAppStartTimestampsSent = false;
1201     private boolean mAppStartTrackingStarted = false;
1202     private long mRenderThreadDrawStartTimeNs = -1;
1203     private long mFirstFramePresentedTimeNs = -1;
1204 
1205     private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
1206     private static boolean sToolkitFrameRateFunctionEnablingReadOnlyFlagValue;
1207     private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
1208     private static boolean sToolkitFrameRateTypingReadOnlyFlagValue;
1209     private static final boolean sToolkitFrameRateViewEnablingReadOnlyFlagValue;
1210     private static boolean sToolkitFrameRateVelocityMappingReadOnlyFlagValue =
1211             toolkitFrameRateVelocityMappingReadOnly();
1212     private static boolean sToolkitEnableInvalidateCheckThreadFlagValue =
1213             Flags.enableInvalidateCheckThread();
1214     private static boolean sSurfaceFlingerBugfixFlagValue =
1215             com.android.graphics.surfaceflinger.flags.Flags.vrrBugfix24q4();
1216     private static final boolean sEnableVrr = ViewProperties.vrr_enabled().orElse(true);
1217 
1218     static {
1219         sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
1220         sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision();
1221         sToolkitFrameRateTypingReadOnlyFlagValue = toolkitFrameRateTypingReadOnly();
1222         sToolkitFrameRateFunctionEnablingReadOnlyFlagValue =
1223                 toolkitFrameRateFunctionEnablingReadOnly();
1224         sToolkitFrameRateViewEnablingReadOnlyFlagValue =
1225                 toolkitFrameRateViewEnablingReadOnly();
1226     }
1227 
1228     // The latest input event from the gesture that was used to resolve the pointer icon.
1229     private MotionEvent mPointerIconEvent = null;
1230 
ViewRootImpl(Context context, Display display)1231     public ViewRootImpl(Context context, Display display) {
1232         this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout());
1233     }
1234 
ViewRootImpl(@iContext Context context, Display display, IWindowSession session, WindowLayout windowLayout)1235     public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
1236             WindowLayout windowLayout) {
1237         mContext = context;
1238         mWindowSession = session;
1239         mWindowLayout = windowLayout;
1240         mDisplay = display;
1241         mBasePackageName = context.getBasePackageName();
1242         final String name = DisplayProperties.debug_vri_package().orElse(null);
1243         mExtraDisplayListenerLogging = !TextUtils.isEmpty(name) && name.equals(mBasePackageName);
1244         mThread = Thread.currentThread();
1245         mLocation = new WindowLeaked(null);
1246         mLocation.fillInStackTrace();
1247         mWidth = -1;
1248         mHeight = -1;
1249         mDirty = new Rect();
1250         mWinFrame = new Rect();
1251         mLastLayoutFrame = new Rect();
1252         mWindow = new W(this);
1253         mLeashToken = new Binder();
1254         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
1255         mViewVisibility = View.GONE;
1256         mTransparentRegion = new Region();
1257         mPreviousTransparentRegion = new Region();
1258         mFirst = true; // true for the first time the view is added
1259         mPerformContentCapture = true; // also true for the first time the view is added
1260         mAdded = false;
1261         mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
1262                 context);
1263         mCompatibleVisibilityInfo = new SystemUiVisibilityInfo();
1264         mAccessibilityManager = AccessibilityManager.getInstance(context);
1265         mHighContrastTextManager = new HighContrastTextManager();
1266         mViewConfiguration = ViewConfiguration.get(context);
1267         mDensity = context.getResources().getDisplayMetrics().densityDpi;
1268         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
1269         mFallbackEventHandler = new PhoneFallbackEventHandler(context);
1270         mChoreographer = Choreographer.getInstance();
1271         mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));
1272         mImeBackAnimationController = new ImeBackAnimationController(this, mInsetsController);
1273         mHandwritingInitiator = new HandwritingInitiator(
1274                 mViewConfiguration,
1275                 mContext.getSystemService(InputMethodManager.class));
1276 
1277         mViewBoundsSandboxingEnabled = getViewBoundsSandboxingEnabled();
1278         mIsStylusPointerIconEnabled =
1279                 InputSettings.isStylusPointerIconEnabled(mContext);
1280 
1281         String processorOverrideName = context.getResources().getString(
1282                                     R.string.config_inputEventCompatProcessorOverrideClassName);
1283         if (processorOverrideName.isEmpty()) {
1284             // No compatibility processor override, using default.
1285             mInputCompatProcessor = new InputEventCompatProcessor(context);
1286         } else {
1287             InputEventCompatProcessor compatProcessor = null;
1288             try {
1289                 final Class<? extends InputEventCompatProcessor> klass =
1290                         (Class<? extends InputEventCompatProcessor>) Class.forName(
1291                                 processorOverrideName);
1292                 compatProcessor = klass.getConstructor(Context.class).newInstance(context);
1293             } catch (Exception e) {
1294                 Log.e(TAG, "Unable to create the InputEventCompatProcessor. ", e);
1295             } finally {
1296                 mInputCompatProcessor = compatProcessor;
1297             }
1298         }
1299 
1300         if (!sCompatibilityDone) {
1301             sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
1302 
1303             sCompatibilityDone = true;
1304         }
1305 
1306         loadSystemProperties();
1307         mImeFocusController = new ImeFocusController(this);
1308 
1309         mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
1310         mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context, Looper.myLooper());
1311         if (sensitiveContentAppProtection()) {
1312             mSensitiveContentProtectionService =
1313                     ISensitiveContentProtectionManager.Stub.asInterface(
1314                         ServiceManager.getService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE));
1315             if (mSensitiveContentProtectionService == null) {
1316                 Log.e(TAG, "SensitiveContentProtectionService shouldn't be null");
1317             }
1318         } else {
1319             mSensitiveContentProtectionService = null;
1320         }
1321 
1322         mAppStartInfoTimestampsFlagValue = android.app.Flags.appStartInfoTimestamps();
1323     }
1324 
1325     public static void addFirstDrawHandler(Runnable callback) {
1326         synchronized (sFirstDrawHandlers) {
1327             if (!sFirstDrawComplete) {
1328                 sFirstDrawHandlers.add(callback);
1329             }
1330         }
1331     }
1332 
1333     /** Add static config callback to be notified about global config changes. */
1334     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1335     public static void addConfigCallback(ConfigChangedCallback callback) {
1336         synchronized (sConfigCallbacks) {
1337             sConfigCallbacks.add(callback);
1338         }
1339     }
1340 
1341     /** Remove a static config callback. */
1342     public static void removeConfigCallback(ConfigChangedCallback callback) {
1343         synchronized (sConfigCallbacks) {
1344             sConfigCallbacks.remove(callback);
1345         }
1346     }
1347 
1348     /**
1349      * Add activity config callback to be notified about override config changes and camera
1350      * compat control state updates.
1351      */
1352     public void setActivityConfigCallback(@Nullable ActivityConfigCallback callback) {
1353         mActivityConfigCallback = callback;
1354         if (!activityWindowInfoFlag()) {
1355             return;
1356         }
1357         if (callback == null) {
1358             mPendingActivityWindowInfo = null;
1359             mLastReportedActivityWindowInfo = null;
1360         } else {
1361             mPendingActivityWindowInfo = new ActivityWindowInfo();
1362             mLastReportedActivityWindowInfo = new ActivityWindowInfo();
1363         }
1364     }
1365 
1366     public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
1367         mAttachInfo.mContentOnApplyWindowInsetsListener = listener;
1368 
1369         // System windows will be fitted on first traversal, so no reason to request additional
1370         // (possibly getting executed after the first traversal).
1371         if (!mFirst) {
1372             requestFitSystemWindows();
1373         }
1374     }
1375 
1376     public void addWindowCallbacks(WindowCallbacks callback) {
1377         mWindowCallbacks.add(callback);
1378     }
1379 
1380     public void removeWindowCallbacks(WindowCallbacks callback) {
1381         mWindowCallbacks.remove(callback);
1382     }
1383 
1384     public void reportDrawFinish() {
1385         if (mWindowDrawCountDown != null) {
1386             mWindowDrawCountDown.countDown();
1387         }
1388     }
1389 
1390     // FIXME for perf testing only
1391     private boolean mProfile = false;
1392 
1393     /**
1394      * Call this to profile the next traversal call.
1395      * FIXME for perf testing only. Remove eventually
1396      */
1397     public void profile() {
1398         mProfile = true;
1399     }
1400 
1401     private boolean isInTouchMode() {
1402         if (mAttachInfo == null) {
1403             return mContext.getResources().getBoolean(R.bool.config_defaultInTouchMode);
1404         }
1405         return mAttachInfo.mInTouchMode;
1406     }
1407 
1408     /**
1409      * Notifies us that our child has been rebuilt, following
1410      * a window preservation operation. In these cases we
1411      * keep the same DecorView, but the activity controlling it
1412      * is a different instance, and we need to update our
1413      * callbacks.
1414      *
1415      * @hide
1416      */
1417     public void notifyChildRebuilt() {
1418         if (mView instanceof RootViewSurfaceTaker) {
1419             if (mSurfaceHolderCallback != null) {
1420                 mSurfaceHolder.removeCallback(mSurfaceHolderCallback);
1421             }
1422 
1423             mSurfaceHolderCallback =
1424                 ((RootViewSurfaceTaker)mView).willYouTakeTheSurface();
1425 
1426             if (mSurfaceHolderCallback != null) {
1427                 mSurfaceHolder = new TakenSurfaceHolder();
1428                 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
1429                 mSurfaceHolder.addCallback(mSurfaceHolderCallback);
1430             } else {
1431                 mSurfaceHolder = null;
1432             }
1433 
1434             mInputQueueCallback =
1435                 ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue();
1436             if (mInputQueueCallback != null) {
1437                 mInputQueueCallback.onInputQueueCreated(mInputQueue);
1438             }
1439         }
1440 
1441         // Update the last resource config in case the resource configuration was changed while
1442         // activity relaunched.
1443         updateLastConfigurationFromResources(getConfiguration());
1444         // Make sure to report the completion of draw for relaunch with preserved window.
1445         reportNextDraw("rebuilt");
1446         // Make sure to resume this root view when relaunching its host activity which was stopped.
1447         if (mStopped) {
1448             setWindowStopped(false);
1449         }
1450     }
1451 
1452     private Configuration getConfiguration() {
1453         return mContext.getResources().getConfiguration();
1454     }
1455 
1456     private WindowConfiguration getCompatWindowConfiguration() {
1457         final WindowConfiguration winConfig = getConfiguration().windowConfiguration;
1458         if (mInvCompatScale == 1f) {
1459             return winConfig;
1460         }
1461         mTempWinConfig.setTo(winConfig);
1462         mTempWinConfig.scale(mInvCompatScale);
1463         return mTempWinConfig;
1464     }
1465 
1466     /**
1467      * We have one child
1468      */
1469     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
1470         setView(view, attrs, panelParentView, UserHandle.myUserId());
1471     }
1472 
1473     /**
1474      * We have one child
1475      */
1476     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
1477             int userId) {
1478         synchronized (this) {
1479             if (mView == null) {
1480                 mView = view;
1481 
1482                 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
1483                 mFallbackEventHandler.setView(view);
1484                 mWindowAttributes.copyFrom(attrs);
1485                 if (mWindowAttributes.packageName == null) {
1486                     mWindowAttributes.packageName = mBasePackageName;
1487                 }
1488 
1489                 attrs = mWindowAttributes;
1490                 setTag();
1491                 mFpsTraceName = "FPS of " + getTitle();
1492                 mLargestViewTraceName = "Largest view percentage(per hundred) of " + getTitle();
1493 
1494                 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
1495                         & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
1496                         && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
1497                     Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
1498                 }
1499                 // Keep track of the actual window flags supplied by the client.
1500                 mClientWindowLayoutFlags = attrs.flags;
1501 
1502                 adjustLayoutInDisplayCutoutMode(attrs);
1503                 setAccessibilityFocus(null, null);
1504 
1505                 if (view instanceof RootViewSurfaceTaker) {
1506                     mSurfaceHolderCallback =
1507                             ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
1508                     if (mSurfaceHolderCallback != null) {
1509                         mSurfaceHolder = new TakenSurfaceHolder();
1510                         mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
1511                         mSurfaceHolder.addCallback(mSurfaceHolderCallback);
1512                     }
1513                 }
1514 
1515                 // Compute surface insets required to draw at specified Z value.
1516                 // TODO: Use real shadow insets for a constant max Z.
1517                 if (!attrs.hasManualSurfaceInsets) {
1518                     attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
1519                 }
1520 
1521                 CompatibilityInfo compatibilityInfo =
1522                         mDisplay.getDisplayAdjustments().getCompatibilityInfo();
1523                 mTranslator = compatibilityInfo.getTranslator();
1524 
1525                 // If the application owns the surface, don't enable hardware acceleration
1526                 if (mSurfaceHolder == null) {
1527                     // While this is supposed to enable only, it can effectively disable
1528                     // the acceleration too.
1529                     enableHardwareAcceleration(attrs);
1530                     final boolean useMTRenderer = MT_RENDERER_AVAILABLE
1531                             && mAttachInfo.mThreadedRenderer != null;
1532                     if (mUseMTRenderer != useMTRenderer) {
1533                         // Shouldn't be resizing, as it's done only in window setup,
1534                         // but end just in case.
1535                         endDragResizing();
1536                         mUseMTRenderer = useMTRenderer;
1537                     }
1538                 }
1539 
1540                 boolean restore = false;
1541                 if (mTranslator != null) {
1542                     mSurface.setCompatibilityTranslator(mTranslator);
1543                     restore = true;
1544                     attrs.backup();
1545                     mTranslator.translateWindowLayout(attrs);
1546                 }
1547                 if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
1548 
1549                 mSoftInputMode = attrs.softInputMode;
1550                 mWindowAttributesChanged = true;
1551                 mAttachInfo.mRootView = view;
1552                 mAttachInfo.mScalingRequired = mTranslator != null;
1553                 mAttachInfo.mApplicationScale =
1554                         mTranslator == null ? 1.0f : mTranslator.applicationScale;
1555                 if (panelParentView != null) {
1556                     mAttachInfo.mPanelParentWindowToken
1557                             = panelParentView.getApplicationWindowToken();
1558                 }
1559                 mAdded = true;
1560                 int res; /* = WindowManagerImpl.ADD_OKAY; */
1561 
1562                 // Schedule the first layout -before- adding to the window
1563                 // manager, to make sure we do the relayout before receiving
1564                 // any other events from the system.
1565                 requestLayout();
1566                 InputChannel inputChannel = null;
1567                 if ((mWindowAttributes.inputFeatures
1568                         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
1569                     inputChannel = new InputChannel();
1570                 }
1571                 mForceDecorViewVisibility = (mWindowAttributes.privateFlags
1572                         & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
1573 
1574                 if (mView instanceof RootViewSurfaceTaker) {
1575                     PendingInsetsController pendingInsetsController =
1576                             ((RootViewSurfaceTaker) mView).providePendingInsetsController();
1577                     if (pendingInsetsController != null) {
1578                         pendingInsetsController.replayAndAttach(mInsetsController);
1579                     }
1580                 }
1581                 if (mView instanceof DecorView) {
1582                     mWindowAttributes.privateFlags |= PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED;
1583                 }
1584 
1585                 try {
1586                     mOrigWindowType = mWindowAttributes.type;
1587                     mAttachInfo.mRecomputeGlobalAttributes = true;
1588                     collectViewAttributes();
1589                     adjustLayoutParamsForCompatibility(mWindowAttributes,
1590                             mInsetsController.getAppearanceControlled(),
1591                             mInsetsController.isBehaviorControlled());
1592                     controlInsetsForCompatibility(mWindowAttributes);
1593 
1594                     Rect attachedFrame = new Rect();
1595                     final float[] compatScale = { 1f };
1596                     res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
1597                             getHostVisibility(), mDisplay.getDisplayId(), userId,
1598                             mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
1599                             mTempControls, attachedFrame, compatScale);
1600                     if (!attachedFrame.isValid()) {
1601                         attachedFrame = null;
1602                     }
1603                     if (mTranslator != null) {
1604                         mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
1605                         mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls.get());
1606                         mTranslator.translateRectInScreenToAppWindow(attachedFrame);
1607                     }
1608                     mTmpFrames.attachedFrame = attachedFrame;
1609                     mTmpFrames.compatScale = compatScale[0];
1610                     mInvCompatScale = 1f / compatScale[0];
1611                 } catch (RemoteException | RuntimeException e) {
1612                     mAdded = false;
1613                     mView = null;
1614                     mAttachInfo.mRootView = null;
1615                     mFallbackEventHandler.setView(null);
1616                     unscheduleTraversals();
1617                     setAccessibilityFocus(null, null);
1618                     throw new RuntimeException("Adding window failed", e);
1619                 } finally {
1620                     if (restore) {
1621                         attrs.restore();
1622                     }
1623                 }
1624 
1625                 mAttachInfo.mAlwaysConsumeSystemBars =
1626                         (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0;
1627                 mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;
1628                 mInsetsController.onStateChanged(mTempInsets);
1629                 mInsetsController.onControlsChanged(mTempControls.get());
1630                 final InsetsState state = mInsetsController.getState();
1631                 final Rect displayCutoutSafe = mTempRect;
1632                 state.getDisplayCutoutSafe(displayCutoutSafe);
1633                 final WindowConfiguration winConfig = getCompatWindowConfiguration();
1634                 mWindowLayout.computeFrames(mWindowAttributes, state,
1635                         displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
1636                         UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
1637                         mInsetsController.getRequestedVisibleTypes(), 1f /* compactScale */,
1638                         mTmpFrames);
1639                 setFrame(mTmpFrames.frame, true /* withinRelayout */);
1640                 registerBackCallbackOnWindow();
1641                 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
1642                 if (res < WindowManagerGlobal.ADD_OKAY) {
1643                     mAttachInfo.mRootView = null;
1644                     mAdded = false;
1645                     mFallbackEventHandler.setView(null);
1646                     unscheduleTraversals();
1647                     setAccessibilityFocus(null, null);
1648                     switch (res) {
1649                         case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
1650                         case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
1651                             throw new WindowManager.BadTokenException(
1652                                     "Unable to add window -- token " + attrs.token
1653                                     + " is not valid; is your activity running?");
1654                         case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
1655                             throw new WindowManager.BadTokenException(
1656                                     "Unable to add window -- token " + attrs.token
1657                                     + " is not for an application");
1658                         case WindowManagerGlobal.ADD_APP_EXITING:
1659                             throw new WindowManager.BadTokenException(
1660                                     "Unable to add window -- app for token " + attrs.token
1661                                     + " is exiting");
1662                         case WindowManagerGlobal.ADD_DUPLICATE_ADD:
1663                             throw new WindowManager.BadTokenException(
1664                                     "Unable to add window -- window " + mWindow
1665                                     + " has already been added");
1666                         case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
1667                             // Silently ignore -- we would have just removed it
1668                             // right away, anyway.
1669                             return;
1670                         case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
1671                             throw new WindowManager.BadTokenException("Unable to add window "
1672                                     + mWindow + " -- another window of type "
1673                                     + mWindowAttributes.type + " already exists");
1674                         case WindowManagerGlobal.ADD_PERMISSION_DENIED:
1675                             throw new WindowManager.BadTokenException("Unable to add window "
1676                                     + mWindow + " -- permission denied for window type "
1677                                     + mWindowAttributes.type);
1678                         case WindowManagerGlobal.ADD_INVALID_DISPLAY:
1679                             throw new WindowManager.InvalidDisplayException("Unable to add window "
1680                                     + mWindow + " -- the specified display can not be found");
1681                         case WindowManagerGlobal.ADD_INVALID_TYPE:
1682                             throw new WindowManager.InvalidDisplayException("Unable to add window "
1683                                     + mWindow + " -- the specified window type "
1684                                     + mWindowAttributes.type + " is not valid");
1685                         case WindowManagerGlobal.ADD_INVALID_USER:
1686                             throw new WindowManager.BadTokenException("Unable to add Window "
1687                                     + mWindow + " -- requested userId is not valid");
1688                     }
1689                     throw new RuntimeException(
1690                             "Unable to add window -- unknown error code " + res);
1691                 }
1692 
1693                 registerListeners();
1694                 // We should update mAttachInfo.mDisplayState after registerDisplayListener
1695                 // because displayState might be changed before registerDisplayListener.
1696                 mAttachInfo.mDisplayState = mDisplay.getState();
1697                 if (mExtraDisplayListenerLogging) {
1698                     Slog.i(mTag, "(" + mBasePackageName + ") Initial DisplayState: "
1699                             + mAttachInfo.mDisplayState, new Throwable());
1700                 }
1701 
1702                 if (view instanceof RootViewSurfaceTaker) {
1703                     mInputQueueCallback =
1704                         ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
1705                 }
1706                 if (inputChannel != null) {
1707                     if (mInputQueueCallback != null) {
1708                         mInputQueue = new InputQueue();
1709                         mInputQueueCallback.onInputQueueCreated(mInputQueue);
1710                     }
1711                     mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
1712                             Looper.myLooper());
1713 
1714                     if (ENABLE_INPUT_LATENCY_TRACKING && mAttachInfo.mThreadedRenderer != null) {
1715                         InputMetricsListener listener = new InputMetricsListener();
1716                         mHardwareRendererObserver = new HardwareRendererObserver(
1717                                 listener, listener.data, mHandler, true /*waitForPresentTime*/);
1718                         mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
1719                     }
1720                     // Update unbuffered request when set the root view.
1721                     mUnbufferedInputSource = mView.mUnbufferedInputSource;
1722                 }
1723 
1724                 view.assignParent(this);
1725                 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
1726                 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
1727 
1728                 if (mAccessibilityManager.isEnabled()) {
1729                     mAccessibilityInteractionConnectionManager.ensureConnection();
1730                     setAccessibilityWindowAttributesIfNeeded();
1731                 }
1732 
1733                 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
1734                     view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
1735                 }
1736 
1737                 // Set up the input pipeline.
1738                 CharSequence counterSuffix = attrs.getTitle();
1739                 mSyntheticInputStage = new SyntheticInputStage();
1740                 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
1741                 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
1742                         "aq:native-post-ime:" + counterSuffix);
1743                 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
1744                 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
1745                         "aq:ime:" + counterSuffix);
1746                 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
1747                 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
1748                         "aq:native-pre-ime:" + counterSuffix);
1749 
1750                 mFirstInputStage = nativePreImeStage;
1751                 mFirstPostImeInputStage = earlyPostImeStage;
1752                 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
1753 
1754                 if (!mRemoved || !mAppVisible) {
1755                     AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
1756                 } else if (LOCAL_LOGV) {
1757                     Log.v(mTag, "setView() enabling visibility when removed");
1758                 }
1759             }
1760         }
1761     }
1762 
1763     private void setAccessibilityWindowAttributesIfNeeded() {
1764         final boolean registered = mAttachInfo.mAccessibilityWindowId
1765                 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1766         if (registered) {
1767             final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
1768                     mWindowAttributes, mContext.getResources().getConfiguration().getLocales());
1769             if (!attributes.equals(mAccessibilityWindowAttributes)) {
1770                 mAccessibilityWindowAttributes = attributes;
1771                 mAccessibilityManager.setAccessibilityWindowAttributes(getDisplayId(),
1772                         mAttachInfo.mAccessibilityWindowId, attributes);
1773             }
1774 
1775         }
1776     }
1777 
1778     private boolean isForceInvertEnabled() {
1779         if (mForceInvertEnabled == INVALID_VALUE) {
1780             reloadForceInvertEnabled();
1781         }
1782         return mForceInvertEnabled == 1;
1783     }
1784 
1785     private void reloadForceInvertEnabled() {
1786         if (forceInvertColor()) {
1787             mForceInvertEnabled = Settings.Secure.getIntForUser(
1788                     mContext.getContentResolver(),
1789                     Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
1790                     /* def= */ 0,
1791                     UserHandle.myUserId());
1792         }
1793     }
1794 
1795     /**
1796      * Register any kind of listeners if setView was success.
1797      */
1798     private void registerListeners() {
1799         if (mExtraDisplayListenerLogging) {
1800             Slog.i(mTag, "Register listeners: " + mBasePackageName);
1801         }
1802         mAccessibilityManager.addAccessibilityStateChangeListener(
1803                 mAccessibilityInteractionConnectionManager, mHandler);
1804         mAccessibilityManager.addHighTextContrastStateChangeListener(
1805                 mHighContrastTextManager, mHandler);
1806         DisplayManagerGlobal
1807                 .getInstance()
1808                 .registerDisplayListener(
1809                         mDisplayListener,
1810                         mHandler,
1811                         DisplayManager.EVENT_FLAG_DISPLAY_ADDED
1812                         | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
1813                         | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED,
1814                         mBasePackageName);
1815 
1816         if (forceInvertColor()) {
1817             if (mForceInvertObserver == null) {
1818                 mForceInvertObserver = new ContentObserver(mHandler) {
1819                     @Override
1820                     public void onChange(boolean selfChange) {
1821                         reloadForceInvertEnabled();
1822                         updateForceDarkMode();
1823                     }
1824                 };
1825                 mContext.getContentResolver().registerContentObserver(
1826                         Settings.Secure.getUriFor(
1827                                 Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED
1828                         ),
1829                         false,
1830                         mForceInvertObserver,
1831                         UserHandle.myUserId());
1832             }
1833         }
1834     }
1835 
1836     /**
1837      * Unregister all listeners while detachedFromWindow.
1838      */
1839     private void unregisterListeners() {
1840         mAccessibilityManager.removeAccessibilityStateChangeListener(
1841                 mAccessibilityInteractionConnectionManager);
1842         mAccessibilityManager.removeHighTextContrastStateChangeListener(
1843                 mHighContrastTextManager);
1844         DisplayManagerGlobal
1845                 .getInstance()
1846                 .unregisterDisplayListener(mDisplayListener);
1847 
1848         if (forceInvertColor()) {
1849             if (mForceInvertObserver != null) {
1850                 mContext.getContentResolver().unregisterContentObserver(mForceInvertObserver);
1851                 mForceInvertObserver = null;
1852             }
1853         }
1854 
1855         if (mExtraDisplayListenerLogging) {
1856             Slog.w(mTag, "Unregister listeners: " + mBasePackageName, new Throwable());
1857         }
1858     }
1859 
1860     private void setTag() {
1861         final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
1862         if (split.length > 0) {
1863             mTag =  "VRI[" + split[split.length - 1] + "]";
1864         }
1865     }
1866 
1867     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1868     public int getWindowFlags() {
1869         return mWindowAttributes.flags;
1870     }
1871 
1872     public int getDisplayId() {
1873         return mDisplay.getDisplayId();
1874     }
1875 
1876     public CharSequence getTitle() {
1877         return mWindowAttributes.getTitle();
1878     }
1879 
1880     /**
1881      * @return the width of the root view. Note that this will return {@code -1} until the first
1882      *         layout traversal, when the width is set.
1883      *
1884      * @hide
1885      */
1886     public int getWidth() {
1887         return mWidth;
1888     }
1889 
1890     /**
1891      * @return the height of the root view. Note that this will return {@code -1} until the first
1892      *         layout traversal, when the height is set.
1893      *
1894      * @hide
1895      */
1896     public int getHeight() {
1897         return mHeight;
1898     }
1899 
1900     /**
1901      * Destroys hardware rendering resources for this ViewRootImpl
1902      *
1903      * May be called on any thread
1904      */
1905     @AnyThread
1906     void destroyHardwareResources() {
1907         final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
1908         if (renderer != null) {
1909             // This is called by WindowManagerGlobal which may or may not be on the right thread
1910             if (Looper.myLooper() != mAttachInfo.mHandler.getLooper()) {
1911                 mAttachInfo.mHandler.postAtFrontOfQueue(this::destroyHardwareResources);
1912                 return;
1913             }
1914             renderer.destroyHardwareResources(mView);
1915             renderer.destroy();
1916         }
1917     }
1918 
1919     /**
1920      * Does nothing; Here only because of @UnsupportedAppUsage
1921      */
1922     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
1923             publicAlternatives = "Use {@link android.webkit.WebView} instead")
1924     public void detachFunctor(long functor) { }
1925 
1926     /**
1927      * Does nothing; Here only because of @UnsupportedAppUsage
1928      */
1929     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
1930             publicAlternatives = "Use {@link android.webkit.WebView} instead")
1931     public static void invokeFunctor(long functor, boolean waitForCompletion) { }
1932 
1933     /**
1934      * @param animator animator to register with the hardware renderer
1935      */
1936     public void registerAnimatingRenderNode(RenderNode animator) {
1937         if (mAttachInfo.mThreadedRenderer != null) {
1938             mAttachInfo.mThreadedRenderer.registerAnimatingRenderNode(animator);
1939         } else {
1940             if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
1941                 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
1942             }
1943             mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
1944         }
1945     }
1946 
1947     /**
1948      * @param animator animator to register with the hardware renderer
1949      */
1950     public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) {
1951         if (mAttachInfo.mThreadedRenderer != null) {
1952             mAttachInfo.mThreadedRenderer.registerVectorDrawableAnimator(animator);
1953         }
1954     }
1955 
1956     /**
1957      * Registers a callback to be executed when the next frame is being drawn on RenderThread. This
1958      * callback will be executed on a RenderThread worker thread, and only used for the next frame
1959      * and thus it will only fire once.
1960      *
1961      * @param callback The callback to register.
1962      */
1963     public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) {
1964         if (mAttachInfo.mThreadedRenderer != null) {
1965             mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
1966                 @Override
1967                 public void onFrameDraw(long frame) {
1968                 }
1969 
1970                 @Override
1971                 public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult,
1972                         long frame) {
1973                     try {
1974                         return callback.onFrameDraw(syncResult, frame);
1975                     } catch (Exception e) {
1976                         Log.e(TAG, "Exception while executing onFrameDraw", e);
1977                     }
1978                     return null;
1979                 }
1980             });
1981         }
1982     }
1983 
1984     @UnsupportedAppUsage
1985     private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
1986         mAttachInfo.mHardwareAccelerated = false;
1987         mAttachInfo.mHardwareAccelerationRequested = false;
1988 
1989         // Don't enable hardware acceleration when the application is in compatibility mode
1990         if (mTranslator != null) return;
1991 
1992         // Try to enable hardware acceleration if requested
1993         final boolean hardwareAccelerated =
1994                 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
1995 
1996         if (hardwareAccelerated) {
1997             // Persistent processes (including the system) should not do
1998             // accelerated rendering on low-end devices.  In that case,
1999             // sRendererDisabled will be set.  In addition, the system process
2000             // itself should never do accelerated rendering.  In that case, both
2001             // sRendererDisabled and sSystemRendererDisabled are set.  When
2002             // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
2003             // can be used by code on the system process to escape that and enable
2004             // HW accelerated drawing.  (This is basically for the lock screen.)
2005 
2006             final boolean forceHwAccelerated = (attrs.privateFlags &
2007                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
2008 
2009             if (ThreadedRenderer.sRendererEnabled || forceHwAccelerated) {
2010                 if (mAttachInfo.mThreadedRenderer != null) {
2011                     mAttachInfo.mThreadedRenderer.destroy();
2012                 }
2013 
2014                 final Rect insets = attrs.surfaceInsets;
2015                 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
2016                         || insets.top != 0 || insets.bottom != 0;
2017                 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
2018                 final ThreadedRenderer renderer = ThreadedRenderer.create(mContext, translucent,
2019                         attrs.getTitle().toString());
2020                 mAttachInfo.mThreadedRenderer = renderer;
2021                 renderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
2022                 updateColorModeIfNeeded(attrs.getColorMode(), attrs.getDesiredHdrHeadroom());
2023                 mHdrRenderState.forceUpdateHdrSdrRatio();
2024                 updateForceDarkMode();
2025                 mAttachInfo.mHardwareAccelerated = true;
2026                 mAttachInfo.mHardwareAccelerationRequested = true;
2027                 if (mHardwareRendererObserver != null) {
2028                     renderer.addObserver(mHardwareRendererObserver);
2029                 }
2030             }
2031         }
2032     }
2033 
2034     private int getNightMode() {
2035         return getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
2036     }
2037 
2038     /** Returns true if force dark should be enabled according to various settings */
2039     @VisibleForTesting
2040     public @ForceDarkType.ForceDarkTypeDef int determineForceDarkType() {
2041         if (forceInvertColor()) {
2042             // Force invert ignores all developer opt-outs.
2043             // We also ignore dark theme, since the app developer can override the user's preference
2044             // for dark mode in configuration.uiMode. Instead, we assume that the force invert
2045             // setting will be enabled at the same time dark theme is in the Settings app.
2046             if (isForceInvertEnabled()) {
2047                 return ForceDarkType.FORCE_INVERT_COLOR_DARK;
2048             }
2049         }
2050 
2051         boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
2052 
2053         if (useAutoDark) {
2054             boolean forceDarkAllowedDefault =
2055                     SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);
2056             TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
2057             useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
2058                     && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);
2059             a.recycle();
2060         }
2061         return useAutoDark ? ForceDarkType.FORCE_DARK : ForceDarkType.NONE;
2062     }
2063 
2064     private void updateForceDarkMode() {
2065         if (mAttachInfo.mThreadedRenderer == null) return;
2066         if (mAttachInfo.mThreadedRenderer.setForceDark(determineForceDarkType())) {
2067             // TODO: Don't require regenerating all display lists to apply this setting
2068             invalidateWorld(mView);
2069         }
2070     }
2071 
2072     @UnsupportedAppUsage
2073     public View getView() {
2074         return mView;
2075     }
2076 
2077     final WindowLeaked getLocation() {
2078         return mLocation;
2079     }
2080 
2081     @VisibleForTesting
2082     public void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
2083         synchronized (this) {
2084             final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
2085             final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
2086             final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
2087             final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
2088             final int oldSoftInputMode = mWindowAttributes.softInputMode;
2089             final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
2090 
2091             if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
2092                     & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
2093                     && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
2094                 Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!");
2095             }
2096 
2097             // Keep track of the actual window flags supplied by the client.
2098             mClientWindowLayoutFlags = attrs.flags;
2099 
2100             // Preserve system UI visibility.
2101             final int systemUiVisibility = mWindowAttributes.systemUiVisibility;
2102             final int subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
2103 
2104             // Preserve appearance and behavior.
2105             final int appearance = mWindowAttributes.insetsFlags.appearance;
2106             final int behavior = mWindowAttributes.insetsFlags.behavior;
2107 
2108             // Calling this before copying prevents redundant LAYOUT_CHANGED.
2109             final int layoutInDisplayCutoutModeFromCaller = adjustLayoutInDisplayCutoutMode(attrs);
2110 
2111             final int changes = mWindowAttributes.copyFrom(attrs);
2112             if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
2113                 // Recompute system ui visibility.
2114                 mAttachInfo.mRecomputeGlobalAttributes = true;
2115             }
2116             if ((changes & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
2117                 // Request to update light center.
2118                 mAttachInfo.mNeedsUpdateLightCenter = true;
2119             }
2120             if ((changes & WindowManager.LayoutParams.COLOR_MODE_CHANGED) != 0) {
2121                 invalidate();
2122             }
2123             if (mWindowAttributes.packageName == null) {
2124                 mWindowAttributes.packageName = mBasePackageName;
2125             }
2126 
2127             // Restore the layoutInDisplayCutoutMode of the caller;
2128             attrs.layoutInDisplayCutoutMode = layoutInDisplayCutoutModeFromCaller;
2129 
2130             // Restore preserved flags.
2131             mWindowAttributes.systemUiVisibility = systemUiVisibility;
2132             mWindowAttributes.subtreeSystemUiVisibility = subtreeSystemUiVisibility;
2133             mWindowAttributes.insetsFlags.appearance = appearance;
2134             mWindowAttributes.insetsFlags.behavior = behavior;
2135 
2136             if (mWindowAttributes.preservePreviousSurfaceInsets) {
2137                 // Restore old surface insets.
2138                 mWindowAttributes.surfaceInsets.set(
2139                         oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
2140                 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
2141             } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft
2142                     || mWindowAttributes.surfaceInsets.top != oldInsetTop
2143                     || mWindowAttributes.surfaceInsets.right != oldInsetRight
2144                     || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) {
2145                 mNeedsRendererSetup = true;
2146             }
2147 
2148             applyKeepScreenOnFlag(mWindowAttributes);
2149 
2150             if (newView) {
2151                 mSoftInputMode = attrs.softInputMode;
2152                 requestLayout();
2153             }
2154 
2155             // Don't lose the mode we last auto-computed.
2156             if ((attrs.softInputMode & SOFT_INPUT_MASK_ADJUST)
2157                     == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
2158                 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
2159                         & ~SOFT_INPUT_MASK_ADJUST) | (oldSoftInputMode & SOFT_INPUT_MASK_ADJUST);
2160             }
2161 
2162             if (mWindowAttributes.softInputMode != oldSoftInputMode) {
2163                 requestFitSystemWindows();
2164             }
2165 
2166             mWindowAttributesChanged = true;
2167             scheduleTraversals();
2168             setAccessibilityWindowAttributesIfNeeded();
2169         }
2170     }
2171 
2172     private int adjustLayoutInDisplayCutoutMode(WindowManager.LayoutParams attrs) {
2173         final int originalMode = attrs.layoutInDisplayCutoutMode;
2174         if ((attrs.privateFlags & (PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED
2175                 | PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE)) != 0
2176                 && attrs.isFullscreen()
2177                 && attrs.getFitInsetsTypes() == 0
2178                 && attrs.getFitInsetsSides() == 0) {
2179             if (originalMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
2180                 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
2181             }
2182         }
2183         return originalMode;
2184     }
2185 
2186     void handleAppVisibility(boolean visible) {
2187         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
2188             Trace.instant(Trace.TRACE_TAG_VIEW, TextUtils.formatSimple(
2189                     "%s visibilityChanged oldVisibility=%b newVisibility=%b", mTag,
2190                     mAppVisible, visible));
2191         }
2192         if (mAppVisible != visible) {
2193             final boolean previousVisible = getHostVisibility() == View.VISIBLE;
2194             mAppVisible = visible;
2195             final boolean currentVisible = getHostVisibility() == View.VISIBLE;
2196             // Root view only cares about whether it is visible or not.
2197             if (previousVisible != currentVisible) {
2198                 Log.d(mTag, "visibilityChanged oldVisibility=" + previousVisible + " newVisibility="
2199                         + currentVisible);
2200                 mAppVisibilityChanged = true;
2201                 scheduleTraversals();
2202             }
2203             // Only enable if the window is not already removed (via earlier call to doDie())
2204             if (!mRemoved || !mAppVisible) {
2205                 AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
2206             } else if (LOCAL_LOGV) {
2207                 Log.v(mTag, "handleAppVisibility() enabling visibility when removed");
2208             }
2209         }
2210     }
2211 
2212     void handleGetNewSurface() {
2213         mNewSurfaceNeeded = true;
2214         mFullRedrawNeeded = true;
2215         scheduleTraversals();
2216     }
2217 
2218     /** Handles messages {@link #MSG_RESIZED} and {@link #MSG_RESIZED_REPORT}. */
2219     private void handleResized(ClientWindowFrames frames, boolean reportDraw,
2220             MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
2221             boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing,
2222             @Nullable ActivityWindowInfo activityWindowInfo) {
2223         if (!mAdded) {
2224             return;
2225         }
2226 
2227         CompatibilityInfo.applyOverrideScaleIfNeeded(mergedConfiguration);
2228         final Rect frame = frames.frame;
2229         final Rect displayFrame = frames.displayFrame;
2230         final Rect attachedFrame = frames.attachedFrame;
2231         if (mTranslator != null) {
2232             mTranslator.translateInsetsStateInScreenToAppWindow(insetsState);
2233             mTranslator.translateRectInScreenToAppWindow(frame);
2234             mTranslator.translateRectInScreenToAppWindow(displayFrame);
2235             mTranslator.translateRectInScreenToAppWindow(attachedFrame);
2236         }
2237         mInsetsController.onStateChanged(insetsState);
2238         final float compatScale = frames.compatScale;
2239         final boolean frameChanged = !mWinFrame.equals(frame);
2240         final boolean shouldReportActivityWindowInfoChanged =
2241                 // Can be null if callbacks is not set
2242                 mLastReportedActivityWindowInfo != null
2243                         // Can be null if not activity window
2244                         && activityWindowInfo != null
2245                         && !mLastReportedActivityWindowInfo.equals(activityWindowInfo);
2246         final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration)
2247                 || shouldReportActivityWindowInfoChanged;
2248         final boolean attachedFrameChanged =
2249                 !Objects.equals(mTmpFrames.attachedFrame, attachedFrame);
2250         final boolean displayChanged = mDisplay.getDisplayId() != displayId;
2251         final boolean compatScaleChanged = mTmpFrames.compatScale != compatScale;
2252         final boolean dragResizingChanged = mPendingDragResizing != dragResizing;
2253         if (!reportDraw && !frameChanged && !configChanged && !attachedFrameChanged
2254                 && !displayChanged && !forceLayout
2255                 && !compatScaleChanged && !dragResizingChanged) {
2256             return;
2257         }
2258 
2259         mPendingDragResizing = dragResizing;
2260         mTmpFrames.compatScale = compatScale;
2261         mInvCompatScale = 1f / compatScale;
2262 
2263         if (configChanged) {
2264             // If configuration changed - notify about that and, maybe, about move to display.
2265             performConfigurationChange(mergedConfiguration, false /* force */,
2266                     displayChanged ? displayId : INVALID_DISPLAY /* same display */,
2267                     activityWindowInfo);
2268         } else if (displayChanged) {
2269             // Moved to display without config change - report last applied one.
2270             onMovedToDisplay(displayId, mLastConfigurationFromResources);
2271         }
2272 
2273         setFrame(frame, false /* withinRelayout */);
2274         mTmpFrames.displayFrame.set(displayFrame);
2275         if (mTmpFrames.attachedFrame != null && attachedFrame != null) {
2276             mTmpFrames.attachedFrame.set(attachedFrame);
2277         }
2278 
2279         if (mDragResizing && mUseMTRenderer) {
2280             boolean fullscreen = frame.equals(mPendingBackDropFrame);
2281             for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
2282                 mWindowCallbacks.get(i).onWindowSizeIsChanging(mPendingBackDropFrame, fullscreen,
2283                         mAttachInfo.mVisibleInsets, mAttachInfo.mStableInsets);
2284             }
2285         }
2286 
2287         mForceNextWindowRelayout |= forceLayout;
2288         mPendingAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
2289         mSyncSeqId = syncSeqId > mSyncSeqId ? syncSeqId : mSyncSeqId;
2290 
2291         if (reportDraw) {
2292             reportNextDraw("resized");
2293         }
2294 
2295         if (mView != null && (frameChanged || configChanged)) {
2296             forceLayout(mView);
2297         }
2298         requestLayout();
2299     }
2300 
2301     /** Handles messages {@link #MSG_INSETS_CONTROL_CHANGED}. */
handleInsetsControlChanged(@onNull InsetsState insetsState, @NonNull InsetsSourceControl.Array activeControls)2302     private void handleInsetsControlChanged(@NonNull InsetsState insetsState,
2303             @NonNull InsetsSourceControl.Array activeControls) {
2304         final InsetsSourceControl[] controls = activeControls.get();
2305 
2306         if (mTranslator != null) {
2307             mTranslator.translateInsetsStateInScreenToAppWindow(insetsState);
2308             mTranslator.translateSourceControlsInScreenToAppWindow(controls);
2309         }
2310 
2311         // Deliver state change before control change, such that:
2312         // a) When gaining control, controller can compare with server state to evaluate
2313         // whether it needs to run animation.
2314         // b) When loosing control, controller can restore server state by taking last
2315         // dispatched state as truth.
2316         mInsetsController.onStateChanged(insetsState);
2317         if (mAdded) {
2318             mInsetsController.onControlsChanged(controls);
2319         } else {
2320             activeControls.release();
2321         }
2322     }
2323 
2324     private final DisplayListener mDisplayListener = new DisplayListener() {
2325         @Override
2326         public void onDisplayChanged(int displayId) {
2327             if (mExtraDisplayListenerLogging) {
2328                 Slog.i(mTag, "Received onDisplayChanged - " + mView);
2329             }
2330             if (mView != null && mDisplay.getDisplayId() == displayId) {
2331                 final int oldDisplayState = mAttachInfo.mDisplayState;
2332                 final int newDisplayState = mDisplay.getState();
2333                 if (mExtraDisplayListenerLogging) {
2334                     Slog.i(mTag, "DisplayState - old: " + oldDisplayState
2335                             + ", new: " + newDisplayState);
2336                 }
2337                 if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
2338                     Trace.traceCounter(Trace.TRACE_TAG_WINDOW_MANAGER,
2339                             "vri#screenState[" + mTag + "] state=", newDisplayState);
2340                 }
2341                 if (oldDisplayState != newDisplayState) {
2342                     mAttachInfo.mDisplayState = newDisplayState;
2343                     pokeDrawLockIfNeeded();
2344                     if (oldDisplayState != Display.STATE_UNKNOWN) {
2345                         final int oldScreenState = toViewScreenState(oldDisplayState);
2346                         final int newScreenState = toViewScreenState(newDisplayState);
2347                         if (oldScreenState != newScreenState) {
2348                             mView.dispatchScreenStateChanged(newScreenState);
2349                         }
2350                         if (oldDisplayState == Display.STATE_OFF) {
2351                             // Draw was suppressed so we need to for it to happen here.
2352                             mFullRedrawNeeded = true;
2353                             scheduleTraversals();
2354                         }
2355                     }
2356                 }
2357             }
2358         }
2359 
2360         @Override
2361         public void onDisplayRemoved(int displayId) {
2362         }
2363 
2364         @Override
2365         public void onDisplayAdded(int displayId) {
2366         }
2367 
2368         private int toViewScreenState(int displayState) {
2369             return displayState == Display.STATE_OFF ?
2370                     View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
2371         }
2372     };
2373 
2374     /**
2375      * Notify about move to a different display.
2376      * @param displayId The id of the display where this view root is moved to.
2377      * @param config Configuration of the resources on new display after move.
2378      *
2379      * @hide
2380      */
onMovedToDisplay(int displayId, Configuration config)2381     public void onMovedToDisplay(int displayId, Configuration config) {
2382         if (mDisplay.getDisplayId() == displayId) {
2383             return;
2384         }
2385 
2386         // Get new instance of display based on current display adjustments. It may be updated later
2387         // if moving between the displays also involved a configuration change.
2388         updateInternalDisplay(displayId, mView.getResources());
2389         mImeFocusController.onMovedToDisplay();
2390         mAttachInfo.mDisplayState = mDisplay.getState();
2391         // Internal state updated, now notify the view hierarchy.
2392         mView.dispatchMovedToDisplay(mDisplay, config);
2393     }
2394 
2395     /**
2396      * Updates {@link #mDisplay} to the display object corresponding to {@param displayId}.
2397      * Uses DEFAULT_DISPLAY if there isn't a display object in the system corresponding
2398      * to {@param displayId}.
2399      */
updateInternalDisplay(int displayId, Resources resources)2400     private void updateInternalDisplay(int displayId, Resources resources) {
2401         final Display preferredDisplay =
2402                 ResourcesManager.getInstance().getAdjustedDisplay(displayId, resources);
2403         mHdrRenderState.stopListening();
2404         if (preferredDisplay == null) {
2405             // Fallback to use default display.
2406             Slog.w(TAG, "Cannot get desired display with Id: " + displayId);
2407             mDisplay = ResourcesManager.getInstance()
2408                     .getAdjustedDisplay(DEFAULT_DISPLAY, resources);
2409         } else {
2410             mDisplay = preferredDisplay;
2411         }
2412         mHdrRenderState.startListening();
2413         mContext.updateDisplay(mDisplay.getDisplayId());
2414     }
2415 
pokeDrawLockIfNeeded()2416     void pokeDrawLockIfNeeded() {
2417         if (!Display.isDozeState(mAttachInfo.mDisplayState)) {
2418             // Only need to acquire wake lock for DOZE state.
2419             return;
2420         }
2421         if (mWindowAttributes.type != WindowManager.LayoutParams.TYPE_BASE_APPLICATION) {
2422             // Non-activity windows should be responsible to hold wake lock by themself, because
2423             // usually they are system windows.
2424             return;
2425         }
2426         if (mAdded && mTraversalScheduled && mAttachInfo.mHasWindowFocus) {
2427             try {
2428                 mWindowSession.pokeDrawLock(mWindow);
2429             } catch (RemoteException ex) {
2430                 // System server died, oh well.
2431             }
2432         }
2433     }
2434 
2435     @Override
requestFitSystemWindows()2436     public void requestFitSystemWindows() {
2437         checkThread();
2438         mApplyInsetsRequested = true;
2439         scheduleTraversals();
2440     }
2441 
notifyInsetsChanged()2442     void notifyInsetsChanged() {
2443         mApplyInsetsRequested = true;
2444         requestLayout();
2445 
2446         // See comment for View.sForceLayoutWhenInsetsChanged
2447         if (View.sForceLayoutWhenInsetsChanged && mView != null
2448                 && (mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST)
2449                         == SOFT_INPUT_ADJUST_RESIZE) {
2450             forceLayout(mView);
2451         }
2452 
2453         // If this changes during traversal, no need to schedule another one as it will dispatch it
2454         // during the current traversal.
2455         if (!mIsInTraversal) {
2456             scheduleTraversals();
2457         }
2458     }
2459 
2460     /**
2461      * Notify the when the running state of a insets animation changed.
2462      */
2463     @VisibleForTesting
notifyInsetsAnimationRunningStateChanged(boolean running)2464     public void notifyInsetsAnimationRunningStateChanged(boolean running) {
2465         if (sToolkitSetFrameRateReadOnlyFlagValue) {
2466             mInsetsAnimationRunning = running;
2467         }
2468     }
2469 
2470     @Override
requestLayout()2471     public void requestLayout() {
2472         if (!mHandlingLayoutInLayoutRequest) {
2473             checkThread();
2474             mLayoutRequested = true;
2475             scheduleTraversals();
2476         }
2477     }
2478 
2479     @Override
isLayoutRequested()2480     public boolean isLayoutRequested() {
2481         return mLayoutRequested;
2482     }
2483 
2484     @Override
onDescendantInvalidated(@onNull View child, @NonNull View descendant)2485     public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) {
2486         if (sToolkitEnableInvalidateCheckThreadFlagValue) {
2487             checkThread();
2488         }
2489         if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
2490             mIsAnimating = true;
2491         }
2492         invalidate();
2493     }
2494 
2495     @UnsupportedAppUsage
invalidate()2496     void invalidate() {
2497         mDirty.set(0, 0, mWidth, mHeight);
2498         if (!mWillDrawSoon) {
2499             scheduleTraversals();
2500         }
2501     }
2502 
invalidateWorld(View view)2503     void invalidateWorld(View view) {
2504         view.invalidate();
2505         if (view instanceof ViewGroup) {
2506             ViewGroup parent = (ViewGroup) view;
2507             for (int i = 0; i < parent.getChildCount(); i++) {
2508                 invalidateWorld(parent.getChildAt(i));
2509             }
2510         }
2511     }
2512 
2513     @Override
invalidateChild(View child, Rect dirty)2514     public void invalidateChild(View child, Rect dirty) {
2515         invalidateChildInParent(null, dirty);
2516     }
2517 
2518     @Override
invalidateChildInParent(int[] location, Rect dirty)2519     public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
2520         checkThread();
2521         if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
2522 
2523         if (dirty == null) {
2524             invalidate();
2525             return null;
2526         } else if (dirty.isEmpty() && !mIsAnimating) {
2527             return null;
2528         }
2529 
2530         if (mCurScrollY != 0 || mTranslator != null) {
2531             mTempRect.set(dirty);
2532             dirty = mTempRect;
2533             if (mCurScrollY != 0) {
2534                 dirty.offset(0, -mCurScrollY);
2535             }
2536             if (mTranslator != null) {
2537                 mTranslator.translateRectInAppWindowToScreen(dirty);
2538             }
2539             if (mAttachInfo.mScalingRequired) {
2540                 dirty.inset(-1, -1);
2541             }
2542         }
2543 
2544         invalidateRectOnScreen(dirty);
2545 
2546         return null;
2547     }
2548 
invalidateRectOnScreen(Rect dirty)2549     private void invalidateRectOnScreen(Rect dirty) {
2550         if (DEBUG_DRAW) Log.v(mTag, "invalidateRectOnScreen: " + dirty);
2551         final Rect localDirty = mDirty;
2552 
2553         // Add the new dirty rect to the current one
2554         localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
2555         // Intersect with the bounds of the window to skip
2556         // updates that lie outside of the visible region
2557         final float appScale = mAttachInfo.mApplicationScale;
2558         final boolean intersected = localDirty.intersect(0, 0,
2559                 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
2560         if (!intersected) {
2561             localDirty.setEmpty();
2562         }
2563         if (!mWillDrawSoon && (intersected || mIsAnimating)) {
2564             scheduleTraversals();
2565         }
2566     }
2567 
setIsAmbientMode(boolean ambient)2568     public void setIsAmbientMode(boolean ambient) {
2569         mIsAmbientMode = ambient;
2570     }
2571 
setWindowStopped(boolean stopped)2572     void setWindowStopped(boolean stopped) {
2573         checkThread();
2574         if (mStopped != stopped) {
2575             mStopped = stopped;
2576             final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
2577             if (renderer != null) {
2578                 if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
2579                 renderer.setStopped(mStopped);
2580             }
2581             if (!mStopped) {
2582                 // Make sure that relayoutWindow will be called to get valid surface because
2583                 // the previous surface may have been released.
2584                 mAppVisibilityChanged = true;
2585                 scheduleTraversals();
2586             } else {
2587                 if (renderer != null) {
2588                     renderer.destroyHardwareResources(mView);
2589                 }
2590 
2591                 if (mSurface.isValid()) {
2592                     if (mSurfaceHolder != null) {
2593                         notifyHolderSurfaceDestroyed();
2594                     }
2595                     notifySurfaceDestroyed();
2596                 }
2597                 destroySurface();
2598 
2599                 // Reset so they can be sent again for warm starts.
2600                 mAppStartTimestampsSent = false;
2601                 mAppStartTrackingStarted = false;
2602                 mRenderThreadDrawStartTimeNs = -1;
2603                 mFirstFramePresentedTimeNs = -1;
2604             }
2605         }
2606     }
2607 
2608 
2609     /** Register callbacks to be notified when the ViewRootImpl surface changes. */
2610     public interface SurfaceChangedCallback {
surfaceCreated(Transaction t)2611         void surfaceCreated(Transaction t);
surfaceReplaced(Transaction t)2612         void surfaceReplaced(Transaction t);
surfaceDestroyed()2613         void surfaceDestroyed();
vriDrawStarted(boolean isWmSync)2614         default void vriDrawStarted(boolean isWmSync) {};
2615     }
2616 
2617     private final ArrayList<SurfaceChangedCallback> mSurfaceChangedCallbacks = new ArrayList<>();
addSurfaceChangedCallback(SurfaceChangedCallback c)2618     public void addSurfaceChangedCallback(SurfaceChangedCallback c) {
2619         mSurfaceChangedCallbacks.add(c);
2620     }
2621 
removeSurfaceChangedCallback(SurfaceChangedCallback c)2622     public void removeSurfaceChangedCallback(SurfaceChangedCallback c) {
2623         mSurfaceChangedCallbacks.remove(c);
2624     }
2625 
notifySurfaceCreated(Transaction t)2626     private void notifySurfaceCreated(Transaction t) {
2627         for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2628             mSurfaceChangedCallbacks.get(i).surfaceCreated(t);
2629         }
2630     }
2631 
2632     /**
2633      * Notify listeners when the ViewRootImpl surface has been replaced. This callback will not be
2634      * called if a new surface is created, only if the valid surface has been replaced with another
2635      * valid surface.
2636      */
notifySurfaceReplaced(Transaction t)2637     private void notifySurfaceReplaced(Transaction t) {
2638         for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2639             mSurfaceChangedCallbacks.get(i).surfaceReplaced(t);
2640         }
2641     }
2642 
notifySurfaceDestroyed()2643     private void notifySurfaceDestroyed() {
2644         for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2645             mSurfaceChangedCallbacks.get(i).surfaceDestroyed();
2646         }
2647     }
2648 
notifyDrawStarted(boolean isWmSync)2649     private void notifyDrawStarted(boolean isWmSync) {
2650         for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
2651             mSurfaceChangedCallbacks.get(i).vriDrawStarted(isWmSync);
2652         }
2653     }
2654 
2655     /**
2656      * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the
2657      * surface insets. If the layer does not exist, it is created.
2658      *
2659      * <p>Parenting to this layer will ensure that its children are cropped by the view's surface
2660      * insets.
2661      */
updateAndGetBoundsLayer(Transaction t)2662     public SurfaceControl updateAndGetBoundsLayer(Transaction t) {
2663         if (mBoundsLayer == null) {
2664             mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession)
2665                     .setContainerLayer()
2666                     .setName("Bounds for - " + getTitle().toString())
2667                     .setParent(getSurfaceControl())
2668                     .setCallsite("ViewRootImpl.getBoundsLayer")
2669                     .build();
2670             setBoundsLayerCrop(t);
2671             t.show(mBoundsLayer);
2672         }
2673        return mBoundsLayer;
2674     }
2675 
updateBlastSurfaceIfNeeded()2676     void updateBlastSurfaceIfNeeded() {
2677         if (!mSurfaceControl.isValid()) {
2678             return;
2679         }
2680 
2681         if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
2682             mBlastBufferQueue.update(mSurfaceControl,
2683                 mSurfaceSize.x, mSurfaceSize.y,
2684                 mWindowAttributes.format);
2685             return;
2686         }
2687 
2688         // If the SurfaceControl has been updated, destroy and recreate the BBQ to reset the BQ and
2689         // BBQ states.
2690         if (mBlastBufferQueue != null) {
2691             mBlastBufferQueue.destroy();
2692         }
2693         mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
2694                 mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
2695         mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
2696         Surface blastSurface;
2697         if (addSchandleToVriSurface()) {
2698             blastSurface = mBlastBufferQueue.createSurfaceWithHandle();
2699         } else {
2700             blastSurface = mBlastBufferQueue.createSurface();
2701         }
2702         // Only call transferFrom if the surface has changed to prevent inc the generation ID and
2703         // causing EGL resources to be recreated.
2704         mSurface.transferFrom(blastSurface);
2705     }
2706 
setBoundsLayerCrop(Transaction t)2707     private void setBoundsLayerCrop(Transaction t) {
2708         // Adjust of insets and update the bounds layer so child surfaces do not draw into
2709         // the surface inset region.
2710         mTempRect.set(0, 0, mSurfaceSize.x, mSurfaceSize.y);
2711         mTempRect.inset(mWindowAttributes.surfaceInsets.left,
2712                 mWindowAttributes.surfaceInsets.top,
2713                 mWindowAttributes.surfaceInsets.right, mWindowAttributes.surfaceInsets.bottom);
2714         mTempRect.inset(mChildBoundingInsets.left, mChildBoundingInsets.top,
2715             mChildBoundingInsets.right, mChildBoundingInsets.bottom);
2716         t.setWindowCrop(mBoundsLayer, mTempRect);
2717     }
2718 
2719     /**
2720      * Called after window layout to update the bounds surface. If the surface insets have changed
2721      * or the surface has resized, update the bounds surface.
2722      */
updateBoundsLayer(SurfaceControl.Transaction t)2723     private boolean updateBoundsLayer(SurfaceControl.Transaction t) {
2724         if (mBoundsLayer != null) {
2725             setBoundsLayerCrop(t);
2726             return true;
2727         }
2728         return false;
2729     }
2730 
prepareSurfaces()2731     private void prepareSurfaces() {
2732         final SurfaceControl.Transaction t = mTransaction;
2733         final SurfaceControl sc = getSurfaceControl();
2734         if (!sc.isValid()) return;
2735 
2736         if (updateBoundsLayer(t)) {
2737             applyTransactionOnDraw(t);
2738         }
2739 
2740         // Set the frame rate selection strategy to FRAME_RATE_SELECTION_STRATEGY_SELF
2741         // This strategy ensures that the frame rate specifications do not cascade down to
2742         // the descendant layers. This is particularly important for applications like Chrome,
2743         // where child surfaces should adhere to default behavior instead of no preference.
2744         // This issue only happens when ViewRootImpl calls setFrameRateCategory. This is
2745         // no longer needed if the dVRR feature is disabled.
2746         if (shouldEnableDvrr()) {
2747             try {
2748                 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) {
2749                     mFrameRateTransaction.setFrameRateSelectionStrategy(sc,
2750                         sc.FRAME_RATE_SELECTION_STRATEGY_SELF).applyAsyncUnsafe();
2751                 }
2752             } catch (Exception e) {
2753                 Log.e(mTag, "Unable to set frame rate selection strategy ", e);
2754             }
2755         }
2756     }
2757 
destroySurface()2758     private void destroySurface() {
2759         if (mBoundsLayer != null) {
2760             mBoundsLayer.release();
2761             mBoundsLayer = null;
2762         }
2763         mSurface.release();
2764         mSurfaceControl.release();
2765 
2766         if (mBlastBufferQueue != null) {
2767             mBlastBufferQueue.destroy();
2768             mBlastBufferQueue = null;
2769         }
2770 
2771         if (mAttachInfo.mThreadedRenderer != null) {
2772             mAttachInfo.mThreadedRenderer.setSurfaceControl(null, null);
2773         }
2774     }
2775 
2776     /**
2777      * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
2778      * through to allow quick reversal of the Activity Transition.
2779      *
2780      * @param paused true to pause, false to resume.
2781      */
setPausedForTransition(boolean paused)2782     public void setPausedForTransition(boolean paused) {
2783         mPausedForTransition = paused;
2784     }
2785 
2786     @Override
getParent()2787     public ViewParent getParent() {
2788         return null;
2789     }
2790 
2791     @Override
getChildVisibleRect(View child, Rect r, android.graphics.Point offset)2792     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
2793         if (child != mView) {
2794             throw new RuntimeException("child is not mine, honest!");
2795         }
2796         // Note: don't apply scroll offset, because we want to know its
2797         // visibility in the virtual canvas being given to the view hierarchy.
2798         return r.intersect(0, 0, mWidth, mHeight);
2799     }
2800 
2801     @Override
getChildLocalHitRegion(@onNull View child, @NonNull Region region, @NonNull Matrix matrix, boolean isHover)2802     public boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region,
2803             @NonNull Matrix matrix, boolean isHover) {
2804         if (child != mView) {
2805             throw new IllegalArgumentException("child " + child + " is not the root view "
2806                     + mView + " managed by this ViewRootImpl");
2807         }
2808 
2809         RectF rectF = new RectF(0, 0, mWidth, mHeight);
2810         matrix.mapRect(rectF);
2811         // Note: don't apply scroll offset, because we want to know its
2812         // visibility in the virtual canvas being given to the view hierarchy.
2813         return region.op(Math.round(rectF.left), Math.round(rectF.top),
2814                 Math.round(rectF.right), Math.round(rectF.bottom), Region.Op.INTERSECT);
2815     }
2816 
2817     @Override
bringChildToFront(View child)2818     public void bringChildToFront(View child) {
2819     }
2820 
2821     // keep in sync with getHostVisibilityReason
getHostVisibility()2822     int getHostVisibility() {
2823         return mView != null && (mAppVisible || mForceDecorViewVisibility)
2824                 ? mView.getVisibility() : View.GONE;
2825     }
2826 
getHostVisibilityReason()2827     String getHostVisibilityReason() {
2828         if (mView == null) {
2829             return "mView is null";
2830         }
2831         if (!mAppVisible && !mForceDecorViewVisibility) {
2832             return "!mAppVisible && !mForceDecorViewVisibility";
2833         }
2834         switch (mView.getVisibility()) {
2835             case View.VISIBLE: return "View.VISIBLE";
2836             case View.GONE: return "View.GONE";
2837             case View.INVISIBLE: return "View.INVISIBLE";
2838             default: return "";
2839         }
2840     }
2841 
2842     /**
2843      * Add LayoutTransition to the list of transitions to be started in the next traversal.
2844      * This list will be cleared after the transitions on the list are start()'ed. These
2845      * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
2846      * happens during the layout phase of traversal, which we want to complete before any of the
2847      * animations are started (because those animations may side-effect properties that layout
2848      * depends upon, like the bounding rectangles of the affected views). So we add the transition
2849      * to the list and it is started just prior to starting the drawing phase of traversal.
2850      *
2851      * @param transition The LayoutTransition to be started on the next traversal.
2852      *
2853      * @hide
2854      */
requestTransitionStart(LayoutTransition transition)2855     public void requestTransitionStart(LayoutTransition transition) {
2856         if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
2857             if (mPendingTransitions == null) {
2858                  mPendingTransitions = new ArrayList<LayoutTransition>();
2859             }
2860             mPendingTransitions.add(transition);
2861         }
2862     }
2863 
2864     /**
2865      * Notifies the HardwareRenderer that a new frame will be coming soon.
2866      * Currently only {@link ThreadedRenderer} cares about this, and uses
2867      * this knowledge to adjust the scheduling of off-thread animations
2868      */
notifyRendererOfFramePending()2869     void notifyRendererOfFramePending() {
2870         if (mAttachInfo.mThreadedRenderer != null) {
2871             mAttachInfo.mThreadedRenderer.notifyFramePending();
2872         }
2873     }
2874 
2875     /**
2876      * Notifies the HardwareRenderer of an expensive upcoming frame, to
2877      * allow better handling of power and scheduling requirements.
2878      *
2879      * @hide
2880      */
notifyRendererOfExpensiveFrame()2881     public void notifyRendererOfExpensiveFrame() {
2882         if (mAttachInfo.mThreadedRenderer != null) {
2883             mAttachInfo.mThreadedRenderer.notifyExpensiveFrame();
2884         }
2885     }
2886 
2887     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
scheduleTraversals()2888     void scheduleTraversals() {
2889         if (!mTraversalScheduled) {
2890             mTraversalScheduled = true;
2891             mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
2892             mChoreographer.postCallback(
2893                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
2894             notifyRendererOfFramePending();
2895             pokeDrawLockIfNeeded();
2896         }
2897     }
2898 
unscheduleTraversals()2899     void unscheduleTraversals() {
2900         if (mTraversalScheduled) {
2901             mTraversalScheduled = false;
2902             mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
2903             mChoreographer.removeCallbacks(
2904                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
2905         }
2906     }
2907 
doTraversal()2908     void doTraversal() {
2909         if (mTraversalScheduled) {
2910             mTraversalScheduled = false;
2911             mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
2912 
2913             if (mProfile) {
2914                 Debug.startMethodTracing("ViewAncestor");
2915             }
2916 
2917             performTraversals();
2918 
2919             if (mProfile) {
2920                 Debug.stopMethodTracing();
2921                 mProfile = false;
2922             }
2923         }
2924     }
2925 
applyKeepScreenOnFlag(WindowManager.LayoutParams params)2926     private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
2927         // Update window's global keep screen on flag: if a view has requested
2928         // that the screen be kept on, then it is always set; otherwise, it is
2929         // set to whatever the client last requested for the global state.
2930         if (mAttachInfo.mKeepScreenOn) {
2931             params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
2932         } else {
2933             params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
2934                     | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
2935         }
2936     }
2937 
collectViewAttributes()2938     private boolean collectViewAttributes() {
2939         if (mAttachInfo.mRecomputeGlobalAttributes) {
2940             //Log.i(mTag, "Computing view hierarchy attributes!");
2941             mAttachInfo.mRecomputeGlobalAttributes = false;
2942             boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
2943             mAttachInfo.mKeepScreenOn = false;
2944             mAttachInfo.mSystemUiVisibility = 0;
2945             mAttachInfo.mHasSystemUiListeners = false;
2946             mView.dispatchCollectViewAttributes(mAttachInfo, 0);
2947             mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
2948             WindowManager.LayoutParams params = mWindowAttributes;
2949             mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
2950             mCompatibleVisibilityInfo.globalVisibility =
2951                     (mCompatibleVisibilityInfo.globalVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE)
2952                             | (mAttachInfo.mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
2953             dispatchDispatchSystemUiVisibilityChanged();
2954             if (mAttachInfo.mKeepScreenOn != oldScreenOn
2955                     || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
2956                     || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
2957                 applyKeepScreenOnFlag(params);
2958                 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
2959                 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
2960                 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
2961                 return true;
2962             }
2963         }
2964         return false;
2965     }
2966 
getImpliedSystemUiVisibility(WindowManager.LayoutParams params)2967     private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
2968         int vis = 0;
2969         // Translucent decor window flags imply stable system ui visibility.
2970         if ((params.flags & FLAG_TRANSLUCENT_STATUS) != 0) {
2971             vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
2972         }
2973         if ((params.flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) {
2974             vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
2975         }
2976         return vis;
2977     }
2978 
2979     /**
2980      * Update the compatible system UI visibility for dispatching it to the legacy app.
2981      */
updateCompatSysUiVisibility(@nsetsType int visibleTypes, @InsetsType int requestedVisibleTypes, @InsetsType int controllableTypes)2982     void updateCompatSysUiVisibility(@InsetsType int visibleTypes,
2983             @InsetsType int requestedVisibleTypes, @InsetsType int controllableTypes) {
2984         // If a type is controllable, the visibility is overridden by the requested visibility.
2985         visibleTypes =
2986                 (requestedVisibleTypes & controllableTypes) | (visibleTypes & ~controllableTypes);
2987 
2988         updateCompatSystemUiVisibilityInfo(SYSTEM_UI_FLAG_FULLSCREEN, Type.statusBars(),
2989                 visibleTypes, controllableTypes);
2990         updateCompatSystemUiVisibilityInfo(SYSTEM_UI_FLAG_HIDE_NAVIGATION, Type.navigationBars(),
2991                 visibleTypes, controllableTypes);
2992         dispatchDispatchSystemUiVisibilityChanged();
2993     }
2994 
updateCompatSystemUiVisibilityInfo(int systemUiFlag, @InsetsType int insetsType, @InsetsType int visibleTypes, @InsetsType int controllableTypes)2995     private void updateCompatSystemUiVisibilityInfo(int systemUiFlag, @InsetsType int insetsType,
2996             @InsetsType int visibleTypes, @InsetsType int controllableTypes) {
2997         final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
2998         final boolean willBeVisible = (visibleTypes & insetsType) != 0;
2999         final boolean hasControl = (controllableTypes & insetsType) != 0;
3000         final boolean wasInvisible = (mAttachInfo.mSystemUiVisibility & systemUiFlag) != 0;
3001         if (willBeVisible) {
3002             info.globalVisibility &= ~systemUiFlag;
3003             if (hasControl && wasInvisible) {
3004                 // The local system UI visibility can only be cleared while we have the control.
3005                 info.localChanges |= systemUiFlag;
3006             }
3007         } else {
3008             info.globalVisibility |= systemUiFlag;
3009             info.localChanges &= ~systemUiFlag;
3010         }
3011     }
3012 
3013     /**
3014      * If the system is forcing showing any system bar, the legacy low profile flag should be
3015      * cleared for compatibility.
3016      *
3017      * @param showTypes {@link InsetsType types} shown by the system.
3018      * @param fromIme {@code true} if the invocation is from IME.
3019      */
clearLowProfileModeIfNeeded(@nsetsType int showTypes, boolean fromIme)3020     private void clearLowProfileModeIfNeeded(@InsetsType int showTypes, boolean fromIme) {
3021         final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
3022         if ((showTypes & Type.systemBars()) != 0 && !fromIme
3023                 && (info.globalVisibility & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
3024             info.globalVisibility &= ~SYSTEM_UI_FLAG_LOW_PROFILE;
3025             info.localChanges |= SYSTEM_UI_FLAG_LOW_PROFILE;
3026             dispatchDispatchSystemUiVisibilityChanged();
3027         }
3028     }
3029 
dispatchDispatchSystemUiVisibilityChanged()3030     private void dispatchDispatchSystemUiVisibilityChanged() {
3031         if (mDispatchedSystemUiVisibility != mCompatibleVisibilityInfo.globalVisibility) {
3032             mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY);
3033             mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY));
3034         }
3035     }
3036 
handleDispatchSystemUiVisibilityChanged()3037     private void handleDispatchSystemUiVisibilityChanged() {
3038         if (mView == null) {
3039             return;
3040         }
3041         final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
3042         if (info.localChanges != 0) {
3043             mView.updateLocalSystemUiVisibility(info.localValue, info.localChanges);
3044             info.localChanges = 0;
3045         }
3046 
3047         final int visibility = info.globalVisibility & View.SYSTEM_UI_CLEARABLE_FLAGS;
3048         if (mDispatchedSystemUiVisibility != visibility) {
3049             mDispatchedSystemUiVisibility = visibility;
3050             mView.dispatchSystemUiVisibilityChanged(visibility);
3051         }
3052     }
3053 
3054     @VisibleForTesting
adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams, @Appearance int appearanceControlled, boolean behaviorControlled)3055     public static void adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams,
3056             @Appearance int appearanceControlled, boolean behaviorControlled) {
3057         final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility;
3058         final int flags = inOutParams.flags;
3059         final int type = inOutParams.type;
3060         final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST;
3061 
3062         @Appearance int appearance = inOutParams.insetsFlags.appearance;
3063         if ((appearanceControlled & APPEARANCE_LOW_PROFILE_BARS) == 0) {
3064             appearance &= ~APPEARANCE_LOW_PROFILE_BARS;
3065             appearance |= (sysUiVis & SYSTEM_UI_FLAG_LOW_PROFILE) != 0
3066                     ? APPEARANCE_LOW_PROFILE_BARS
3067                     : 0;
3068         }
3069         if ((appearanceControlled & APPEARANCE_LIGHT_STATUS_BARS) == 0) {
3070             appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
3071             appearance |= (sysUiVis & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
3072                     ? APPEARANCE_LIGHT_STATUS_BARS
3073                     : 0;
3074         }
3075         if ((appearanceControlled & APPEARANCE_LIGHT_NAVIGATION_BARS) == 0) {
3076             appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
3077             appearance |= (sysUiVis & SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0
3078                     ? APPEARANCE_LIGHT_NAVIGATION_BARS
3079                     : 0;
3080         }
3081         inOutParams.insetsFlags.appearance = appearance;
3082 
3083         if (!behaviorControlled) {
3084             if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
3085                     || (flags & FLAG_FULLSCREEN) != 0) {
3086                 inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
3087             } else {
3088                 inOutParams.insetsFlags.behavior = BEHAVIOR_DEFAULT;
3089             }
3090         }
3091 
3092         inOutParams.privateFlags &= ~PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
3093 
3094         if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) {
3095             return;
3096         }
3097 
3098         int types = inOutParams.getFitInsetsTypes();
3099         boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility();
3100 
3101         if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0
3102                 || (flags & FLAG_LAYOUT_IN_SCREEN) != 0)
3103                 || (flags & FLAG_TRANSLUCENT_STATUS) != 0) {
3104             types &= ~Type.statusBars();
3105         }
3106         if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
3107                 || (flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) {
3108             types &= ~Type.systemBars();
3109         }
3110         if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
3111             ignoreVis = true;
3112         } else if ((types & Type.systemBars()) == Type.systemBars()) {
3113             if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
3114                 types |= Type.ime();
3115             } else {
3116                 inOutParams.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
3117             }
3118         }
3119         inOutParams.setFitInsetsTypes(types);
3120         inOutParams.setFitInsetsIgnoringVisibility(ignoreVis);
3121 
3122         // The fitting of insets are not really controlled by the clients, so we remove the flag.
3123         inOutParams.privateFlags &= ~PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
3124     }
3125 
controlInsetsForCompatibility(WindowManager.LayoutParams params)3126     private void controlInsetsForCompatibility(WindowManager.LayoutParams params) {
3127         final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility;
3128         final int flags = params.flags;
3129         final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT;
3130         final boolean nonAttachedAppWindow = params.type >= FIRST_APPLICATION_WINDOW
3131                 && params.type <= LAST_APPLICATION_WINDOW;
3132         final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0;
3133         final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0
3134                 || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow);
3135         final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0;
3136         final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3137 
3138         @InsetsType int typesToHide = 0;
3139         @InsetsType int typesToShow = 0;
3140         if (statusIsHiddenByFlags && !statusWasHiddenByFlags) {
3141             typesToHide |= Type.statusBars();
3142         } else if (!statusIsHiddenByFlags && statusWasHiddenByFlags) {
3143             typesToShow |= Type.statusBars();
3144         }
3145         if (navIsHiddenByFlags && !navWasHiddenByFlags) {
3146             typesToHide |= Type.navigationBars();
3147         } else if (!navIsHiddenByFlags && navWasHiddenByFlags) {
3148             typesToShow |= Type.navigationBars();
3149         }
3150         if (typesToHide != 0) {
3151             getInsetsController().hide(typesToHide);
3152         }
3153         if (typesToShow != 0) {
3154             getInsetsController().show(typesToShow);
3155         }
3156         mTypesHiddenByFlags |= typesToHide;
3157         mTypesHiddenByFlags &= ~typesToShow;
3158     }
3159 
measureHierarchy(final View host, final WindowManager.LayoutParams lp, final Resources res, final int desiredWindowWidth, final int desiredWindowHeight, boolean forRootSizeOnly)3160     private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
3161             final Resources res, final int desiredWindowWidth, final int desiredWindowHeight,
3162             boolean forRootSizeOnly) {
3163         int childWidthMeasureSpec;
3164         int childHeightMeasureSpec;
3165         boolean windowSizeMayChange = false;
3166 
3167         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
3168                 "Measuring " + host + " in display " + desiredWindowWidth
3169                 + "x" + desiredWindowHeight + "...");
3170 
3171         boolean goodMeasure = false;
3172         if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
3173             // On large screens, we don't want to allow dialogs to just
3174             // stretch to fill the entire width of the screen to display
3175             // one line of text.  First try doing the layout at a smaller
3176             // size to see if it will fit.
3177             final DisplayMetrics packageMetrics = res.getDisplayMetrics();
3178             res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
3179             int baseSize = 0;
3180             if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
3181                 baseSize = (int)mTmpValue.getDimension(packageMetrics);
3182             }
3183             if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
3184                     + ", desiredWindowWidth=" + desiredWindowWidth);
3185             if (baseSize != 0 && desiredWindowWidth > baseSize) {
3186                 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags);
3187                 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,
3188                         lp.privateFlags);
3189                 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3190                 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
3191                         + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
3192                         + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
3193                         + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
3194                 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
3195                     goodMeasure = true;
3196                 } else {
3197                     // Didn't fit in that size... try expanding a bit.
3198                     baseSize = (baseSize+desiredWindowWidth)/2;
3199                     if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
3200                             + baseSize);
3201                     childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags);
3202                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3203                     if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
3204                             + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
3205                     if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
3206                         if (DEBUG_DIALOG) Log.v(mTag, "Good!");
3207                         goodMeasure = true;
3208                     }
3209                 }
3210             }
3211         }
3212 
3213         if (!goodMeasure) {
3214             childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width,
3215                     lp.privateFlags);
3216             childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,
3217                     lp.privateFlags);
3218             if (!forRootSizeOnly || !setMeasuredRootSizeFromSpec(
3219                     childWidthMeasureSpec, childHeightMeasureSpec)) {
3220                 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3221             } else {
3222                 // We already know how big the window should be before measuring the views.
3223                 // We can measure the views before laying out them. This is to avoid unnecessary
3224                 // measure.
3225                 mViewMeasureDeferred = true;
3226             }
3227             if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
3228                 windowSizeMayChange = true;
3229             }
3230         }
3231 
3232         if (DBG) {
3233             System.out.println("======================================");
3234             System.out.println("performTraversals -- after measure");
3235             host.debug();
3236         }
3237 
3238         return windowSizeMayChange;
3239     }
3240 
3241     /**
3242      * Sets the measured root size for requesting the window frame.
3243      *
3244      * @param widthMeasureSpec contains the size and the mode of the width.
3245      * @param heightMeasureSpec contains the size and the mode of the height.
3246      * @return {@code true} if we actually set the measured size; {@code false} otherwise.
3247      */
setMeasuredRootSizeFromSpec(int widthMeasureSpec, int heightMeasureSpec)3248     private boolean setMeasuredRootSizeFromSpec(int widthMeasureSpec, int heightMeasureSpec) {
3249         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
3250         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
3251         if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
3252             // We don't know the exact size. We need to measure the hierarchy to know that.
3253             return false;
3254         }
3255         mMeasuredWidth = MeasureSpec.getSize(widthMeasureSpec);
3256         mMeasuredHeight = MeasureSpec.getSize(heightMeasureSpec);
3257         return true;
3258     }
3259 
3260     /**
3261      * Modifies the input matrix such that it maps view-local coordinates to
3262      * on-screen coordinates.
3263      *
3264      * @param m input matrix to modify
3265      */
transformMatrixToGlobal(Matrix m)3266     void transformMatrixToGlobal(Matrix m) {
3267         m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
3268     }
3269 
3270     /**
3271      * Modifies the input matrix such that it maps on-screen coordinates to
3272      * view-local coordinates.
3273      *
3274      * @param m input matrix to modify
3275      */
transformMatrixToLocal(Matrix m)3276     void transformMatrixToLocal(Matrix m) {
3277         m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
3278     }
3279 
getWindowInsets(boolean forceConstruct)3280     /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
3281         if (mLastWindowInsets == null || forceConstruct) {
3282             final Configuration config = getConfiguration();
3283             mLastWindowInsets = mInsetsController.calculateInsets(
3284                     config.isScreenRound(), mWindowAttributes.type,
3285                     config.windowConfiguration.getActivityType(), mWindowAttributes.softInputMode,
3286                     mWindowAttributes.flags, (mWindowAttributes.systemUiVisibility
3287                             | mWindowAttributes.subtreeSystemUiVisibility));
3288 
3289             mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect());
3290             mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect());
3291             mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets(
3292                     mWindowAttributes.type, config.windowConfiguration.getActivityType(),
3293                     mWindowAttributes.softInputMode, mWindowAttributes.flags).toRect());
3294         }
3295         return mLastWindowInsets;
3296     }
3297 
dispatchApplyInsets(View host)3298     public void dispatchApplyInsets(View host) {
3299         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchApplyInsets");
3300         mApplyInsetsRequested = false;
3301         WindowInsets insets = getWindowInsets(true /* forceConstruct */);
3302         if (!shouldDispatchCutout()) {
3303             // Window is either not laid out in cutout or the status bar inset takes care of
3304             // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
3305             insets = insets.consumeDisplayCutout();
3306         }
3307         host.dispatchApplyWindowInsets(insets);
3308         mAttachInfo.delayNotifyContentCaptureInsetsEvent(insets.getInsets(Type.all()));
3309         Trace.traceEnd(Trace.TRACE_TAG_VIEW);
3310     }
3311 
shouldDispatchCutout()3312     private boolean shouldDispatchCutout() {
3313         return mWindowAttributes.layoutInDisplayCutoutMode
3314                         == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
3315                 || mWindowAttributes.layoutInDisplayCutoutMode
3316                         == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3317     }
3318 
getInsetsController()3319     public InsetsController getInsetsController() {
3320         return mInsetsController;
3321     }
3322 
shouldUseDisplaySize(final WindowManager.LayoutParams lp)3323     private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
3324         return lp.type == TYPE_STATUS_BAR_ADDITIONAL
3325                 || lp.type == TYPE_INPUT_METHOD
3326                 || lp.type == TYPE_VOLUME_OVERLAY;
3327     }
3328 
3329     /**
3330      * @return {@code true} if we should reduce unnecessary measure for the window.
3331      * TODO(b/260382739): Apply this to all windows.
3332      */
shouldOptimizeMeasure(final WindowManager.LayoutParams lp)3333     private static boolean shouldOptimizeMeasure(final WindowManager.LayoutParams lp) {
3334         return (lp.privateFlags & PRIVATE_FLAG_OPTIMIZE_MEASURE) != 0;
3335     }
3336 
getWindowBoundsInsetSystemBars()3337     private Rect getWindowBoundsInsetSystemBars() {
3338         final Rect bounds = new Rect(
3339                 mContext.getResources().getConfiguration().windowConfiguration.getBounds());
3340         bounds.inset(mInsetsController.getState().calculateInsets(
3341                 bounds, Type.systemBars(), false /* ignoreVisibility */));
3342         return bounds;
3343     }
3344 
dipToPx(int dip)3345     int dipToPx(int dip) {
3346         final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
3347         return (int) (displayMetrics.density * dip + 0.5f);
3348     }
3349 
performTraversals()3350     private void performTraversals() {
3351         mLastPerformTraversalsSkipDrawReason = null;
3352 
3353         // cache mView since it is used so much below...
3354         final View host = mView;
3355         if (DBG) {
3356             System.out.println("======================================");
3357             System.out.println("performTraversals");
3358             host.debug();
3359         }
3360 
3361         if (host == null || !mAdded) {
3362             mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added";
3363             return;
3364         }
3365 
3366         if (mNumPausedForSync > 0) {
3367             if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
3368                 Trace.instant(Trace.TRACE_TAG_VIEW,
3369                         TextUtils.formatSimple("performTraversals#mNumPausedForSync=%d",
3370                                 mNumPausedForSync));
3371             }
3372             if (DEBUG_BLAST) {
3373                 Log.d(mTag, "Skipping traversal due to sync " + mNumPausedForSync);
3374             }
3375             mLastPerformTraversalsSkipDrawReason = "paused_for_sync";
3376             return;
3377         }
3378 
3379         mIsInTraversal = true;
3380         mWillDrawSoon = true;
3381         boolean cancelDraw = false;
3382         String cancelReason = null;
3383         boolean isSyncRequest = false;
3384 
3385         boolean windowSizeMayChange = false;
3386         WindowManager.LayoutParams lp = mWindowAttributes;
3387 
3388         int desiredWindowWidth;
3389         int desiredWindowHeight;
3390 
3391         final int viewVisibility = getHostVisibility();
3392         final String viewVisibilityReason = getHostVisibilityReason();
3393         final boolean viewVisibilityChanged = !mFirst
3394                 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded
3395                 // Also check for possible double visibility update, which will make current
3396                 // viewVisibility value equal to mViewVisibility and we may miss it.
3397                 || mAppVisibilityChanged);
3398         mAppVisibilityChanged = false;
3399         final boolean viewUserVisibilityChanged = !mFirst &&
3400                 ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
3401         final boolean shouldOptimizeMeasure = shouldOptimizeMeasure(lp);
3402 
3403         WindowManager.LayoutParams params = null;
3404         Rect frame = mWinFrame;
3405         if (mFirst) {
3406             mFullRedrawNeeded = true;
3407             mLayoutRequested = true;
3408 
3409             final Configuration config = getConfiguration();
3410             if (shouldUseDisplaySize(lp)) {
3411                 // NOTE -- system code, won't try to do compat mode.
3412                 Point size = new Point();
3413                 mDisplay.getRealSize(size);
3414                 desiredWindowWidth = size.x;
3415                 desiredWindowHeight = size.y;
3416             } else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
3417                     || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
3418                 // For wrap content, we have to remeasure later on anyways. Use size consistent with
3419                 // below so we get best use of the measure cache.
3420                 final Rect bounds = getWindowBoundsInsetSystemBars();
3421                 desiredWindowWidth = bounds.width();
3422                 desiredWindowHeight = bounds.height();
3423             } else {
3424                 // After addToDisplay, the frame contains the frameHint from window manager, which
3425                 // for most windows is going to be the same size as the result of relayoutWindow.
3426                 // Using this here allows us to avoid remeasuring after relayoutWindow
3427                 desiredWindowWidth = frame.width();
3428                 desiredWindowHeight = frame.height();
3429             }
3430 
3431             // We used to use the following condition to choose 32 bits drawing caches:
3432             // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
3433             // However, windows are now always 32 bits by default, so choose 32 bits
3434             mAttachInfo.mUse32BitDrawingCache = true;
3435             mAttachInfo.mWindowVisibility = viewVisibility;
3436             mAttachInfo.mRecomputeGlobalAttributes = false;
3437             mLastConfigurationFromResources.setTo(config);
3438             mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
3439             // Set the layout direction if it has not been set before (inherit is the default)
3440             if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
3441                 host.setLayoutDirection(config.getLayoutDirection());
3442             }
3443             host.dispatchAttachedToWindow(mAttachInfo, 0);
3444             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
3445             dispatchApplyInsets(host);
3446             if (!mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()
3447                     // Don't register compat OnBackInvokedCallback for windowless window.
3448                     // The onBackInvoked event by default should forward to host app, so the
3449                     // host app can decide the behavior.
3450                     && mWindowlessBackKeyCallback == null) {
3451                 // For apps requesting legacy back behavior, we add a compat callback that
3452                 // dispatches {@link KeyEvent#KEYCODE_BACK} to their root views.
3453                 // This way from system point of view, these apps are providing custom
3454                 // {@link OnBackInvokedCallback}s, and will not play system back animations
3455                 // for them.
3456                 registerCompatOnBackInvokedCallback();
3457             }
3458         } else {
3459             desiredWindowWidth = frame.width();
3460             desiredWindowHeight = frame.height();
3461             if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
3462                 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
3463                 mFullRedrawNeeded = true;
3464                 mLayoutRequested = true;
3465                 windowSizeMayChange = true;
3466             }
3467         }
3468 
3469         if (viewVisibilityChanged) {
3470             mAttachInfo.mWindowVisibility = viewVisibility;
3471             host.dispatchWindowVisibilityChanged(viewVisibility);
3472             mAttachInfo.mTreeObserver.dispatchOnWindowVisibilityChange(viewVisibility);
3473             if (viewUserVisibilityChanged) {
3474                 host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
3475             }
3476             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
3477                 endDragResizing();
3478                 destroyHardwareResources();
3479             }
3480 
3481             if (shouldEnableDvrr() && viewVisibility == View.VISIBLE) {
3482                 // Boost frame rate when the viewVisibility becomes true.
3483                 // This is mainly for lanuchers that lanuch new windows.
3484                 boostFrameRate(FRAME_RATE_BOOST_TIME);
3485             }
3486         }
3487 
3488         // Non-visible windows can't hold accessibility focus.
3489         if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
3490             host.clearAccessibilityFocus();
3491         }
3492 
3493         // Execute enqueued actions on every traversal in case a detached view enqueued an action
3494         getRunQueue().executeActions(mAttachInfo.mHandler);
3495 
3496         if (mFirst) {
3497             // make sure touch mode code executes by setting cached value
3498             // to opposite of the added touch mode.
3499             mAttachInfo.mInTouchMode = !mAddedTouchMode;
3500             ensureTouchModeLocally(mAddedTouchMode);
3501         }
3502 
3503         boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
3504         if (layoutRequested) {
3505             if (!mFirst) {
3506                 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
3507                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
3508                     windowSizeMayChange = true;
3509 
3510                     if (shouldUseDisplaySize(lp)) {
3511                         // NOTE -- system code, won't try to do compat mode.
3512                         Point size = new Point();
3513                         mDisplay.getRealSize(size);
3514                         desiredWindowWidth = size.x;
3515                         desiredWindowHeight = size.y;
3516                     } else {
3517                         final Rect bounds = getWindowBoundsInsetSystemBars();
3518                         desiredWindowWidth = bounds.width();
3519                         desiredWindowHeight = bounds.height();
3520                     }
3521                 }
3522             }
3523 
3524             // Ask host how big it wants to be
3525             windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(),
3526                     desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure);
3527         }
3528 
3529         if (collectViewAttributes()) {
3530             params = lp;
3531         }
3532         if (mAttachInfo.mForceReportNewAttributes) {
3533             mAttachInfo.mForceReportNewAttributes = false;
3534             params = lp;
3535         }
3536 
3537         if (mFirst || mAttachInfo.mViewVisibilityChanged) {
3538             mAttachInfo.mViewVisibilityChanged = false;
3539             int resizeMode = mSoftInputMode & SOFT_INPUT_MASK_ADJUST;
3540             // If we are in auto resize mode, then we need to determine
3541             // what mode to use now.
3542             if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
3543                 final int N = mAttachInfo.mScrollContainers.size();
3544                 for (int i=0; i<N; i++) {
3545                     if (mAttachInfo.mScrollContainers.get(i).isShown()) {
3546                         resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
3547                     }
3548                 }
3549                 if (resizeMode == 0) {
3550                     resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
3551                 }
3552                 if ((lp.softInputMode & SOFT_INPUT_MASK_ADJUST) != resizeMode) {
3553                     lp.softInputMode = (lp.softInputMode & ~SOFT_INPUT_MASK_ADJUST) | resizeMode;
3554                     params = lp;
3555                 }
3556             }
3557         }
3558 
3559         if (mApplyInsetsRequested) {
3560             dispatchApplyInsets(host);
3561             if (mLayoutRequested) {
3562                 // Short-circuit catching a new layout request here, so
3563                 // we don't need to go through two layout passes when things
3564                 // change due to fitting system windows, which can happen a lot.
3565                 windowSizeMayChange |= measureHierarchy(host, lp,
3566                         mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight,
3567                         shouldOptimizeMeasure);
3568             }
3569         }
3570 
3571         if (layoutRequested) {
3572             // Clear this now, so that if anything requests a layout in the
3573             // rest of this function we will catch it and re-run a full
3574             // layout pass.
3575             mLayoutRequested = false;
3576         }
3577 
3578         boolean windowShouldResize = layoutRequested && windowSizeMayChange
3579             && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
3580                 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
3581                         frame.width() < desiredWindowWidth && frame.width() != mWidth)
3582                 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
3583                         frame.height() < desiredWindowHeight && frame.height() != mHeight));
3584         windowShouldResize |= mDragResizing && mPendingDragResizing;
3585 
3586         // Determine whether to compute insets.
3587         // If there are no inset listeners remaining then we may still need to compute
3588         // insets in case the old insets were non-empty and must be reset.
3589         final boolean computesInternalInsets =
3590                 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
3591                 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
3592 
3593         boolean insetsPending = false;
3594         int relayoutResult = 0;
3595         boolean updatedConfiguration = false;
3596 
3597         final int surfaceGenerationId = mSurface.getGenerationId();
3598 
3599         final boolean isViewVisible = viewVisibility == View.VISIBLE;
3600         boolean surfaceSizeChanged = false;
3601         boolean surfaceCreated = false;
3602         boolean surfaceDestroyed = false;
3603         // True if surface generation id changes or relayout result is RELAYOUT_RES_SURFACE_CHANGED.
3604         boolean surfaceReplaced = false;
3605 
3606         final boolean windowAttributesChanged = mWindowAttributesChanged;
3607         if (windowAttributesChanged) {
3608             mWindowAttributesChanged = false;
3609             params = lp;
3610         }
3611 
3612         if (params != null) {
3613             if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0
3614                     && !PixelFormat.formatHasAlpha(params.format)) {
3615                 params.format = PixelFormat.TRANSLUCENT;
3616             }
3617             adjustLayoutParamsForCompatibility(params,
3618                     mInsetsController.getAppearanceControlled(),
3619                     mInsetsController.isBehaviorControlled());
3620             controlInsetsForCompatibility(params);
3621             if (mDispatchedSystemBarAppearance != params.insetsFlags.appearance) {
3622                 mDispatchedSystemBarAppearance = params.insetsFlags.appearance;
3623                 mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance);
3624             }
3625         }
3626 
3627         if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
3628                 || mForceNextWindowRelayout) {
3629             if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
3630                 Trace.traceBegin(Trace.TRACE_TAG_VIEW,
3631                         TextUtils.formatSimple("%s-relayoutWindow#"
3632                                         + "first=%b/resize=%b/vis=%b/params=%b/force=%b", mTag,
3633                                 mFirst, windowShouldResize, viewVisibilityChanged, params != null,
3634                                 mForceNextWindowRelayout));
3635             }
3636 
3637             mForceNextWindowRelayout = false;
3638 
3639             // If this window is giving internal insets to the window manager, then we want to first
3640             // make the provided insets unchanged during layout. This avoids it briefly causing
3641             // other windows to resize/move based on the raw frame of the window, waiting until we
3642             // can finish laying out this window and get back to the window manager with the
3643             // ultimately computed insets.
3644             insetsPending = computesInternalInsets
3645                     // If this window provides insets via params, its insets source frame can be
3646                     // updated directly without waiting for WindowSession#setInsets.
3647                     && mWindowAttributes.providedInsets == null;
3648 
3649             if (mSurfaceHolder != null) {
3650                 mSurfaceHolder.mSurfaceLock.lock();
3651                 mDrawingAllowed = true;
3652             }
3653 
3654             boolean hwInitialized = false;
3655             boolean dispatchApplyInsets = false;
3656             boolean hadSurface = mSurface.isValid();
3657 
3658             try {
3659                 if (DEBUG_LAYOUT) {
3660                     Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
3661                             host.getMeasuredHeight() + ", params=" + params);
3662                 }
3663 
3664                 if (mFirst || viewVisibilityChanged) {
3665                     mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
3666                 }
3667                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
3668                 cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW)
3669                         == RELAYOUT_RES_CANCEL_AND_REDRAW;
3670                 cancelReason = "relayout";
3671                 final boolean dragResizing = mPendingDragResizing;
3672                 if (mSyncSeqId > mLastSyncSeqId) {
3673                     mLastSyncSeqId = mSyncSeqId;
3674                     if (DEBUG_BLAST) {
3675                         Log.d(mTag, "Relayout called with blastSync");
3676                     }
3677                     reportNextDraw("relayout");
3678                     mSyncBuffer = true;
3679                     isSyncRequest = true;
3680                     if (!cancelDraw) {
3681                         mDrewOnceForSync = false;
3682                     }
3683                 }
3684 
3685                 final boolean surfaceControlChanged =
3686                         (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
3687                                 == RELAYOUT_RES_SURFACE_CHANGED;
3688 
3689                 if (mSurfaceControl.isValid()) {
3690                     updateOpacity(mWindowAttributes, dragResizing,
3691                             surfaceControlChanged /*forceUpdate */);
3692                     // No need to updateDisplayDecoration if it's a new SurfaceControl and
3693                     // mDisplayDecorationCached is false, since that's the default for a new
3694                     // SurfaceControl.
3695                     if (surfaceControlChanged && mDisplayDecorationCached) {
3696                         updateDisplayDecoration();
3697                     }
3698                     if (surfaceControlChanged
3699                             && mWindowAttributes.type
3700                             == WindowManager.LayoutParams.TYPE_STATUS_BAR) {
3701                         mTransaction.setDefaultFrameRateCompatibility(mSurfaceControl,
3702                             Surface.FRAME_RATE_COMPATIBILITY_NO_VOTE).apply();
3703                     }
3704 
3705                     if (setScPropertiesInClient()) {
3706                         if (surfaceControlChanged || windowAttributesChanged) {
3707                             boolean colorSpaceAgnostic = (lp.privateFlags
3708                                     & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC)
3709                                     != 0;
3710                             mTransaction.setColorSpaceAgnostic(mSurfaceControl, colorSpaceAgnostic)
3711                                     .apply();
3712                         }
3713                     }
3714                 }
3715 
3716                 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
3717                         + " surface=" + mSurface);
3718 
3719                 // If the pending {@link MergedConfiguration} handed back from
3720                 // {@link #relayoutWindow} does not match the one last reported,
3721                 // WindowManagerService has reported back a frame from a configuration not yet
3722                 // handled by the client. In this case, we need to accept the configuration so we
3723                 // do not lay out and draw with the wrong configuration.
3724                 boolean shouldPerformConfigurationUpdate =
3725                         !mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)
3726                                 || !Objects.equals(mPendingActivityWindowInfo,
3727                                 mLastReportedActivityWindowInfo);
3728                 if (mRelayoutRequested && shouldPerformConfigurationUpdate) {
3729                     if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
3730                             + mPendingMergedConfiguration.getMergedConfiguration());
3731                     performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration),
3732                             !mFirst, INVALID_DISPLAY /* same display */,
3733                             mPendingActivityWindowInfo != null
3734                                     ? new ActivityWindowInfo(mPendingActivityWindowInfo)
3735                                     : null);
3736                     updatedConfiguration = true;
3737                 }
3738                 final boolean updateSurfaceNeeded = mUpdateSurfaceNeeded;
3739                 mUpdateSurfaceNeeded = false;
3740 
3741                 surfaceSizeChanged = false;
3742                 if (!mLastSurfaceSize.equals(mSurfaceSize)) {
3743                     surfaceSizeChanged = true;
3744                     mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y);
3745                 }
3746                 final boolean alwaysConsumeSystemBarsChanged =
3747                         mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
3748                 updateColorModeIfNeeded(lp.getColorMode(), lp.getDesiredHdrHeadroom());
3749                 surfaceCreated = !hadSurface && mSurface.isValid();
3750                 surfaceDestroyed = hadSurface && !mSurface.isValid();
3751 
3752                 // When using Blast, the surface generation id may not change when there's a new
3753                 // SurfaceControl. In that case, we also check relayout flag
3754                 // RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
3755                 // SurfaceControl.
3756                 surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()
3757                         || surfaceControlChanged) && mSurface.isValid();
3758                 if (surfaceReplaced) {
3759                     mSurfaceSequenceId++;
3760                 }
3761                 if (alwaysConsumeSystemBarsChanged) {
3762                     mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars;
3763                     dispatchApplyInsets = true;
3764                 }
3765                 if (dispatchApplyInsets || mLastSystemUiVisibility !=
3766                         mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) {
3767                     mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
3768                     dispatchApplyInsets(host);
3769                     // We applied insets so force contentInsetsChanged to ensure the
3770                     // hierarchy is measured below.
3771                     dispatchApplyInsets = true;
3772                 }
3773 
3774                 if (surfaceCreated) {
3775                     // If we are creating a new surface, then we need to
3776                     // completely redraw it.
3777                     mFullRedrawNeeded = true;
3778                     mPreviousTransparentRegion.setEmpty();
3779 
3780                     // Only initialize up-front if transparent regions are not
3781                     // requested, otherwise defer to see if the entire window
3782                     // will be transparent
3783                     if (mAttachInfo.mThreadedRenderer != null) {
3784                         try {
3785                             hwInitialized = mAttachInfo.mThreadedRenderer.initialize(mSurface);
3786                             if (hwInitialized && (host.mPrivateFlags
3787                                             & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
3788                                 // Don't pre-allocate if transparent regions
3789                                 // are requested as they may not be needed
3790                                 mAttachInfo.mThreadedRenderer.allocateBuffers();
3791                             }
3792                         } catch (OutOfResourcesException e) {
3793                             handleOutOfResourcesException(e);
3794                             mLastPerformTraversalsSkipDrawReason = "oom_initialize_renderer";
3795                             return;
3796                         }
3797                     }
3798                 } else if (surfaceDestroyed) {
3799                     // If the surface has been removed, then reset the scroll
3800                     // positions.
3801                     if (mLastScrolledFocus != null) {
3802                         mLastScrolledFocus.clear();
3803                     }
3804                     mScrollY = mCurScrollY = 0;
3805                     if (mView instanceof RootViewSurfaceTaker) {
3806                         ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
3807                     }
3808                     if (mScroller != null) {
3809                         mScroller.abortAnimation();
3810                     }
3811                     // Our surface is gone
3812                     if (isHardwareEnabled()) {
3813                         mAttachInfo.mThreadedRenderer.destroy();
3814                     }
3815                 } else if ((surfaceReplaced || surfaceSizeChanged || updateSurfaceNeeded)
3816                         && mSurfaceHolder == null
3817                         && mAttachInfo.mThreadedRenderer != null
3818                         && mSurface.isValid()) {
3819                     mFullRedrawNeeded = true;
3820                     try {
3821                         // Need to do updateSurface (which leads to CanvasContext::setSurface and
3822                         // re-create the EGLSurface) if either the Surface changed (as indicated by
3823                         // generation id), or WindowManager changed the surface size. The latter is
3824                         // because on some chips, changing the consumer side's BufferQueue size may
3825                         // not take effect immediately unless we create a new EGLSurface.
3826                         // Note that frame size change doesn't always imply surface size change (eg.
3827                         // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
3828                         // flag from WindowManager.
3829                         mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
3830                     } catch (OutOfResourcesException e) {
3831                         handleOutOfResourcesException(e);
3832                         mLastPerformTraversalsSkipDrawReason = "oom_update_surface";
3833                         return;
3834                     }
3835                 }
3836 
3837                 if (mDragResizing != dragResizing) {
3838                     if (dragResizing) {
3839                         final boolean backdropSizeMatchesFrame =
3840                                 mWinFrame.width() == mPendingBackDropFrame.width()
3841                                         && mWinFrame.height() == mPendingBackDropFrame.height();
3842                         // TODO: Need cutout?
3843                         startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame,
3844                                 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets);
3845                     } else {
3846                         // We shouldn't come here, but if we come we should end the resize.
3847                         endDragResizing();
3848                     }
3849                 }
3850                 if (!mUseMTRenderer) {
3851                     if (dragResizing) {
3852                         mCanvasOffsetX = mWinFrame.left;
3853                         mCanvasOffsetY = mWinFrame.top;
3854                     } else {
3855                         mCanvasOffsetX = mCanvasOffsetY = 0;
3856                     }
3857                 }
3858             } catch (RemoteException e) {
3859             } finally {
3860                 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
3861                     Trace.traceEnd(Trace.TRACE_TAG_VIEW);
3862                 }
3863             }
3864 
3865             if (DEBUG_ORIENTATION) Log.v(
3866                     TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
3867 
3868             mAttachInfo.mWindowLeft = frame.left;
3869             mAttachInfo.mWindowTop = frame.top;
3870 
3871             // !!FIXME!! This next section handles the case where we did not get the
3872             // window size we asked for. We should avoid this by getting a maximum size from
3873             // the window session beforehand.
3874             if (mWidth != frame.width() || mHeight != frame.height()) {
3875                 mWidth = frame.width();
3876                 mHeight = frame.height();
3877             }
3878 
3879             if (mSurfaceHolder != null) {
3880                 // The app owns the surface; tell it about what is going on.
3881                 if (mSurface.isValid()) {
3882                     // XXX .copyFrom() doesn't work!
3883                     //mSurfaceHolder.mSurface.copyFrom(mSurface);
3884                     mSurfaceHolder.mSurface = mSurface;
3885                 }
3886                 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
3887                 mSurfaceHolder.mSurfaceLock.unlock();
3888                 if (surfaceCreated) {
3889                     mSurfaceHolder.ungetCallbacks();
3890 
3891                     mIsCreating = true;
3892                     SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
3893                     if (callbacks != null) {
3894                         for (SurfaceHolder.Callback c : callbacks) {
3895                             c.surfaceCreated(mSurfaceHolder);
3896                         }
3897                     }
3898                 }
3899 
3900                 if ((surfaceCreated || surfaceReplaced || surfaceSizeChanged
3901                         || windowAttributesChanged) && mSurface.isValid()) {
3902                     SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
3903                     if (callbacks != null) {
3904                         for (SurfaceHolder.Callback c : callbacks) {
3905                             c.surfaceChanged(mSurfaceHolder, lp.format,
3906                                     mWidth, mHeight);
3907                         }
3908                     }
3909                     mIsCreating = false;
3910                 }
3911 
3912                 if (surfaceDestroyed) {
3913                     notifyHolderSurfaceDestroyed();
3914                     mSurfaceHolder.mSurfaceLock.lock();
3915                     try {
3916                         mSurfaceHolder.mSurface = new Surface();
3917                     } finally {
3918                         mSurfaceHolder.mSurfaceLock.unlock();
3919                     }
3920                 }
3921             }
3922 
3923             final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer;
3924             if (threadedRenderer != null && threadedRenderer.isEnabled()) {
3925                 if (hwInitialized
3926                         || mWidth != threadedRenderer.getWidth()
3927                         || mHeight != threadedRenderer.getHeight()
3928                         || mNeedsRendererSetup) {
3929                     threadedRenderer.setup(mWidth, mHeight, mAttachInfo,
3930                             mWindowAttributes.surfaceInsets);
3931                     mNeedsRendererSetup = false;
3932                 }
3933             }
3934 
3935             // TODO: In the CL "ViewRootImpl: Fix issue with early draw report in
3936             // seamless rotation". We moved processing of RELAYOUT_RES_BLAST_SYNC
3937             // earlier in the function, potentially triggering a call to
3938             // reportNextDraw(). That same CL changed this and the next reference
3939             // to wasReportNextDraw, such that this logic would remain undisturbed
3940             // (it continues to operate as if the code was never moved). This was
3941             // done to achieve a more hermetic fix for S, but it's entirely
3942             // possible that checking the most recent value is actually more
3943             // correct here.
3944             if (!mStopped || mReportNextDraw) {
3945                 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
3946                         || dispatchApplyInsets || updatedConfiguration) {
3947                     int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
3948                             lp.privateFlags);
3949                     int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
3950                             lp.privateFlags);
3951 
3952                     if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed!  mWidth="
3953                             + mWidth + " measuredWidth=" + host.getMeasuredWidth()
3954                             + " mHeight=" + mHeight
3955                             + " measuredHeight=" + host.getMeasuredHeight()
3956                             + " dispatchApplyInsets=" + dispatchApplyInsets);
3957 
3958                      // Ask host how big it wants to be
3959                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3960 
3961                     // Implementation of weights from WindowManager.LayoutParams
3962                     // We just grow the dimensions as needed and re-measure if
3963                     // needs be
3964                     int width = host.getMeasuredWidth();
3965                     int height = host.getMeasuredHeight();
3966                     boolean measureAgain = false;
3967 
3968                     if (lp.horizontalWeight > 0.0f) {
3969                         width += (int) ((mWidth - width) * lp.horizontalWeight);
3970                         childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
3971                                 MeasureSpec.EXACTLY);
3972                         measureAgain = true;
3973                     }
3974                     if (lp.verticalWeight > 0.0f) {
3975                         height += (int) ((mHeight - height) * lp.verticalWeight);
3976                         childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
3977                                 MeasureSpec.EXACTLY);
3978                         measureAgain = true;
3979                     }
3980 
3981                     if (measureAgain) {
3982                         if (DEBUG_LAYOUT) Log.v(mTag,
3983                                 "And hey let's measure once more: width=" + width
3984                                 + " height=" + height);
3985                         performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
3986                     }
3987 
3988                     layoutRequested = true;
3989                 }
3990             }
3991         } else {
3992             // Not the first pass and no window/insets/visibility change but the window
3993             // may have moved and we need check that and if so to update the left and right
3994             // in the attach info. We translate only the window frame since on window move
3995             // the window manager tells us only for the new frame but the insets are the
3996             // same and we do not want to translate them more than once.
3997             maybeHandleWindowMove(frame);
3998         }
3999 
4000         if (mViewMeasureDeferred) {
4001             // It's time to measure the views since we are going to layout them.
4002             performMeasure(
4003                     MeasureSpec.makeMeasureSpec(frame.width(), MeasureSpec.EXACTLY),
4004                     MeasureSpec.makeMeasureSpec(frame.height(), MeasureSpec.EXACTLY));
4005         }
4006 
4007         if (!mRelayoutRequested && mCheckIfCanDraw) {
4008             // We had a sync previously, but we didn't call IWindowSession#relayout in this
4009             // traversal. So we don't know if the sync is complete that we can continue to draw.
4010             // Here invokes cancelDraw to obtain the information.
4011             try {
4012                 cancelDraw = mWindowSession.cancelDraw(mWindow);
4013                 cancelReason = "wm_sync";
4014                 if (DEBUG_BLAST) {
4015                     Log.d(mTag, "cancelDraw returned " + cancelDraw);
4016                 }
4017             } catch (RemoteException e) {
4018             }
4019         }
4020 
4021         if (surfaceSizeChanged || surfaceReplaced || surfaceCreated ||
4022             windowAttributesChanged || mChildBoundingInsetsChanged) {
4023             // If the surface has been replaced, there's a chance the bounds layer is not parented
4024             // to the new layer. When updating bounds layer, also reparent to the main VRI
4025             // SurfaceControl to ensure it's correctly placed in the hierarchy.
4026             //
4027             // This needs to be done on the client side since WMS won't reparent the children to the
4028             // new surface if it thinks the app is closing. WMS gets the signal that the app is
4029             // stopping, but on the client side it doesn't get stopped since it's restarted quick
4030             // enough. WMS doesn't want to keep around old children since they will leak when the
4031             // client creates new children.
4032             prepareSurfaces();
4033             mChildBoundingInsetsChanged = false;
4034         }
4035 
4036         final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
4037         boolean triggerGlobalLayoutListener = didLayout
4038                 || mAttachInfo.mRecomputeGlobalAttributes;
4039         if (didLayout) {
4040             performLayout(lp, mWidth, mHeight);
4041 
4042             // By this point all views have been sized and positioned
4043             // We can compute the transparent area
4044 
4045             if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
4046                 // start out transparent
4047                 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
4048                 host.getLocationInWindow(mTmpLocation);
4049                 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
4050                         mTmpLocation[0] + host.mRight - host.mLeft,
4051                         mTmpLocation[1] + host.mBottom - host.mTop);
4052 
4053                 host.gatherTransparentRegion(mTransparentRegion);
4054                 final Rect bounds = mAttachInfo.mTmpInvalRect;
4055                 if (getAccessibilityFocusedRect(bounds)) {
4056                   host.applyDrawableToTransparentRegion(getAccessibilityFocusedDrawable(),
4057                       mTransparentRegion);
4058                 }
4059                 if (mTranslator != null) {
4060                     mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
4061                 }
4062 
4063                 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
4064                     mPreviousTransparentRegion.set(mTransparentRegion);
4065                     mFullRedrawNeeded = true;
4066                     // TODO: Ideally we would do this in prepareSurfaces,
4067                     // but prepareSurfaces is currently working under
4068                     // the assumption that we paused the render thread
4069                     // via the WM relayout code path. We probably eventually
4070                     // want to synchronize transparent region hint changes
4071                     // with draws.
4072                     SurfaceControl sc = getSurfaceControl();
4073                     if (sc.isValid()) {
4074                         mTransaction.setTransparentRegionHint(sc, mTransparentRegion).apply();
4075                     }
4076                 }
4077             }
4078 
4079             if (DBG) {
4080                 System.out.println("======================================");
4081                 System.out.println("performTraversals -- after setFrame");
4082                 host.debug();
4083             }
4084         }
4085 
4086         boolean didUseTransaction = false;
4087         // These callbacks will trigger SurfaceView SurfaceHolder.Callbacks and must be invoked
4088         // after the measure pass. If its invoked before the measure pass and the app modifies
4089         // the view hierarchy in the callbacks, we could leave the views in a broken state.
4090         if (surfaceCreated) {
4091             notifySurfaceCreated(mTransaction);
4092             didUseTransaction = true;
4093         } else if (surfaceReplaced) {
4094             notifySurfaceReplaced(mTransaction);
4095             didUseTransaction = true;
4096         } else if (surfaceDestroyed)  {
4097             notifySurfaceDestroyed();
4098         }
4099 
4100         if (didUseTransaction) {
4101             applyTransactionOnDraw(mTransaction);
4102         }
4103 
4104         if (triggerGlobalLayoutListener) {
4105             mAttachInfo.mRecomputeGlobalAttributes = false;
4106             mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
4107         }
4108 
4109         Rect contentInsets = null;
4110         Rect visibleInsets = null;
4111         Region touchableRegion = null;
4112         int touchableInsetMode = TOUCHABLE_INSETS_REGION;
4113         boolean computedInternalInsets = false;
4114         if (computesInternalInsets) {
4115             final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
4116 
4117             // Clear the original insets.
4118             insets.reset();
4119 
4120             // Compute new insets in place.
4121             mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
4122             mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
4123 
4124             // Tell the window manager.
4125             if (insetsPending || !mLastGivenInsets.equals(insets)) {
4126                 mLastGivenInsets.set(insets);
4127 
4128                 // Translate insets to screen coordinates if needed.
4129                 if (mTranslator != null) {
4130                     contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
4131                     visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
4132                     touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
4133                 } else {
4134                     contentInsets = insets.contentInsets;
4135                     visibleInsets = insets.visibleInsets;
4136                     touchableRegion = insets.touchableRegion;
4137                 }
4138                 computedInternalInsets = true;
4139             }
4140             touchableInsetMode = insets.mTouchableInsets;
4141         }
4142         boolean needsSetInsets = computedInternalInsets;
4143         needsSetInsets |= !Objects.equals(mPreviousTouchableRegion, mTouchableRegion) &&
4144             (mTouchableRegion != null);
4145         if (needsSetInsets) {
4146             if (mTouchableRegion != null) {
4147                 if (mPreviousTouchableRegion == null) {
4148                     mPreviousTouchableRegion = new Region();
4149                 }
4150                 mPreviousTouchableRegion.set(mTouchableRegion);
4151                 if (touchableInsetMode != TOUCHABLE_INSETS_REGION) {
4152                     Log.e(mTag, "Setting touchableInsetMode to non TOUCHABLE_INSETS_REGION" +
4153                           " from OnComputeInternalInsets, while also using setTouchableRegion" +
4154                           " causes setTouchableRegion to be ignored");
4155                 }
4156             } else {
4157                 mPreviousTouchableRegion = null;
4158             }
4159             if (contentInsets == null) contentInsets = new Rect(0,0,0,0);
4160             if (visibleInsets == null) visibleInsets = new Rect(0,0,0,0);
4161             if (touchableRegion == null) {
4162                 touchableRegion = mTouchableRegion;
4163             } else if (touchableRegion != null && mTouchableRegion != null) {
4164                 touchableRegion.op(touchableRegion, mTouchableRegion, Region.Op.UNION);
4165             }
4166             try {
4167                 mWindowSession.setInsets(mWindow, touchableInsetMode,
4168                                          contentInsets, visibleInsets, touchableRegion);
4169             } catch (RemoteException e) {
4170                 throw e.rethrowFromSystemServer();
4171             }
4172         } else if (mTouchableRegion == null && mPreviousTouchableRegion != null) {
4173             mPreviousTouchableRegion = null;
4174             try {
4175                 mWindowSession.clearTouchableRegion(mWindow);
4176             } catch (RemoteException e) {
4177                 throw e.rethrowFromSystemServer();
4178             }
4179         }
4180 
4181         if (mFirst) {
4182             if (sAlwaysAssignFocus || !isInTouchMode()) {
4183                 // handle first focus request
4184                 if (DEBUG_INPUT_RESIZE) {
4185                     Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus());
4186                 }
4187                 if (mView != null) {
4188                     if (!mView.hasFocus()) {
4189                         mView.restoreDefaultFocus();
4190                         if (DEBUG_INPUT_RESIZE) {
4191                             Log.v(mTag, "First: requested focused view=" + mView.findFocus());
4192                         }
4193                     } else {
4194                         if (DEBUG_INPUT_RESIZE) {
4195                             Log.v(mTag, "First: existing focused view=" + mView.findFocus());
4196                         }
4197                     }
4198                 }
4199             } else {
4200                 // Some views (like ScrollView) won't hand focus to descendants that aren't within
4201                 // their viewport. Before layout, there's a good change these views are size 0
4202                 // which means no children can get focus. After layout, this view now has size, but
4203                 // is not guaranteed to hand-off focus to a focusable child (specifically, the edge-
4204                 // case where the child has a size prior to layout and thus won't trigger
4205                 // focusableViewAvailable).
4206                 View focused = mView.findFocus();
4207                 if (focused instanceof ViewGroup
4208                         && ((ViewGroup) focused).getDescendantFocusability()
4209                                 == ViewGroup.FOCUS_AFTER_DESCENDANTS) {
4210                     focused.restoreDefaultFocus();
4211                 }
4212             }
4213 
4214             if (shouldEnableDvrr()) {
4215                 // Boost the frame rate when the ViewRootImpl first becomes available.
4216                 boostFrameRate(FRAME_RATE_BOOST_TIME);
4217             }
4218         }
4219 
4220         final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
4221         if (changedVisibility) {
4222             maybeFireAccessibilityWindowStateChangedEvent();
4223         }
4224 
4225         mFirst = false;
4226         mWillDrawSoon = false;
4227         mNewSurfaceNeeded = false;
4228         mViewVisibility = viewVisibility;
4229 
4230         final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
4231         mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
4232 
4233         if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
4234             reportNextDraw("first_relayout");
4235         }
4236 
4237         mCheckIfCanDraw = isSyncRequest || cancelDraw;
4238 
4239         boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
4240         boolean cancelAndRedraw = cancelDueToPreDrawListener
4241                  || (cancelDraw && mDrewOnceForSync);
4242 
4243         if (!cancelAndRedraw) {
4244             // A sync was already requested before the WMS requested sync. This means we need to
4245             // sync the buffer, regardless if WMS wants to sync the buffer.
4246             if (mActiveSurfaceSyncGroup != null) {
4247                 mSyncBuffer = true;
4248             }
4249 
4250             createSyncIfNeeded();
4251             notifyDrawStarted(isInWMSRequestedSync());
4252             mDrewOnceForSync = true;
4253 
4254             // If the active SSG is also requesting to sync a buffer, the following needs to happen
4255             // 1. Ensure we keep track of the number of active syncs to know when to disable RT
4256             //    RT animations that conflict with syncing a buffer.
4257             // 2. Add a safeguard SSG to prevent multiple SSG that sync buffers from being submitted
4258             //    out of order.
4259             if (mActiveSurfaceSyncGroup != null && mSyncBuffer) {
4260                 updateSyncInProgressCount(mActiveSurfaceSyncGroup);
4261                 safeguardOverlappingSyncs(mActiveSurfaceSyncGroup);
4262             }
4263         }
4264 
4265         if (!isViewVisible) {
4266             if (mLastTraversalWasVisible) {
4267                 logAndTrace("Not drawing due to not visible. Reason=" + viewVisibilityReason);
4268             }
4269             mLastPerformTraversalsSkipDrawReason = "view_not_visible";
4270             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
4271                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
4272                     mPendingTransitions.get(i).endChangingAnimations();
4273                 }
4274                 mPendingTransitions.clear();
4275             }
4276 
4277             handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
4278                     mPendingTransaction, "view not visible");
4279         } else if (cancelAndRedraw) {
4280             if (!mWasLastDrawCanceled) {
4281                 logAndTrace("Canceling draw."
4282                         + " cancelDueToPreDrawListener=" + cancelDueToPreDrawListener
4283                         + " cancelDueToSync=" + (cancelDraw && mDrewOnceForSync));
4284             }
4285             mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
4286                 ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
4287                 : "cancel_" + cancelReason;
4288             // Try again
4289             scheduleTraversals();
4290         } else {
4291             if (mWasLastDrawCanceled) {
4292                 logAndTrace("Draw frame after cancel");
4293             }
4294             if (!mLastTraversalWasVisible) {
4295                 logAndTrace("Start draw after previous draw not visible");
4296             }
4297             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
4298                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
4299                     mPendingTransitions.get(i).startChangingAnimations();
4300                 }
4301                 mPendingTransitions.clear();
4302             }
4303             if (!performDraw(mActiveSurfaceSyncGroup)) {
4304                 handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
4305                         mPendingTransaction, mLastPerformDrawSkippedReason);
4306             }
4307         }
4308         mWasLastDrawCanceled = cancelAndRedraw;
4309         mLastTraversalWasVisible = isViewVisible;
4310 
4311         if (mAttachInfo.mContentCaptureEvents != null) {
4312             notifyContentCaptureEvents();
4313         }
4314 
4315         mIsInTraversal = false;
4316         mRelayoutRequested = false;
4317 
4318         if (!cancelAndRedraw) {
4319             mReportNextDraw = false;
4320             mLastReportNextDrawReason = null;
4321             mActiveSurfaceSyncGroup = null;
4322             if (mHasPendingTransactions) {
4323                 // TODO: We shouldn't ever actually hit this, it means mPendingTransaction wasn't
4324                 // merged with a sync group or BLASTBufferQueue before making it to this point
4325                 // But better a one or two frame flicker than steady-state broken from dropping
4326                 // whatever is in this transaction
4327                 mPendingTransaction.apply();
4328                 mHasPendingTransactions = false;
4329             }
4330             mSyncBuffer = false;
4331             if (isInWMSRequestedSync()) {
4332                 mWmsRequestSyncGroup.markSyncReady();
4333                 mWmsRequestSyncGroup = null;
4334                 mWmsRequestSyncGroupState = WMS_SYNC_NONE;
4335             }
4336         }
4337 
4338         // For the variable refresh rate project.
4339         // We set the preferred frame rate and frame rate category at the end of performTraversals
4340         // when the values are applicable.
4341         if (mDrawnThisFrame) {
4342             mDrawnThisFrame = false;
4343             if (!mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) {
4344                 mInvalidationIdleMessagePosted = true;
4345                 mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS);
4346             }
4347             setCategoryFromCategoryCounts();
4348             updateInfrequentCount();
4349             updateFrameRateFromThreadedRendererViews();
4350             setPreferredFrameRate(mPreferredFrameRate);
4351             setPreferredFrameRateCategory(mPreferredFrameRateCategory);
4352             if (mPreferredFrameRate > 0
4353                     || (mLastPreferredFrameRate != 0 && mPreferredFrameRate == 0)
4354             ) {
4355                 mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
4356                 mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING,
4357                         FRAME_RATE_SETTING_REEVALUATE_TIME);
4358             }
4359             mFrameRateCategoryHighCount = mFrameRateCategoryHighCount > 0
4360                     ? mFrameRateCategoryHighCount - 1 : mFrameRateCategoryHighCount;
4361             mFrameRateCategoryNormalCount = mFrameRateCategoryNormalCount > 0
4362                     ? mFrameRateCategoryNormalCount - 1 : mFrameRateCategoryNormalCount;
4363             mFrameRateCategoryLowCount = mFrameRateCategoryLowCount > 0
4364                     ? mFrameRateCategoryLowCount - 1 : mFrameRateCategoryLowCount;
4365             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT;
4366             mPreferredFrameRate = -1;
4367             mIsFrameRateConflicted = false;
4368             mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_UNKNOWN;
4369         } else if (mPreferredFrameRate == 0) {
4370             // From MSG_FRAME_RATE_SETTING, where mPreferredFrameRate is set to 0
4371             setPreferredFrameRate(0);
4372             mPreferredFrameRate = -1;
4373         }
4374     }
4375 
createSyncIfNeeded()4376     private void createSyncIfNeeded() {
4377         // WMS requested sync already started or there's nothing needing to sync
4378         if (isInWMSRequestedSync() || !mReportNextDraw) {
4379             return;
4380         }
4381 
4382         final int seqId = mSyncSeqId;
4383         mWmsRequestSyncGroupState = WMS_SYNC_PENDING;
4384         mWmsRequestSyncGroup = new SurfaceSyncGroup("wmsSync-" + mTag, t -> {
4385             mWmsRequestSyncGroupState = WMS_SYNC_MERGED;
4386             // See b/286355097. If the current process is not system, then invoking finishDraw on
4387             // any thread is fine since once it calls into system process, finishDrawing will run
4388             // on a different thread. However, when the current process is system, the finishDraw in
4389             // system server will be run on the current thread, which could result in a deadlock.
4390             if (mWindowSession instanceof Binder) {
4391                 // The transaction should be copied to a local reference when posting onto a new
4392                 // thread because up until now the SSG is holding a lock on the transaction. Once
4393                 // the call jumps onto a new thread, the lock is no longer held and the transaction
4394                 // send back may be modified or used again.
4395                 Transaction transactionCopy = new Transaction();
4396                 transactionCopy.merge(t);
4397                 mHandler.postAtFrontOfQueue(() -> reportDrawFinished(transactionCopy, seqId));
4398             } else {
4399                 reportDrawFinished(t, seqId);
4400             }
4401         });
4402 
4403         // Only trigger once per {@link ViewRootImpl} instance, so don't add listener if
4404         // {link mTransactionCompletedTimeNs} has already been set.
4405         if (mAppStartInfoTimestampsFlagValue && !mAppStartTrackingStarted) {
4406             mAppStartTrackingStarted = true;
4407             Transaction transaction = new Transaction();
4408             transaction.addTransactionCompletedListener(mSimpleExecutor,
4409                     new Consumer<TransactionStats>() {
4410                         @Override
4411                         public void accept(TransactionStats transactionStats) {
4412                             SyncFence presentFence = transactionStats.getPresentFence();
4413                             if (presentFence.awaitForever()) {
4414                                 if (mFirstFramePresentedTimeNs == -1) {
4415                                     // Only trigger once per {@link ViewRootImpl} instance.
4416                                     mFirstFramePresentedTimeNs = presentFence.getSignalTime();
4417                                     maybeSendAppStartTimes();
4418                                 }
4419                             }
4420                             presentFence.close();
4421                         }
4422                     });
4423             applyTransactionOnDraw(transaction);
4424         }
4425 
4426         if (DEBUG_BLAST) {
4427             Log.d(mTag, "Setup new sync=" + mWmsRequestSyncGroup.getName());
4428         }
4429 
4430         mWmsRequestSyncGroup.add(this, null /* runnable */);
4431     }
4432 
maybeSendAppStartTimes()4433     private void maybeSendAppStartTimes() {
4434         synchronized (this) {
4435             if (mAppStartTimestampsSent) {
4436                 // Don't send timestamps more than once.
4437                 return;
4438             }
4439 
4440             // If we already have {@link mRenderThreadDrawStartTimeNs} then pass it through, if not
4441             // post to main thread and check if we have it there.
4442             if (mRenderThreadDrawStartTimeNs != -1) {
4443                 sendAppStartTimesLocked();
4444             } else {
4445                 mHandler.post(new Runnable() {
4446                     @Override
4447                     public void run() {
4448                         synchronized (ViewRootImpl.this) {
4449                             if (mRenderThreadDrawStartTimeNs == -1) {
4450                                 return;
4451                             }
4452                             sendAppStartTimesLocked();
4453                         }
4454                     }
4455                 });
4456             }
4457         }
4458     }
4459 
4460     @GuardedBy("this")
sendAppStartTimesLocked()4461     private void sendAppStartTimesLocked() {
4462         try {
4463             ActivityManager.getService().reportStartInfoViewTimestamps(
4464                     mRenderThreadDrawStartTimeNs, mFirstFramePresentedTimeNs);
4465             mAppStartTimestampsSent = true;
4466         } catch (RemoteException e) {
4467             // Ignore, timestamps may be lost.
4468             if (DBG) Log.d(TAG, "Exception attempting to report start timestamps.", e);
4469         }
4470     }
4471 
4472     /**
4473      * Helper used to notify the service to block projection when a sensitive
4474      * view (the view displays sensitive content) is attached to the window.
4475      * The window manager service is also notified to unblock projection when
4476      * no attached view (to the window) displays sensitive content.
4477      *
4478      * <ol>
4479      *   <li>It should only notify service to block projection when first sensitive view is
4480      *   attached to the window.
4481      *   <li>It should only notify service to unblock projection when all sensitive view are
4482      *   removed from the window.
4483      * </ol>
4484      *
4485      * @param enableProtection if true, the protection is enabled for this window.
4486      *                         if false, the protection is removed for this window.
4487      */
applySensitiveContentAppProtection(boolean enableProtection)4488     private void applySensitiveContentAppProtection(boolean enableProtection) {
4489         try {
4490             if (mSensitiveContentProtectionService == null) {
4491                 return;
4492             }
4493             if (DEBUG_SENSITIVE_CONTENT) {
4494                 Log.d(TAG, "Notify sensitive content, package=" + mContext.getPackageName()
4495                         + ", token=" + getWindowToken() + ", flag=" + enableProtection);
4496             }
4497             // The window would be blocked during screen share if it shows sensitive content.
4498             mSensitiveContentProtectionService.setSensitiveContentProtection(
4499                     getWindowToken(), mContext.getPackageName(), enableProtection);
4500         } catch (RemoteException ex) {
4501             Log.e(TAG, "Unable to protect sensitive content during screen share", ex);
4502         }
4503     }
4504 
4505     /**
4506      * Add sensitive content protection, when there are one or more visible sensitive views.
4507      */
addSensitiveContentAppProtection()4508     void addSensitiveContentAppProtection() {
4509         applySensitiveContentAppProtection(true);
4510     }
4511 
4512     /**
4513      * Remove sensitive content protection, when there is no visible sensitive view.
4514      */
removeSensitiveContentAppProtection()4515     void removeSensitiveContentAppProtection() {
4516         if (!sensitiveContentPrematureProtectionRemovedFix()) {
4517             applySensitiveContentAppProtection(false);
4518             return;
4519         }
4520         if (DEBUG_SENSITIVE_CONTENT) {
4521             Log.d(TAG, "Add transaction to remove sensitive content protection, package="
4522                     + mContext.getPackageName() + ", token=" + getWindowToken());
4523         }
4524         Transaction t = new Transaction();
4525         t.addTransactionCommittedListener(mExecutor, () -> {
4526             if (mAttachInfo.mSensitiveViewsCount == 0) {
4527                 applySensitiveContentAppProtection(false);
4528             }
4529         });
4530         applyTransactionOnDraw(t);
4531     }
4532 
notifyContentCaptureEvents()4533     private void notifyContentCaptureEvents() {
4534         if (!isContentCaptureEnabled()) {
4535             if (DEBUG_CONTENT_CAPTURE) {
4536                 Log.d(mTag, "notifyContentCaptureEvents while disabled");
4537             }
4538             mAttachInfo.mContentCaptureEvents = null;
4539             return;
4540         }
4541 
4542         final ContentCaptureManager manager = mAttachInfo.mContentCaptureManager;
4543         if (manager != null && mAttachInfo.mContentCaptureEvents != null) {
4544             final ContentCaptureSession session = manager.getMainContentCaptureSession();
4545             session.notifyContentCaptureEvents(mAttachInfo.mContentCaptureEvents);
4546         }
4547         mAttachInfo.mContentCaptureEvents = null;
4548     }
4549 
notifyHolderSurfaceDestroyed()4550     private void notifyHolderSurfaceDestroyed() {
4551         mSurfaceHolder.ungetCallbacks();
4552         SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
4553         if (callbacks != null) {
4554             for (SurfaceHolder.Callback c : callbacks) {
4555                 c.surfaceDestroyed(mSurfaceHolder);
4556             }
4557         }
4558     }
4559 
maybeHandleWindowMove(Rect frame)4560     private void maybeHandleWindowMove(Rect frame) {
4561         // TODO: Well, we are checking whether the frame has changed similarly
4562         // to how this is done for the insets. This is however incorrect since
4563         // the insets and the frame are translated. For example, the old frame
4564         // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
4565         // reported frame is (2, 2 - 2, 2) which implies no change but this is not
4566         // true since we are comparing a not translated value to a translated one.
4567         // This scenario is rare but we may want to fix that.
4568 
4569         final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left
4570                 || mAttachInfo.mWindowTop != frame.top;
4571         if (windowMoved) {
4572             mAttachInfo.mWindowLeft = frame.left;
4573             mAttachInfo.mWindowTop = frame.top;
4574         }
4575         if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) {
4576             // Update the light position for the new offsets.
4577             if (mAttachInfo.mThreadedRenderer != null) {
4578                 mAttachInfo.mThreadedRenderer.setLightCenter(mAttachInfo);
4579             }
4580             mAttachInfo.mNeedsUpdateLightCenter = false;
4581         }
4582     }
4583 
handleWindowFocusChanged()4584     private void handleWindowFocusChanged() {
4585         final boolean hasWindowFocus;
4586         synchronized (this) {
4587             if (!mWindowFocusChanged) {
4588                 return;
4589             }
4590             mWindowFocusChanged = false;
4591             hasWindowFocus = mUpcomingWindowFocus;
4592         }
4593         if (hasWindowFocus) {
4594             mInsetsController.onWindowFocusGained(
4595                     getFocusedViewOrNull() != null /* hasViewFocused */);
4596         } else {
4597             mInsetsController.onWindowFocusLost();
4598         }
4599 
4600         if (mAdded) {
4601             dispatchFocusEvent(hasWindowFocus, false /* fakeFocus */);
4602             // Note: must be done after the focus change callbacks,
4603             // so all of the view state is set up correctly.
4604             mImeFocusController.onPostWindowFocus(
4605                     getFocusedViewOrNull(), hasWindowFocus, mWindowAttributes);
4606 
4607             if (hasWindowFocus) {
4608                 // Clear the forward bit.  We can just do this directly, since
4609                 // the window manager doesn't care about it.
4610                 mWindowAttributes.softInputMode &=
4611                         ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
4612                 ((WindowManager.LayoutParams) mView.getLayoutParams())
4613                         .softInputMode &=
4614                         ~WindowManager.LayoutParams
4615                                 .SOFT_INPUT_IS_FORWARD_NAVIGATION;
4616 
4617                 maybeFireAccessibilityWindowStateChangedEvent();
4618 
4619                 // Refocusing a window that has a focused view should fire a
4620                 // focus event for the view since the global focused view changed.
4621                 fireAccessibilityFocusEventIfHasFocusedNode();
4622             } else {
4623                 if (mPointerCapture) {
4624                     handlePointerCaptureChanged(false);
4625                 }
4626             }
4627         }
4628         mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
4629 
4630         // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus
4631         // is lost, so we don't need to to force a flush - there might be other events such as
4632         // text changes, but these should be flushed independently.
4633         if (hasWindowFocus) {
4634             handleContentCaptureFlush();
4635         }
4636     }
4637 
4638     /**
4639      * Send a fake focus event for unfocused apps in split screen as some game engines wait to
4640      * get focus before drawing the content of the app. This will be used so that apps do not get
4641      * blacked out when they are resumed and do not have focus yet.
4642      *
4643      * {@hide}
4644      */
4645     // TODO(b/263094829): Investigate dispatching this for onPause as well
dispatchCompatFakeFocus()4646     public void dispatchCompatFakeFocus() {
4647         boolean aboutToHaveFocus = false;
4648         synchronized (this) {
4649             aboutToHaveFocus = mWindowFocusChanged && mUpcomingWindowFocus;
4650         }
4651         final boolean alreadyHaveFocus = mAttachInfo.mHasWindowFocus;
4652         if (aboutToHaveFocus || alreadyHaveFocus) {
4653             // Do not need to toggle focus if app doesn't need it, or has focus.
4654             return;
4655         }
4656         EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
4657                 "Giving fake focus to " + mBasePackageName, "reason=unity bug workaround");
4658         dispatchFocusEvent(true /* hasWindowFocus */, true /* fakeFocus */);
4659         EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
4660                 "Removing fake focus from " + mBasePackageName, "reason=timeout callback");
4661         dispatchFocusEvent(false /* hasWindowFocus */, true /* fakeFocus */);
4662     }
4663 
dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus)4664     private void dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus) {
4665         profileRendering(hasWindowFocus);
4666         if (hasWindowFocus && mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
4667             mFullRedrawNeeded = true;
4668             try {
4669                 final Rect surfaceInsets = mWindowAttributes.surfaceInsets;
4670                 mAttachInfo.mThreadedRenderer.initializeIfNeeded(
4671                         mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
4672             } catch (OutOfResourcesException e) {
4673                 Log.e(mTag, "OutOfResourcesException locking surface", e);
4674                 try {
4675                     if (!mWindowSession.outOfMemory(mWindow)) {
4676                         Slog.w(mTag, "No processes killed for memory;"
4677                                 + " killing self");
4678                         Process.killProcess(Process.myPid());
4679                     }
4680                 } catch (RemoteException ex) {
4681                 }
4682                 // Retry in a bit.
4683                 mHandler.sendMessageDelayed(mHandler.obtainMessage(
4684                         MSG_WINDOW_FOCUS_CHANGED), 500);
4685                 return;
4686             }
4687         }
4688 
4689         mAttachInfo.mHasWindowFocus = hasWindowFocus;
4690 
4691         if (!fakeFocus) {
4692             mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes);
4693         }
4694 
4695         if (mView != null) {
4696             mAttachInfo.mKeyDispatchState.reset();
4697             mView.dispatchWindowFocusChanged(hasWindowFocus);
4698             mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
4699             if (mAttachInfo.mTooltipHost != null) {
4700                 mAttachInfo.mTooltipHost.hideTooltip();
4701             }
4702         }
4703     }
4704 
handleWindowTouchModeChanged()4705     private void handleWindowTouchModeChanged() {
4706         final boolean inTouchMode;
4707         synchronized (this) {
4708             inTouchMode = mUpcomingInTouchMode;
4709         }
4710         ensureTouchModeLocally(inTouchMode);
4711     }
4712 
maybeFireAccessibilityWindowStateChangedEvent()4713     private void maybeFireAccessibilityWindowStateChangedEvent() {
4714         // Toasts are presented as notifications - don't present them as windows as well.
4715         boolean isToast = mWindowAttributes != null && (mWindowAttributes.type == TYPE_TOAST);
4716         if (!isToast && mView != null) {
4717             mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
4718         }
4719     }
4720 
fireAccessibilityFocusEventIfHasFocusedNode()4721     private void fireAccessibilityFocusEventIfHasFocusedNode() {
4722         if (!mAccessibilityManager.isEnabled()) {
4723             return;
4724         }
4725         final View focusedView = mView.findFocus();
4726         if (focusedView == null) {
4727             return;
4728         }
4729         final AccessibilityNodeProvider provider = focusedView.getAccessibilityNodeProvider();
4730         if (provider == null) {
4731             focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
4732         } else {
4733             final AccessibilityNodeInfo focusedNode = findFocusedVirtualNode(provider);
4734             if (focusedNode != null) {
4735                 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
4736                         focusedNode.getSourceNodeId());
4737                 // This is a best effort since clearing and setting the focus via the
4738                 // provider APIs could have side effects. We don't have a provider API
4739                 // similar to that on View to ask a given event to be fired.
4740                 final AccessibilityEvent event = AccessibilityEvent.obtain(
4741                         AccessibilityEvent.TYPE_VIEW_FOCUSED);
4742                 event.setSource(focusedView, virtualId);
4743                 event.setPackageName(focusedNode.getPackageName());
4744                 event.setChecked(focusedNode.isChecked());
4745                 event.setContentDescription(focusedNode.getContentDescription());
4746                 event.setPassword(focusedNode.isPassword());
4747                 event.getText().add(focusedNode.getText());
4748                 event.setEnabled(focusedNode.isEnabled());
4749                 focusedView.getParent().requestSendAccessibilityEvent(focusedView, event);
4750                 focusedNode.recycle();
4751             }
4752         }
4753     }
4754 
findFocusedVirtualNode(AccessibilityNodeProvider provider)4755     private AccessibilityNodeInfo findFocusedVirtualNode(AccessibilityNodeProvider provider) {
4756         AccessibilityNodeInfo focusedNode = provider.findFocus(
4757                 AccessibilityNodeInfo.FOCUS_INPUT);
4758         if (focusedNode != null) {
4759             return focusedNode;
4760         }
4761 
4762         if (!mContext.isAutofillCompatibilityEnabled()) {
4763             return null;
4764         }
4765 
4766         // Unfortunately some provider implementations don't properly
4767         // implement AccessibilityNodeProvider#findFocus
4768         AccessibilityNodeInfo current = provider.createAccessibilityNodeInfo(
4769                 AccessibilityNodeProvider.HOST_VIEW_ID);
4770         if (current == null) {
4771             return null;
4772         }
4773         if (current.isFocused()) {
4774             return current;
4775         }
4776 
4777         final Queue<AccessibilityNodeInfo> fringe = new ArrayDeque<>();
4778         fringe.offer(current);
4779 
4780         while (!fringe.isEmpty()) {
4781             current = fringe.poll();
4782             final LongArray childNodeIds = current.getChildNodeIds();
4783             if (childNodeIds== null || childNodeIds.size() <= 0) {
4784                 continue;
4785             }
4786             final int childCount = childNodeIds.size();
4787             for (int i = 0; i < childCount; i++) {
4788                 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
4789                         childNodeIds.get(i));
4790                 final AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(virtualId);
4791                 if (child != null) {
4792                     if (child.isFocused()) {
4793                         return child;
4794                     }
4795                     fringe.offer(child);
4796                 }
4797             }
4798             current.recycle();
4799         }
4800 
4801         return null;
4802     }
4803 
handleOutOfResourcesException(Surface.OutOfResourcesException e)4804     private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
4805         Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
4806         try {
4807             if (!mWindowSession.outOfMemory(mWindow) &&
4808                     Process.myUid() != Process.SYSTEM_UID) {
4809                 Slog.w(mTag, "No processes killed for memory; killing self");
4810                 Process.killProcess(Process.myPid());
4811             }
4812         } catch (RemoteException ex) {
4813         }
4814         mLayoutRequested = true;    // ask wm for a new surface next time.
4815     }
4816 
performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec)4817     private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
4818         if (mView == null) {
4819             return;
4820         }
4821         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
4822         try {
4823             mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4824         } finally {
4825             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
4826         }
4827         mMeasuredWidth = mView.getMeasuredWidth();
4828         mMeasuredHeight = mView.getMeasuredHeight();
4829         mViewMeasureDeferred = false;
4830     }
4831 
4832     /**
4833      * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
4834      * is currently undergoing a layout pass.
4835      *
4836      * @return whether the view hierarchy is currently undergoing a layout pass
4837      */
isInLayout()4838     boolean isInLayout() {
4839         return mInLayout;
4840     }
4841 
4842     /**
4843      * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
4844      * undergoing a layout pass. requestLayout() should not generally be called during layout,
4845      * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
4846      * all children in that container hierarchy are measured and laid out at the end of the layout
4847      * pass for that container). If requestLayout() is called anyway, we handle it correctly
4848      * by registering all requesters during a frame as it proceeds. At the end of the frame,
4849      * we check all of those views to see if any still have pending layout requests, which
4850      * indicates that they were not correctly handled by their container hierarchy. If that is
4851      * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
4852      * to blank containers, and force a second request/measure/layout pass in this frame. If
4853      * more requestLayout() calls are received during that second layout pass, we post those
4854      * requests to the next frame to avoid possible infinite loops.
4855      *
4856      * <p>The return value from this method indicates whether the request should proceed
4857      * (if it is a request during the first layout pass) or should be skipped and posted to the
4858      * next frame (if it is a request during the second layout pass).</p>
4859      *
4860      * @param view the view that requested the layout.
4861      *
4862      * @return true if request should proceed, false otherwise.
4863      */
requestLayoutDuringLayout(final View view)4864     boolean requestLayoutDuringLayout(final View view) {
4865         if (view.mParent == null || view.mAttachInfo == null) {
4866             // Would not normally trigger another layout, so just let it pass through as usual
4867             return true;
4868         }
4869         if (!mLayoutRequesters.contains(view)) {
4870             mLayoutRequesters.add(view);
4871         }
4872         if (!mHandlingLayoutInLayoutRequest) {
4873             // Let the request proceed normally; it will be processed in a second layout pass
4874             // if necessary
4875             return true;
4876         } else {
4877             // Don't let the request proceed during the second layout pass.
4878             // It will post to the next frame instead.
4879             return false;
4880         }
4881     }
4882 
performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight)4883     private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
4884             int desiredWindowHeight) {
4885         mScrollMayChange = true;
4886         mInLayout = true;
4887 
4888         final View host = mView;
4889         if (host == null) {
4890             return;
4891         }
4892         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
4893             Log.v(mTag, "Laying out " + host + " to (" +
4894                     host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
4895         }
4896 
4897         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
4898         try {
4899             host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
4900 
4901             mInLayout = false;
4902             int numViewsRequestingLayout = mLayoutRequesters.size();
4903             if (numViewsRequestingLayout > 0) {
4904                 // requestLayout() was called during layout.
4905                 // If no layout-request flags are set on the requesting views, there is no problem.
4906                 // If some requests are still pending, then we need to clear those flags and do
4907                 // a full request/measure/layout pass to handle this situation.
4908                 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
4909                         false);
4910                 if (validLayoutRequesters != null) {
4911                     // Set this flag to indicate that any further requests are happening during
4912                     // the second pass, which may result in posting those requests to the next
4913                     // frame instead
4914                     mHandlingLayoutInLayoutRequest = true;
4915 
4916                     // Process fresh layout requests, then measure and layout
4917                     int numValidRequests = validLayoutRequesters.size();
4918                     for (int i = 0; i < numValidRequests; ++i) {
4919                         final View view = validLayoutRequesters.get(i);
4920                         Log.w("View", "requestLayout() improperly called by " + view +
4921                                 " during layout: running second layout pass");
4922                         view.requestLayout();
4923                     }
4924                     measureHierarchy(host, lp, mView.getContext().getResources(),
4925                             desiredWindowWidth, desiredWindowHeight, false /* forRootSizeOnly */);
4926                     mInLayout = true;
4927                     host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
4928 
4929                     mHandlingLayoutInLayoutRequest = false;
4930 
4931                     // Check the valid requests again, this time without checking/clearing the
4932                     // layout flags, since requests happening during the second pass get noop'd
4933                     validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
4934                     if (validLayoutRequesters != null) {
4935                         final ArrayList<View> finalRequesters = validLayoutRequesters;
4936                         // Post second-pass requests to the next frame
4937                         getRunQueue().post(new Runnable() {
4938                             @Override
4939                             public void run() {
4940                                 int numValidRequests = finalRequesters.size();
4941                                 for (int i = 0; i < numValidRequests; ++i) {
4942                                     final View view = finalRequesters.get(i);
4943                                     Log.w("View", "requestLayout() improperly called by " + view +
4944                                             " during second layout pass: posting in next frame");
4945                                     view.requestLayout();
4946                                 }
4947                             }
4948                         });
4949                     }
4950                 }
4951 
4952             }
4953         } finally {
4954             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
4955         }
4956         mInLayout = false;
4957     }
4958 
4959     /**
4960      * This method is called during layout when there have been calls to requestLayout() during
4961      * layout. It walks through the list of views that requested layout to determine which ones
4962      * still need it, based on visibility in the hierarchy and whether they have already been
4963      * handled (as is usually the case with ListView children).
4964      *
4965      * @param layoutRequesters The list of views that requested layout during layout
4966      * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
4967      * If so, the FORCE_LAYOUT flag was not set on requesters.
4968      * @return A list of the actual views that still need to be laid out.
4969      */
getValidLayoutRequesters(ArrayList<View> layoutRequesters, boolean secondLayoutRequests)4970     private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
4971             boolean secondLayoutRequests) {
4972 
4973         int numViewsRequestingLayout = layoutRequesters.size();
4974         ArrayList<View> validLayoutRequesters = null;
4975         for (int i = 0; i < numViewsRequestingLayout; ++i) {
4976             View view = layoutRequesters.get(i);
4977             if (view != null && view.mAttachInfo != null && view.mParent != null &&
4978                     (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
4979                             View.PFLAG_FORCE_LAYOUT)) {
4980                 boolean gone = false;
4981                 View parent = view;
4982                 // Only trigger new requests for views in a non-GONE hierarchy
4983                 while (parent != null) {
4984                     if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
4985                         gone = true;
4986                         break;
4987                     }
4988                     if (parent.mParent instanceof View) {
4989                         parent = (View) parent.mParent;
4990                     } else {
4991                         parent = null;
4992                     }
4993                 }
4994                 if (!gone) {
4995                     if (validLayoutRequesters == null) {
4996                         validLayoutRequesters = new ArrayList<View>();
4997                     }
4998                     validLayoutRequesters.add(view);
4999                 }
5000             }
5001         }
5002         if (!secondLayoutRequests) {
5003             // If we're checking the layout flags, then we need to clean them up also
5004             for (int i = 0; i < numViewsRequestingLayout; ++i) {
5005                 View view = layoutRequesters.get(i);
5006                 while (view != null &&
5007                         (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
5008                     view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
5009                     if (view.mParent instanceof View) {
5010                         view = (View) view.mParent;
5011                     } else {
5012                         view = null;
5013                     }
5014                 }
5015             }
5016         }
5017         layoutRequesters.clear();
5018         return validLayoutRequesters;
5019     }
5020 
5021     @Override
requestTransparentRegion(View child)5022     public void requestTransparentRegion(View child) {
5023         // the test below should not fail unless someone is messing with us
5024         checkThread();
5025         if (mView != child) {
5026             return;
5027         }
5028 
5029         if ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
5030             mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
5031             // Need to make sure we re-evaluate the window attributes next
5032             // time around, to ensure the window has the correct format.
5033             mWindowAttributesChanged = true;
5034         }
5035 
5036         // Always request layout to apply the latest transparent region.
5037         requestLayout();
5038     }
5039 
5040     /**
5041      * Figures out the measure spec for the root view in a window based on it's
5042      * layout params.
5043      *
5044      * @param windowSize The available width or height of the window.
5045      * @param measurement The layout width or height requested in the layout params.
5046      * @param privateFlags The private flags in the layout params of the window.
5047      * @return The measure spec to use to measure the root view.
5048      */
getRootMeasureSpec(int windowSize, int measurement, int privateFlags)5049     private static int getRootMeasureSpec(int windowSize, int measurement, int privateFlags) {
5050         int measureSpec;
5051         final int rootDimension = (privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0
5052                 ? MATCH_PARENT : measurement;
5053         switch (rootDimension) {
5054             case ViewGroup.LayoutParams.MATCH_PARENT:
5055                 // Window can't resize. Force root view to be windowSize.
5056                 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
5057                 break;
5058             case ViewGroup.LayoutParams.WRAP_CONTENT:
5059                 // Window can resize. Set max size for root view.
5060                 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
5061                 break;
5062             default:
5063                 // Window wants to be an exact size. Force root view to be that size.
5064                 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
5065                 break;
5066         }
5067         return measureSpec;
5068     }
5069 
5070     int mHardwareXOffset;
5071     int mHardwareYOffset;
5072 
5073     @Override
onPreDraw(RecordingCanvas canvas)5074     public void onPreDraw(RecordingCanvas canvas) {
5075         // If mCurScrollY is not 0 then this influences the hardwareYOffset. The end result is we
5076         // can apply offsets that are not handled by anything else, resulting in underdraw as
5077         // the View is shifted (thus shifting the window background) exposing unpainted
5078         // content. To handle this with minimal glitches we just clear to BLACK if the window
5079         // is opaque. If it's not opaque then HWUI already internally does a glClear to
5080         // transparent, so there's no risk of underdraw on non-opaque surfaces.
5081         if (mCurScrollY != 0 && mHardwareYOffset != 0 && mAttachInfo.mThreadedRenderer.isOpaque()) {
5082             canvas.drawColor(Color.BLACK);
5083         }
5084         canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
5085     }
5086 
5087     @Override
onPostDraw(RecordingCanvas canvas)5088     public void onPostDraw(RecordingCanvas canvas) {
5089         drawAccessibilityFocusedDrawableIfNeeded(canvas);
5090         if (mUseMTRenderer) {
5091             for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
5092                 mWindowCallbacks.get(i).onPostDraw(canvas);
5093             }
5094         }
5095     }
5096 
5097     /**
5098      * @hide
5099      */
outputDisplayList(View view)5100     void outputDisplayList(View view) {
5101         view.mRenderNode.output();
5102     }
5103 
5104     /**
5105      * @see #PROPERTY_PROFILE_RENDERING
5106      */
profileRendering(boolean enabled)5107     private void profileRendering(boolean enabled) {
5108         if (mProfileRendering) {
5109             mRenderProfilingEnabled = enabled;
5110 
5111             if (mRenderProfiler != null) {
5112                 mChoreographer.removeFrameCallback(mRenderProfiler);
5113             }
5114             if (mRenderProfilingEnabled) {
5115                 if (mRenderProfiler == null) {
5116                     mRenderProfiler = new Choreographer.FrameCallback() {
5117                         @Override
5118                         public void doFrame(long frameTimeNanos) {
5119                             mDirty.set(0, 0, mWidth, mHeight);
5120                             scheduleTraversals();
5121                             if (mRenderProfilingEnabled) {
5122                                 mChoreographer.postFrameCallback(mRenderProfiler);
5123                             }
5124                         }
5125                     };
5126                 }
5127                 mChoreographer.postFrameCallback(mRenderProfiler);
5128             } else {
5129                 mRenderProfiler = null;
5130             }
5131         }
5132     }
5133 
5134     /**
5135      * Called from draw() when DEBUG_FPS is enabled
5136      */
trackFPS()5137     private void trackFPS() {
5138         // Tracks frames per second drawn. First value in a series of draws may be bogus
5139         // because it down not account for the intervening idle time
5140         long nowTime = System.currentTimeMillis();
5141         if (mFpsStartTime < 0) {
5142             mFpsStartTime = mFpsPrevTime = nowTime;
5143             mFpsNumFrames = 0;
5144         } else {
5145             ++mFpsNumFrames;
5146             String thisHash = Integer.toHexString(System.identityHashCode(this));
5147             long frameTime = nowTime - mFpsPrevTime;
5148             long totalTime = nowTime - mFpsStartTime;
5149             Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
5150             mFpsPrevTime = nowTime;
5151             if (totalTime > 1000) {
5152                 float fps = (float) mFpsNumFrames * 1000 / totalTime;
5153                 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
5154                 mFpsStartTime = nowTime;
5155                 mFpsNumFrames = 0;
5156             }
5157         }
5158     }
5159 
5160     /**
5161      * Called from draw() to collect metrics for frame rate decision.
5162      */
collectFrameRateDecisionMetrics()5163     private void collectFrameRateDecisionMetrics() {
5164         if (!Trace.isEnabled()) {
5165             if (mPreviousFrameDrawnTime > 0) mPreviousFrameDrawnTime = -1;
5166             return;
5167         }
5168 
5169         if (mPreviousFrameDrawnTime < 0) {
5170             mPreviousFrameDrawnTime = mChoreographer.getExpectedPresentationTimeNanos();
5171             return;
5172         }
5173 
5174         long expectedDrawnTime = mChoreographer.getExpectedPresentationTimeNanos();
5175         long timeDiff = expectedDrawnTime - mPreviousFrameDrawnTime;
5176         if (timeDiff <= 0) {
5177             return;
5178         }
5179 
5180         long fps = NANOS_PER_SEC / timeDiff;
5181         Trace.setCounter(mFpsTraceName, fps);
5182         mPreviousFrameDrawnTime = expectedDrawnTime;
5183 
5184         long percentage = (long) (mLargestChildPercentage * 100);
5185         Trace.setCounter(mLargestViewTraceName, percentage);
5186         mLargestChildPercentage = 0.0f;
5187     }
5188 
reportDrawFinished(@ullable Transaction t, int seqId)5189     private void reportDrawFinished(@Nullable Transaction t, int seqId) {
5190         logAndTrace("reportDrawFinished seqId=" + seqId);
5191         try {
5192             mWindowSession.finishDrawing(mWindow, t, seqId);
5193         } catch (RemoteException e) {
5194             Log.e(mTag, "Unable to report draw finished", e);
5195             if (t != null) {
5196                 t.apply();
5197             }
5198         } finally {
5199             if (t != null) {
5200                 t.clear();
5201             }
5202         }
5203     }
5204 
5205     /**
5206      * @hide
5207      */
isHardwareEnabled()5208     public boolean isHardwareEnabled() {
5209         return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled();
5210     }
5211 
5212     /**
5213      * This VRI is currently in the middle of a sync request that was initiated by WMS.
5214      */
isInWMSRequestedSync()5215     public boolean isInWMSRequestedSync() {
5216         return mWmsRequestSyncGroup != null;
5217     }
5218 
addFrameCommitCallbackIfNeeded()5219     private void addFrameCommitCallbackIfNeeded() {
5220         if (!isHardwareEnabled()) {
5221             return;
5222         }
5223 
5224         ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
5225                 .captureFrameCommitCallbacks();
5226         final boolean needFrameCommitCallback =
5227                 (commitCallbacks != null && commitCallbacks.size() > 0);
5228         if (!needFrameCommitCallback) {
5229             return;
5230         }
5231 
5232         if (DEBUG_DRAW) {
5233             Log.d(mTag, "Creating frameCommitCallback"
5234                     + " commitCallbacks size=" + commitCallbacks.size());
5235         }
5236         mAttachInfo.mThreadedRenderer.setFrameCommitCallback(didProduceBuffer -> {
5237             if (DEBUG_DRAW) {
5238                 Log.d(mTag, "Received frameCommitCallback didProduceBuffer=" + didProduceBuffer);
5239             }
5240 
5241             mHandler.postAtFrontOfQueue(() -> {
5242                 for (int i = 0; i < commitCallbacks.size(); i++) {
5243                     commitCallbacks.get(i).run();
5244                 }
5245             });
5246         });
5247     }
5248 
5249     /**
5250      * These callbacks check if the draw failed for any reason and apply
5251      * those transactions directly so they don't get stuck forever.
5252      */
registerCallbackForPendingTransactions()5253     private void registerCallbackForPendingTransactions() {
5254         Transaction t = new Transaction();
5255         t.merge(mPendingTransaction);
5256 
5257         registerRtFrameCallback(new FrameDrawingCallback() {
5258             @Override
5259             public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
5260                 mergeWithNextTransaction(t, frame);
5261                 if ((syncResult
5262                         & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
5263                     mBlastBufferQueue.applyPendingTransactions(frame);
5264                     return null;
5265                 }
5266 
5267                 return didProduceBuffer -> {
5268                     if (!didProduceBuffer) {
5269                         logAndTrace("Transaction not synced due to no frame drawn");
5270                         mBlastBufferQueue.applyPendingTransactions(frame);
5271                     }
5272                 };
5273 
5274             }
5275 
5276             @Override
5277             public void onFrameDraw(long frame) {
5278             }
5279         });
5280     }
5281 
performDraw(@ullable SurfaceSyncGroup surfaceSyncGroup)5282     private boolean performDraw(@Nullable SurfaceSyncGroup surfaceSyncGroup) {
5283         mLastPerformDrawSkippedReason = null;
5284         if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
5285             mLastPerformDrawSkippedReason = "screen_off";
5286             if (!mLastDrawScreenOff) {
5287                 logAndTrace("Not drawing due to screen off");
5288             }
5289             mLastDrawScreenOff = true;
5290             return false;
5291         } else if (mView == null) {
5292             mLastPerformDrawSkippedReason = "no_root_view";
5293             return false;
5294         }
5295 
5296         if (mLastDrawScreenOff) {
5297             logAndTrace("Resumed drawing after screen turned on");
5298             mLastDrawScreenOff = false;
5299         }
5300 
5301         final boolean fullRedrawNeeded = mFullRedrawNeeded || surfaceSyncGroup != null;
5302         mFullRedrawNeeded = false;
5303 
5304         mIsDrawing = true;
5305         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw-" + mTag);
5306 
5307         addFrameCommitCallbackIfNeeded();
5308 
5309         boolean usingAsyncReport;
5310 
5311         try {
5312             usingAsyncReport = draw(fullRedrawNeeded, surfaceSyncGroup, mSyncBuffer);
5313             if (mAttachInfo.mThreadedRenderer != null && !usingAsyncReport) {
5314                 mAttachInfo.mThreadedRenderer.setFrameCallback(null);
5315             }
5316         } finally {
5317             mIsDrawing = false;
5318             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
5319         }
5320 
5321         // For whatever reason we didn't create a HardwareRenderer, end any
5322         // hardware animations that are now dangling
5323         if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
5324             final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
5325             for (int i = 0; i < count; i++) {
5326                 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
5327             }
5328             mAttachInfo.mPendingAnimatingRenderNodes.clear();
5329         }
5330 
5331         final Transaction pendingTransaction;
5332         if (!usingAsyncReport && mHasPendingTransactions) {
5333             pendingTransaction = new Transaction();
5334             pendingTransaction.merge(mPendingTransaction);
5335         } else {
5336             pendingTransaction = null;
5337         }
5338 
5339         if (mReportNextDraw) {
5340             // if we're using multi-thread renderer, wait for the window frame draws
5341             if (mWindowDrawCountDown != null) {
5342                 try {
5343                     mWindowDrawCountDown.await();
5344                 } catch (InterruptedException e) {
5345                     Log.e(mTag, "Window redraw count down interrupted!");
5346                 }
5347                 mWindowDrawCountDown = null;
5348             }
5349 
5350             if (mAttachInfo.mThreadedRenderer != null) {
5351                 mAttachInfo.mThreadedRenderer.setStopped(mStopped);
5352             }
5353 
5354             if (LOCAL_LOGV) {
5355                 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
5356             }
5357 
5358             if (mSurfaceHolder != null && mSurface.isValid()) {
5359                 usingAsyncReport = true;
5360                 SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> {
5361                     handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null,
5362                             pendingTransaction, "SurfaceHolder");
5363                 });
5364 
5365                 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
5366 
5367                 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
5368             } else if (!usingAsyncReport) {
5369                 if (mAttachInfo.mThreadedRenderer != null) {
5370                     mAttachInfo.mThreadedRenderer.fence();
5371                 }
5372             }
5373         }
5374 
5375         if (!usingAsyncReport) {
5376             handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null,
5377                     pendingTransaction, "no async report");
5378         }
5379 
5380         if (mPerformContentCapture) {
5381             performContentCaptureInitialReport();
5382         }
5383         return true;
5384     }
5385 
handleSyncRequestWhenNoAsyncDraw(SurfaceSyncGroup surfaceSyncGroup, boolean hasPendingTransaction, @Nullable Transaction pendingTransaction, String logReason)5386     private void handleSyncRequestWhenNoAsyncDraw(SurfaceSyncGroup surfaceSyncGroup,
5387             boolean hasPendingTransaction, @Nullable Transaction pendingTransaction,
5388             String logReason) {
5389         if (surfaceSyncGroup != null) {
5390             if (hasPendingTransaction && pendingTransaction != null) {
5391                 surfaceSyncGroup.addTransaction(pendingTransaction);
5392             }
5393             surfaceSyncGroup.markSyncReady();
5394         } else if (hasPendingTransaction && pendingTransaction != null) {
5395             Trace.instant(Trace.TRACE_TAG_VIEW,
5396                     "Transaction not synced due to " + logReason + "-" + mTag);
5397             if (DEBUG_BLAST) {
5398                 Log.d(mTag, "Pending transaction will not be applied in sync with a draw due to "
5399                         + logReason);
5400             }
5401             pendingTransaction.apply();
5402         }
5403     }
5404     /**
5405      * Checks (and caches) if content capture is enabled for this context.
5406      */
isContentCaptureEnabled()5407     private boolean isContentCaptureEnabled() {
5408         switch (mContentCaptureEnabled) {
5409             case CONTENT_CAPTURE_ENABLED_TRUE:
5410                 return true;
5411             case CONTENT_CAPTURE_ENABLED_FALSE:
5412                 return false;
5413             case CONTENT_CAPTURE_ENABLED_NOT_CHECKED:
5414                 final boolean reallyEnabled = isContentCaptureReallyEnabled();
5415                 mContentCaptureEnabled = reallyEnabled ? CONTENT_CAPTURE_ENABLED_TRUE
5416                         : CONTENT_CAPTURE_ENABLED_FALSE;
5417                 return reallyEnabled;
5418             default:
5419                 Log.w(TAG, "isContentCaptureEnabled(): invalid state " + mContentCaptureEnabled);
5420                 return false;
5421         }
5422 
5423     }
5424 
5425     /**
5426      * Checks (without caching) if content capture is enabled for this context.
5427      */
isContentCaptureReallyEnabled()5428     private boolean isContentCaptureReallyEnabled() {
5429         // First check if context supports it, so it saves a service lookup when it doesn't
5430         if (mContext.getContentCaptureOptions() == null) return false;
5431 
5432         final ContentCaptureManager ccm = mAttachInfo.getContentCaptureManager(mContext);
5433         // Then check if it's enabled in the contex itself.
5434         if (ccm == null || !ccm.isContentCaptureEnabled()) return false;
5435 
5436         return true;
5437     }
5438 
performContentCaptureInitialReport()5439     private void performContentCaptureInitialReport() {
5440         mPerformContentCapture = false; // One-time offer!
5441         final View rootView = mView;
5442         if (DEBUG_CONTENT_CAPTURE) {
5443             Log.v(mTag, "performContentCaptureInitialReport() on " + rootView);
5444         }
5445         boolean traceDispatchCapture = false;
5446         try {
5447             if (!isContentCaptureEnabled()) return;
5448 
5449             traceDispatchCapture = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
5450             if (traceDispatchCapture) {
5451                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for "
5452                         + getClass().getSimpleName());
5453             }
5454 
5455             // Initial dispatch of window bounds to content capture
5456             if (mAttachInfo.mContentCaptureManager != null) {
5457                 ContentCaptureSession session =
5458                         mAttachInfo.mContentCaptureManager.getMainContentCaptureSession();
5459                 session.notifyWindowBoundsChanged(session.getId(),
5460                         getConfiguration().windowConfiguration.getBounds());
5461             }
5462 
5463             // Content capture is a go!
5464             rootView.dispatchInitialProvideContentCaptureStructure();
5465         } finally {
5466             if (traceDispatchCapture) {
5467                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
5468             }
5469         }
5470     }
5471 
handleContentCaptureFlush()5472     private void handleContentCaptureFlush() {
5473         if (DEBUG_CONTENT_CAPTURE) {
5474             Log.v(mTag, "handleContentCaptureFlush()");
5475         }
5476         boolean traceFlushContentCapture = false;
5477         try {
5478             if (!isContentCaptureEnabled()) return;
5479 
5480             traceFlushContentCapture = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
5481             if (traceFlushContentCapture) {
5482                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for "
5483                         + getClass().getSimpleName());
5484             }
5485 
5486             final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager;
5487             if (ccm == null) {
5488                 Log.w(TAG, "No ContentCapture on AttachInfo");
5489                 return;
5490             }
5491             ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED);
5492         } finally {
5493             if (traceFlushContentCapture) {
5494                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
5495             }
5496         }
5497     }
5498 
draw(boolean fullRedrawNeeded, @Nullable SurfaceSyncGroup activeSyncGroup, boolean syncBuffer)5499     private boolean draw(boolean fullRedrawNeeded, @Nullable SurfaceSyncGroup activeSyncGroup,
5500             boolean syncBuffer) {
5501         Surface surface = mSurface;
5502         if (!surface.isValid()) {
5503             return false;
5504         }
5505 
5506         if (DEBUG_FPS) {
5507             trackFPS();
5508         }
5509 
5510         if (sToolkitMetricsForFrameRateDecisionFlagValue) {
5511             collectFrameRateDecisionMetrics();
5512         }
5513 
5514         if (!sFirstDrawComplete) {
5515             synchronized (sFirstDrawHandlers) {
5516                 sFirstDrawComplete = true;
5517                 final int count = sFirstDrawHandlers.size();
5518                 for (int i = 0; i< count; i++) {
5519                     mHandler.post(sFirstDrawHandlers.get(i));
5520                 }
5521             }
5522         }
5523 
5524         scrollToRectOrFocus(null, false);
5525 
5526         if (mAttachInfo.mViewScrollChanged) {
5527             mAttachInfo.mViewScrollChanged = false;
5528             mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
5529         }
5530 
5531         boolean animating = mScroller != null && mScroller.computeScrollOffset();
5532         final int curScrollY;
5533         if (animating) {
5534             curScrollY = mScroller.getCurrY();
5535         } else {
5536             curScrollY = mScrollY;
5537         }
5538         if (mCurScrollY != curScrollY) {
5539             mCurScrollY = curScrollY;
5540             fullRedrawNeeded = true;
5541             if (mView instanceof RootViewSurfaceTaker) {
5542                 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
5543             }
5544         }
5545 
5546         final float appScale = mAttachInfo.mApplicationScale;
5547         final boolean scalingRequired = mAttachInfo.mScalingRequired;
5548 
5549         final Rect dirty = mDirty;
5550         if (mSurfaceHolder != null) {
5551             // The app owns the surface, we won't draw.
5552             dirty.setEmpty();
5553             if (animating && mScroller != null) {
5554                 mScroller.abortAnimation();
5555             }
5556             return false;
5557         }
5558 
5559         if (fullRedrawNeeded) {
5560             dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
5561         }
5562 
5563         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
5564             Log.v(mTag, "Draw " + mView + "/"
5565                     + mWindowAttributes.getTitle()
5566                     + ": dirty={" + dirty.left + "," + dirty.top
5567                     + "," + dirty.right + "," + dirty.bottom + "} surface="
5568                     + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
5569                     appScale + ", width=" + mWidth + ", height=" + mHeight);
5570         }
5571 
5572         mAttachInfo.mTreeObserver.dispatchOnDraw();
5573 
5574         int xOffset = -mCanvasOffsetX;
5575         int yOffset = -mCanvasOffsetY + curScrollY;
5576         final WindowManager.LayoutParams params = mWindowAttributes;
5577         final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
5578         if (surfaceInsets != null) {
5579             xOffset -= surfaceInsets.left;
5580             yOffset -= surfaceInsets.top;
5581 
5582             // Offset dirty rect for surface insets.
5583             dirty.offset(surfaceInsets.left, surfaceInsets.top);
5584         }
5585 
5586         boolean accessibilityFocusDirty = isAccessibilityFocusDirty();
5587 
5588         // Force recalculation of transparent regions
5589         if (accessibilityFocusDirty) {
5590             final Rect bounds = mAttachInfo.mTmpInvalRect;
5591             if (getAccessibilityFocusedRect(bounds)) {
5592                 requestLayout();
5593             }
5594         }
5595 
5596         mAttachInfo.mDrawingTime =
5597                 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
5598 
5599         boolean useAsyncReport = false;
5600         if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
5601             if (isHardwareEnabled()) {
5602                 // If accessibility focus moved, always invalidate the root.
5603                 boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
5604                 mInvalidateRootRequested = false;
5605 
5606                 // Draw with hardware renderer.
5607                 mIsAnimating = false;
5608 
5609                 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
5610                     mHardwareYOffset = yOffset;
5611                     mHardwareXOffset = xOffset;
5612                     invalidateRoot = true;
5613                 }
5614 
5615                 if (invalidateRoot) {
5616                     mAttachInfo.mThreadedRenderer.invalidateRoot();
5617                 }
5618 
5619                 dirty.setEmpty();
5620 
5621                 // Stage the content drawn size now. It will be transferred to the renderer
5622                 // shortly before the draw commands get send to the renderer.
5623                 final boolean updated = updateContentDrawBounds();
5624 
5625                 if (mReportNextDraw) {
5626                     // report next draw overrides setStopped()
5627                     // This value is re-sync'd to the value of mStopped
5628                     // in the handling of mReportNextDraw post-draw.
5629                     mAttachInfo.mThreadedRenderer.setStopped(false);
5630                 }
5631 
5632                 if (updated) {
5633                     requestDrawWindow();
5634                 }
5635 
5636                 useAsyncReport = true;
5637 
5638                 if (mHdrRenderState.updateForFrame(mAttachInfo.mDrawingTime)) {
5639                     final float renderRatio = mHdrRenderState.getRenderHdrSdrRatio();
5640                     applyTransactionOnDraw(mTransaction.setExtendedRangeBrightness(
5641                             getSurfaceControl(), renderRatio,
5642                             mHdrRenderState.getDesiredHdrSdrRatio()));
5643                     mAttachInfo.mThreadedRenderer.setTargetHdrSdrRatio(renderRatio);
5644                 }
5645 
5646                 if (activeSyncGroup != null) {
5647                     registerCallbacksForSync(syncBuffer, activeSyncGroup);
5648                     if (syncBuffer) {
5649                         mAttachInfo.mThreadedRenderer.forceDrawNextFrame();
5650                     }
5651                 } else if (mHasPendingTransactions) {
5652                     // Register a callback if there's no sync involved but there were calls to
5653                     // applyTransactionOnDraw. If there is a sync involved, the sync callback will
5654                     // handle merging the pending transaction.
5655                     registerCallbackForPendingTransactions();
5656                 }
5657 
5658                 long timeNs = SystemClock.uptimeNanos();
5659                 mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
5660 
5661                 // Only trigger once per {@link ViewRootImpl} instance.
5662                 if (mAppStartInfoTimestampsFlagValue && mRenderThreadDrawStartTimeNs == -1) {
5663                     mRenderThreadDrawStartTimeNs = timeNs;
5664                 }
5665             } else {
5666                 // If we get here with a disabled & requested hardware renderer, something went
5667                 // wrong (an invalidate posted right before we destroyed the hardware surface
5668                 // for instance) so we should just bail out. Locking the surface with software
5669                 // rendering at this point would lock it forever and prevent hardware renderer
5670                 // from doing its job when it comes back.
5671                 // Before we request a new frame we must however attempt to reinitiliaze the
5672                 // hardware renderer if it's in requested state. This would happen after an
5673                 // eglTerminate() for instance.
5674                 if (mAttachInfo.mThreadedRenderer != null &&
5675                         !mAttachInfo.mThreadedRenderer.isEnabled() &&
5676                         mAttachInfo.mThreadedRenderer.isRequested() &&
5677                         mSurface.isValid()) {
5678 
5679                     try {
5680                         mAttachInfo.mThreadedRenderer.initializeIfNeeded(
5681                                 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
5682                     } catch (OutOfResourcesException e) {
5683                         handleOutOfResourcesException(e);
5684                         return false;
5685                     }
5686 
5687                     mFullRedrawNeeded = true;
5688                     scheduleTraversals();
5689                     return false;
5690                 }
5691 
5692                 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
5693                         scalingRequired, dirty, surfaceInsets)) {
5694                     return false;
5695                 }
5696             }
5697         }
5698 
5699         if (animating) {
5700             mFullRedrawNeeded = true;
5701             scheduleTraversals();
5702         }
5703         return useAsyncReport;
5704     }
5705 
5706     /**
5707      * @return true if drawing was successful, false if an error occurred
5708      */
drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets)5709     private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
5710             boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
5711 
5712         // Draw with software renderer.
5713         final Canvas canvas;
5714 
5715         try {
5716             canvas = mSurface.lockCanvas(dirty);
5717             canvas.setDensity(mDensity);
5718         } catch (Surface.OutOfResourcesException e) {
5719             handleOutOfResourcesException(e);
5720             return false;
5721         } catch (IllegalArgumentException e) {
5722             Log.e(mTag, "Could not lock surface", e);
5723             // Don't assume this is due to out of memory, it could be
5724             // something else, and if it is something else then we could
5725             // kill stuff (or ourself) for no reason.
5726             mLayoutRequested = true;    // ask wm for a new surface next time.
5727             return false;
5728         }
5729 
5730         try {
5731             if (DEBUG_ORIENTATION || DEBUG_DRAW) {
5732                 Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
5733                         + canvas.getWidth() + ", h=" + canvas.getHeight() + ", dirty: " + dirty
5734                         + ", xOff=" + xoff + ", yOff=" + yoff);
5735                 //canvas.drawARGB(255, 255, 0, 0);
5736             }
5737 
5738             // If this bitmap's format includes an alpha channel, we
5739             // need to clear it before drawing so that the child will
5740             // properly re-composite its drawing on a transparent
5741             // background. This automatically respects the clip/dirty region
5742             // or
5743             // If we are applying an offset, we need to clear the area
5744             // where the offset doesn't appear to avoid having garbage
5745             // left in the blank areas.
5746             if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
5747                 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
5748             }
5749 
5750             dirty.setEmpty();
5751             mIsAnimating = false;
5752             mView.mPrivateFlags |= View.PFLAG_DRAWN;
5753 
5754             if (DEBUG_DRAW) {
5755                 Context cxt = mView.getContext();
5756                 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
5757                         ", metrics=" + cxt.getResources().getDisplayMetrics() +
5758                         ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
5759             }
5760             canvas.translate(-xoff, -yoff);
5761             if (mTranslator != null) {
5762                 mTranslator.translateCanvas(canvas);
5763             }
5764             canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
5765 
5766             mView.draw(canvas);
5767 
5768             drawAccessibilityFocusedDrawableIfNeeded(canvas);
5769         } finally {
5770             try {
5771                 surface.unlockCanvasAndPost(canvas);
5772             } catch (IllegalArgumentException e) {
5773                 Log.e(mTag, "Could not unlock surface", e);
5774                 mLayoutRequested = true;    // ask wm for a new surface next time.
5775                 //noinspection ReturnInsideFinallyBlock
5776                 return false;
5777             }
5778 
5779             if (LOCAL_LOGV) {
5780                 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
5781             }
5782         }
5783         return true;
5784     }
5785 
5786     /**
5787      * We want to draw a highlight around the current accessibility focused.
5788      * Since adding a style for all possible view is not a viable option we
5789      * have this specialized drawing method.
5790      *
5791      * Note: We are doing this here to be able to draw the highlight for
5792      *       virtual views in addition to real ones.
5793      *
5794      * Note: A round accessibility focus border is drawn on rounded watch
5795      *
5796      * Note: Need to set bounds of accessibility focused drawable before drawing on rounded watch,
5797      * so that when accessibility focus moved, root will be invalidated at
5798      * {@link #draw(boolean, SurfaceSyncGroup, boolean)} and accessibility focus border will be
5799      * updated.
5800      *
5801      * @param canvas The canvas on which to draw.
5802      */
drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas)5803     private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
5804         final Rect bounds = mAttachInfo.mTmpInvalRect;
5805         if (getAccessibilityFocusedRect(bounds)) {
5806             boolean isRoundWatch = mContext.getResources().getConfiguration().isScreenRound()
5807                     && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
5808             final Drawable drawable = getAccessibilityFocusedDrawable();
5809             if (drawable != null) {
5810                 drawable.setBounds(bounds);
5811                 drawable.draw(canvas);
5812                 if (mDisplay != null && isRoundWatch) {
5813                     // Draw an extra round accessibility focus border on round watch
5814                     drawAccessibilityFocusedBorderOnRoundDisplay(canvas, bounds,
5815                             getRoundDisplayRadius(), getRoundDisplayAccessibilityHighlightPaint());
5816                 }
5817             }
5818         } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
5819             mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
5820         }
5821     }
5822 
getRoundDisplayRadius()5823     private int getRoundDisplayRadius() {
5824         Point displaySize = new Point();
5825         mDisplay.getRealSize(displaySize);
5826         return displaySize.x / 2;
5827     }
5828 
getRoundDisplayAccessibilityHighlightPaint()5829     private Paint getRoundDisplayAccessibilityHighlightPaint() {
5830         // Lazily create the round display accessibility highlight paint.
5831         if (mRoundDisplayAccessibilityHighlightPaint == null) {
5832             mRoundDisplayAccessibilityHighlightPaint = new Paint();
5833             mRoundDisplayAccessibilityHighlightPaint.setStyle(Paint.Style.STROKE);
5834             mRoundDisplayAccessibilityHighlightPaint.setAntiAlias(true);
5835         }
5836         mRoundDisplayAccessibilityHighlightPaint.setStrokeWidth(
5837                 mAccessibilityManager.getAccessibilityFocusStrokeWidth());
5838         mRoundDisplayAccessibilityHighlightPaint.setColor(
5839                 mAccessibilityManager.getAccessibilityFocusColor());
5840         return mRoundDisplayAccessibilityHighlightPaint;
5841     }
5842 
drawAccessibilityFocusedBorderOnRoundDisplay(Canvas canvas, Rect bounds, int roundDisplayRadius, Paint accessibilityFocusHighlightPaint)5843     private void drawAccessibilityFocusedBorderOnRoundDisplay(Canvas canvas, Rect bounds,
5844             int roundDisplayRadius, Paint accessibilityFocusHighlightPaint) {
5845         int saveCount = canvas.save();
5846         canvas.clipRect(bounds);
5847         canvas.drawCircle(/* cx= */ roundDisplayRadius,
5848                 /* cy= */ roundDisplayRadius,
5849                 /* radius= */ roundDisplayRadius
5850                         - mAccessibilityManager.getAccessibilityFocusStrokeWidth() / 2.0f,
5851                 accessibilityFocusHighlightPaint);
5852         canvas.restoreToCount(saveCount);
5853     }
5854 
getAccessibilityFocusedRect(Rect bounds)5855     private boolean getAccessibilityFocusedRect(Rect bounds) {
5856         if (mView == null) {
5857             Slog.w(TAG, "calling getAccessibilityFocusedRect() while the mView is null");
5858             return false;
5859         }
5860         if (!mAccessibilityManager.isEnabled()
5861                 || !mAccessibilityManager.isTouchExplorationEnabled()) {
5862             return false;
5863         }
5864 
5865         final View host = mAccessibilityFocusedHost;
5866         if (host == null || host.mAttachInfo == null) {
5867             return false;
5868         }
5869 
5870         final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
5871         if (provider == null) {
5872             host.getBoundsOnScreen(bounds, true);
5873         } else if (mAccessibilityFocusedVirtualView != null) {
5874             mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
5875         } else {
5876             return false;
5877         }
5878 
5879         // Transform the rect into window-relative coordinates.
5880         final AttachInfo attachInfo = mAttachInfo;
5881         bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
5882         bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
5883         if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
5884                 attachInfo.mViewRootImpl.mHeight)) {
5885             // If no intersection, set bounds to empty.
5886             bounds.setEmpty();
5887         }
5888         return !bounds.isEmpty();
5889     }
5890 
getAccessibilityFocusedDrawable()5891     private Drawable getAccessibilityFocusedDrawable() {
5892         // Lazily load the accessibility focus drawable.
5893         if (mAttachInfo.mAccessibilityFocusDrawable == null) {
5894             final TypedValue value = new TypedValue();
5895             final boolean resolved = mView.mContext.getTheme().resolveAttribute(
5896                     R.attr.accessibilityFocusedDrawable, value, true);
5897             if (resolved) {
5898                 mAttachInfo.mAccessibilityFocusDrawable =
5899                         mView.mContext.getDrawable(value.resourceId);
5900             }
5901         }
5902         // Sets the focus appearance data into the accessibility focus drawable.
5903         if (mAttachInfo.mAccessibilityFocusDrawable instanceof GradientDrawable) {
5904             final GradientDrawable drawable =
5905                     (GradientDrawable) mAttachInfo.mAccessibilityFocusDrawable;
5906             drawable.setStroke(mAccessibilityManager.getAccessibilityFocusStrokeWidth(),
5907                     mAccessibilityManager.getAccessibilityFocusColor());
5908         }
5909 
5910         return mAttachInfo.mAccessibilityFocusDrawable;
5911     }
5912 
updateSystemGestureExclusionRectsForView(View view)5913     void updateSystemGestureExclusionRectsForView(View view) {
5914         mGestureExclusionTracker.updateRectsForView(view);
5915         mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
5916     }
5917 
systemGestureExclusionChanged()5918     void systemGestureExclusionChanged() {
5919         final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects();
5920         if (rectsForWindowManager != null && mView != null) {
5921             try {
5922                 mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager);
5923             } catch (RemoteException e) {
5924                 throw e.rethrowFromSystemServer();
5925             }
5926             mAttachInfo.mTreeObserver
5927                     .dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager);
5928         }
5929     }
5930 
5931     /**
5932      * Called from DecorView when gesture interception state has changed.
5933      *
5934      * @param intercepted If DecorView is intercepting touch events
5935      */
updateDecorViewGestureInterception(boolean intercepted)5936     public void updateDecorViewGestureInterception(boolean intercepted) {
5937         mHandler.sendMessage(
5938                 mHandler.obtainMessage(
5939                         MSG_DECOR_VIEW_GESTURE_INTERCEPTION,
5940                         /* arg1= */ intercepted ? 1 : 0,
5941                         /* arg2= */ 0));
5942     }
5943 
decorViewInterceptionChanged(boolean intercepted)5944     void decorViewInterceptionChanged(boolean intercepted) {
5945         if (mView != null) {
5946             try {
5947                 mWindowSession.reportDecorViewGestureInterceptionChanged(mWindow, intercepted);
5948             } catch (RemoteException e) {
5949                 throw e.rethrowFromSystemServer();
5950             }
5951         }
5952     }
5953 
5954     /**
5955      * Set the root-level system gesture exclusion rects. These are added to those provided by
5956      * the root's view hierarchy.
5957      */
setRootSystemGestureExclusionRects(@onNull List<Rect> rects)5958     public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) {
5959         mGestureExclusionTracker.setRootRects(rects);
5960         mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
5961     }
5962 
5963     /**
5964      * Returns the root-level system gesture exclusion rects. These do not include those provided by
5965      * the root's view hierarchy.
5966      */
5967     @NonNull
getRootSystemGestureExclusionRects()5968     public List<Rect> getRootSystemGestureExclusionRects() {
5969         return mGestureExclusionTracker.getRootRects();
5970     }
5971 
5972     /**
5973      * Called from View when the position listener is triggered
5974      */
updateKeepClearRectsForView(View view)5975     void updateKeepClearRectsForView(View view) {
5976         mKeepClearRectsTracker.updateRectsForView(view);
5977         mUnrestrictedKeepClearRectsTracker.updateRectsForView(view);
5978         mHandler.sendEmptyMessage(MSG_KEEP_CLEAR_RECTS_CHANGED);
5979     }
5980 
updateKeepClearForAccessibilityFocusRect()5981     private void updateKeepClearForAccessibilityFocusRect() {
5982         if (mViewConfiguration.isPreferKeepClearForFocusEnabled()) {
5983             if (mKeepClearAccessibilityFocusRect == null) {
5984                 mKeepClearAccessibilityFocusRect = new Rect();
5985             }
5986             boolean hasAccessibilityFocus =
5987                     getAccessibilityFocusedRect(mKeepClearAccessibilityFocusRect);
5988             if (!hasAccessibilityFocus) {
5989                 mKeepClearAccessibilityFocusRect.setEmpty();
5990             }
5991             mHandler.obtainMessage(MSG_KEEP_CLEAR_RECTS_CHANGED, 1, 0).sendToTarget();
5992         }
5993     }
5994 
keepClearRectsChanged(boolean accessibilityFocusRectChanged)5995     void keepClearRectsChanged(boolean accessibilityFocusRectChanged) {
5996         boolean restrictedKeepClearRectsChanged = mKeepClearRectsTracker.computeChanges();
5997         boolean unrestrictedKeepClearRectsChanged =
5998                 mUnrestrictedKeepClearRectsTracker.computeChanges();
5999 
6000         if ((restrictedKeepClearRectsChanged || unrestrictedKeepClearRectsChanged
6001                 || accessibilityFocusRectChanged) && mView != null) {
6002             mHasPendingKeepClearAreaChange = true;
6003             // Only report keep clear areas immediately if they have not been reported recently
6004             if (!mHandler.hasMessages(MSG_REPORT_KEEP_CLEAR_RECTS)) {
6005                 mHandler.sendEmptyMessageDelayed(MSG_REPORT_KEEP_CLEAR_RECTS,
6006                         KEEP_CLEAR_AREA_REPORT_RATE_MILLIS);
6007                 reportKeepClearAreasChanged();
6008             }
6009         }
6010     }
6011 
reportKeepClearAreasChanged()6012     void reportKeepClearAreasChanged() {
6013         if (!mHasPendingKeepClearAreaChange || mView == null) {
6014             return;
6015         }
6016         mHasPendingKeepClearAreaChange = false;
6017 
6018         List<Rect> restrictedKeepClearRects = mKeepClearRectsTracker.getLastComputedRects();
6019         final List<Rect> unrestrictedKeepClearRects =
6020                 mUnrestrictedKeepClearRectsTracker.getLastComputedRects();
6021 
6022         if (mKeepClearAccessibilityFocusRect != null
6023                 && !mKeepClearAccessibilityFocusRect.isEmpty()) {
6024             restrictedKeepClearRects = new ArrayList<>(restrictedKeepClearRects);
6025             restrictedKeepClearRects.add(mKeepClearAccessibilityFocusRect);
6026         }
6027 
6028         try {
6029             mWindowSession.reportKeepClearAreasChanged(mWindow, restrictedKeepClearRects,
6030                     unrestrictedKeepClearRects);
6031         } catch (RemoteException e) {
6032             throw e.rethrowFromSystemServer();
6033         }
6034     }
6035 
6036     /**
6037      * Requests that the root render node is invalidated next time we perform a draw, such that
6038      * {@link WindowCallbacks#onPostDraw} gets called.
6039      */
requestInvalidateRootRenderNode()6040     public void requestInvalidateRootRenderNode() {
6041         mInvalidateRootRequested = true;
6042     }
6043 
scrollToRectOrFocus(Rect rectangle, boolean immediate)6044     boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
6045         final Rect ci = mAttachInfo.mContentInsets;
6046         final Rect vi = mAttachInfo.mVisibleInsets;
6047         int scrollY = 0;
6048         boolean handled = false;
6049 
6050         if (vi.left > ci.left || vi.top > ci.top
6051                 || vi.right > ci.right || vi.bottom > ci.bottom) {
6052             // We'll assume that we aren't going to change the scroll
6053             // offset, since we want to avoid that unless it is actually
6054             // going to make the focus visible...  otherwise we scroll
6055             // all over the place.
6056             scrollY = mScrollY;
6057             // We can be called for two different situations: during a draw,
6058             // to update the scroll position if the focus has changed (in which
6059             // case 'rectangle' is null), or in response to a
6060             // requestChildRectangleOnScreen() call (in which case 'rectangle'
6061             // is non-null and we just want to scroll to whatever that
6062             // rectangle is).
6063             final View focus = mView.findFocus();
6064             if (focus == null) {
6065                 return false;
6066             }
6067             View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
6068             if (focus != lastScrolledFocus) {
6069                 // If the focus has changed, then ignore any requests to scroll
6070                 // to a rectangle; first we want to make sure the entire focus
6071                 // view is visible.
6072                 rectangle = null;
6073             }
6074             if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
6075                     + " rectangle=" + rectangle + " ci=" + ci
6076                     + " vi=" + vi);
6077             if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
6078                 // Optimization: if the focus hasn't changed since last
6079                 // time, and no layout has happened, then just leave things
6080                 // as they are.
6081                 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
6082                         + mScrollY + " vi=" + vi.toShortString());
6083             } else {
6084                 // We need to determine if the currently focused view is
6085                 // within the visible part of the window and, if not, apply
6086                 // a pan so it can be seen.
6087                 mLastScrolledFocus = new WeakReference<View>(focus);
6088                 mScrollMayChange = false;
6089                 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
6090                 // Try to find the rectangle from the focus view.
6091                 if (focus.getGlobalVisibleRect(mVisRect, null)) {
6092                     if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
6093                             + mView.getWidth() + " h=" + mView.getHeight()
6094                             + " ci=" + ci.toShortString()
6095                             + " vi=" + vi.toShortString());
6096                     if (rectangle == null) {
6097                         focus.getFocusedRect(mTempRect);
6098                         if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
6099                                 + ": focusRect=" + mTempRect.toShortString());
6100                         if (mView instanceof ViewGroup) {
6101                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
6102                                     focus, mTempRect);
6103                         }
6104                         if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6105                                 "Focus in window: focusRect="
6106                                 + mTempRect.toShortString()
6107                                 + " visRect=" + mVisRect.toShortString());
6108                     } else {
6109                         mTempRect.set(rectangle);
6110                         if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6111                                 "Request scroll to rect: "
6112                                 + mTempRect.toShortString()
6113                                 + " visRect=" + mVisRect.toShortString());
6114                     }
6115                     if (mTempRect.intersect(mVisRect)) {
6116                         if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6117                                 "Focus window visible rect: "
6118                                 + mTempRect.toShortString());
6119                         if (mTempRect.height() >
6120                                 (mView.getHeight()-vi.top-vi.bottom)) {
6121                             // If the focus simply is not going to fit, then
6122                             // best is probably just to leave things as-is.
6123                             if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6124                                     "Too tall; leaving scrollY=" + scrollY);
6125                         }
6126                         // Next, check whether top or bottom is covered based on the non-scrolled
6127                         // position, and calculate new scrollY (or set it to 0).
6128                         // We can't keep using mScrollY here. For example mScrollY is non-zero
6129                         // due to IME, then IME goes away. The current value of mScrollY leaves top
6130                         // and bottom both visible, but we still need to scroll it back to 0.
6131                         else if (mTempRect.top < vi.top) {
6132                             scrollY = mTempRect.top - vi.top;
6133                             if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6134                                     "Top covered; scrollY=" + scrollY);
6135                         } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) {
6136                             scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom);
6137                             if (DEBUG_INPUT_RESIZE) Log.v(mTag,
6138                                     "Bottom covered; scrollY=" + scrollY);
6139                         } else {
6140                             scrollY = 0;
6141                         }
6142                         handled = true;
6143                     }
6144                 }
6145             }
6146         }
6147 
6148         if (scrollY != mScrollY) {
6149             if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
6150                     + mScrollY + " , new=" + scrollY);
6151             if (!immediate) {
6152                 if (mScroller == null) {
6153                     mScroller = new Scroller(mView.getContext());
6154                 }
6155                 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
6156             } else if (mScroller != null) {
6157                 mScroller.abortAnimation();
6158             }
6159             mScrollY = scrollY;
6160         }
6161 
6162         return handled;
6163     }
6164 
6165     @VisibleForTesting(visibility = PACKAGE)
setScrollY(int scrollY)6166     public void setScrollY(int scrollY) {
6167         if (mScroller != null) {
6168             mScroller.abortAnimation();
6169         }
6170         mScrollY = scrollY;
6171     }
6172 
6173     @VisibleForTesting
getScrollY()6174     public int getScrollY() {
6175         return mScrollY;
6176     }
6177 
6178     /**
6179      * @hide
6180      */
6181     @UnsupportedAppUsage
getAccessibilityFocusedHost()6182     public View getAccessibilityFocusedHost() {
6183         return mAccessibilityFocusedHost;
6184     }
6185 
6186     /**
6187      * Get accessibility-focused virtual view. The bounds and sourceNodeId of the returned node is
6188      * up-to-date while other fields may be stale.
6189      *
6190      * @hide
6191      */
6192     @UnsupportedAppUsage
getAccessibilityFocusedVirtualView()6193     public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
6194         return mAccessibilityFocusedVirtualView;
6195     }
6196 
setAccessibilityFocus(View view, AccessibilityNodeInfo node)6197     void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
6198         // If we have a virtual view with accessibility focus we need
6199         // to clear the focus and invalidate the virtual view bounds.
6200         if (mAccessibilityFocusedVirtualView != null) {
6201 
6202             AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
6203             View focusHost = mAccessibilityFocusedHost;
6204 
6205             // Wipe the state of the current accessibility focus since
6206             // the call into the provider to clear accessibility focus
6207             // will fire an accessibility event which will end up calling
6208             // this method and we want to have clean state when this
6209             // invocation happens.
6210             mAccessibilityFocusedHost = null;
6211             mAccessibilityFocusedVirtualView = null;
6212 
6213             // Clear accessibility focus on the host after clearing state since
6214             // this method may be reentrant.
6215             focusHost.clearAccessibilityFocusNoCallbacks(
6216                     AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
6217 
6218             AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
6219             if (provider != null) {
6220                 // Invalidate the area of the cleared accessibility focus.
6221                 focusNode.getBoundsInParent(mTempRect);
6222                 focusHost.invalidate(mTempRect);
6223                 // Clear accessibility focus in the virtual node.
6224                 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
6225                         focusNode.getSourceNodeId());
6226                 provider.performAction(virtualNodeId,
6227                         AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
6228             }
6229             focusNode.recycle();
6230         }
6231         if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view))  {
6232             // Clear accessibility focus in the view.
6233             mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(
6234                     AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
6235         }
6236 
6237         // Set the new focus host and node.
6238         mAccessibilityFocusedHost = view;
6239         mAccessibilityFocusedVirtualView = node;
6240         updateKeepClearForAccessibilityFocusRect();
6241 
6242         requestInvalidateRootRenderNode();
6243         if (isAccessibilityFocusDirty()) {
6244             scheduleTraversals();
6245         }
6246     }
6247 
hasPointerCapture()6248     boolean hasPointerCapture() {
6249         return mPointerCapture;
6250     }
6251 
requestPointerCapture(boolean enabled)6252     void requestPointerCapture(boolean enabled) {
6253         final IBinder inputToken = getInputToken();
6254         if (inputToken == null) {
6255             Log.e(mTag, "No input channel to request Pointer Capture.");
6256             return;
6257         }
6258         InputManagerGlobal
6259                 .getInstance()
6260                 .requestPointerCapture(inputToken, enabled);
6261     }
6262 
handlePointerCaptureChanged(boolean hasCapture)6263     private void handlePointerCaptureChanged(boolean hasCapture) {
6264         if (mPointerCapture == hasCapture) {
6265             return;
6266         }
6267         mPointerCapture = hasCapture;
6268         if (mView != null) {
6269             mView.dispatchPointerCaptureChanged(hasCapture);
6270         }
6271     }
6272 
updateColorModeIfNeeded(@ctivityInfo.ColorMode int colorMode, float desiredRatio)6273     private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode,
6274             float desiredRatio) {
6275         if (mAttachInfo.mThreadedRenderer == null) {
6276             return;
6277         }
6278         boolean isHdr = colorMode == ActivityInfo.COLOR_MODE_HDR
6279                 || colorMode == ActivityInfo.COLOR_MODE_HDR10;
6280         if (isHdr && !mDisplay.isHdrSdrRatioAvailable()) {
6281             colorMode = ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
6282             isHdr = false;
6283         }
6284         // TODO: Centralize this sanitization? Why do we let setting bad modes?
6285         // Alternatively, can we just let HWUI figure it out? Do we need to care here?
6286         if (colorMode != ActivityInfo.COLOR_MODE_A8
6287                 && !getConfiguration().isScreenWideColorGamut()) {
6288             colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
6289         }
6290         float automaticRatio = mAttachInfo.mThreadedRenderer.setColorMode(colorMode);
6291         if (desiredRatio == 0 || desiredRatio > automaticRatio) {
6292             desiredRatio = automaticRatio;
6293         }
6294 
6295         mHdrRenderState.setDesiredHdrSdrRatio(isHdr, desiredRatio);
6296     }
6297 
6298     @Override
requestChildFocus(View child, View focused)6299     public void requestChildFocus(View child, View focused) {
6300         if (DEBUG_INPUT_RESIZE) {
6301             Log.v(mTag, "Request child focus: focus now " + focused);
6302         }
6303         checkThread();
6304         scheduleTraversals();
6305     }
6306 
6307     @Override
clearChildFocus(View child)6308     public void clearChildFocus(View child) {
6309         if (DEBUG_INPUT_RESIZE) {
6310             Log.v(mTag, "Clearing child focus");
6311         }
6312         checkThread();
6313         scheduleTraversals();
6314     }
6315 
6316     @Override
getParentForAccessibility()6317     public ViewParent getParentForAccessibility() {
6318         return null;
6319     }
6320 
6321     @Override
focusableViewAvailable(View v)6322     public void focusableViewAvailable(View v) {
6323         checkThread();
6324         if (mView != null) {
6325             if (!mView.hasFocus()) {
6326                 if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) {
6327                     v.requestFocus();
6328                 }
6329             } else {
6330                 // the one case where will transfer focus away from the current one
6331                 // is if the current view is a view group that prefers to give focus
6332                 // to its children first AND the view is a descendant of it.
6333                 View focused = mView.findFocus();
6334                 if (focused instanceof ViewGroup) {
6335                     ViewGroup group = (ViewGroup) focused;
6336                     if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
6337                             && isViewDescendantOf(v, focused)) {
6338                         v.requestFocus();
6339                     }
6340                 }
6341             }
6342         }
6343     }
6344 
6345     @Override
recomputeViewAttributes(View child)6346     public void recomputeViewAttributes(View child) {
6347         checkThread();
6348         if (mView == child) {
6349             mAttachInfo.mRecomputeGlobalAttributes = true;
6350             if (!mWillDrawSoon) {
6351                 scheduleTraversals();
6352             }
6353         }
6354     }
6355 
dispatchDetachedFromWindow()6356     void dispatchDetachedFromWindow() {
6357         // Make sure we free-up insets resources if view never received onWindowFocusLost()
6358         // because of a die-signal
6359         mInsetsController.onWindowFocusLost();
6360         mFirstInputStage.onDetachedFromWindow();
6361         if (mView != null && mView.mAttachInfo != null) {
6362             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
6363             mView.dispatchDetachedFromWindow();
6364         }
6365 
6366         mAccessibilityInteractionConnectionManager.ensureNoConnection();
6367         mAccessibilityInteractionConnectionManager.ensureNoDirectConnection();
6368         removeSendWindowContentChangedCallback();
6369         if (android.view.accessibility.Flags.preventLeakingViewrootimpl()
6370                 && mAccessibilityInteractionController != null) {
6371             mAccessibilityInteractionController.destroy();
6372             mAccessibilityInteractionController = null;
6373         }
6374 
6375         destroyHardwareRenderer();
6376 
6377         setAccessibilityFocus(null, null);
6378 
6379         mInsetsController.cancelExistingAnimations();
6380 
6381         mView.assignParent(null);
6382         mView = null;
6383         mAttachInfo.mRootView = null;
6384 
6385         destroySurface();
6386 
6387         if (mInputQueueCallback != null && mInputQueue != null) {
6388             mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
6389             mInputQueue.dispose();
6390             mInputQueueCallback = null;
6391             mInputQueue = null;
6392         }
6393         try {
6394             mWindowSession.remove(mWindow.asBinder());
6395         } catch (RemoteException e) {
6396         }
6397         // Dispose receiver would dispose client InputChannel, too. That could send out a socket
6398         // broken event, so we need to unregister the server InputChannel when removing window to
6399         // prevent server side receive the event and prompt error.
6400         if (mInputEventReceiver != null) {
6401             mInputEventReceiver.dispose();
6402             mInputEventReceiver = null;
6403         }
6404 
6405         unregisterListeners();
6406         unscheduleTraversals();
6407     }
6408 
6409     /**
6410      * Notifies all callbacks that configuration and/or display has changed and updates internal
6411      * state.
6412      * @param mergedConfiguration New global and override config in {@link MergedConfiguration}
6413      *                            container.
6414      * @param force Flag indicating if we should force apply the config.
6415      * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not
6416      *                     changed.
6417      * @param activityWindowInfo New activity window info. {@code null} if it is non-app window, or
6418      *                           this is not a Configuration change to the activity window (global).
6419      */
performConfigurationChange(@onNull MergedConfiguration mergedConfiguration, boolean force, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo)6420     private void performConfigurationChange(@NonNull MergedConfiguration mergedConfiguration,
6421             boolean force, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) {
6422         if (mergedConfiguration == null) {
6423             throw new IllegalArgumentException("No merged config provided.");
6424         }
6425 
6426         final int lastRotation = mLastReportedMergedConfiguration.getMergedConfiguration()
6427                 .windowConfiguration.getRotation();
6428         final int newRotation = mergedConfiguration.getMergedConfiguration()
6429                 .windowConfiguration.getRotation();
6430         if (lastRotation != newRotation) {
6431             // Trigger ThreadedRenderer#updateSurface() if the surface control doesn't change.
6432             // Because even if the actual surface size is not changed, e.g. flip 180 degrees,
6433             // the buffers may still have content in previous rotation. And the next draw may
6434             // not update all regions, that causes some afterimages to flicker.
6435             mUpdateSurfaceNeeded = true;
6436             if (!mIsInTraversal) {
6437                 mForceNextWindowRelayout = true;
6438             }
6439         }
6440 
6441         Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
6442         final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration();
6443         if (DEBUG_CONFIGURATION) Log.v(mTag,
6444                 "Applying new config to window " + mWindowAttributes.getTitle()
6445                         + ", globalConfig: " + globalConfig
6446                         + ", overrideConfig: " + overrideConfig);
6447 
6448         final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
6449         if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
6450             globalConfig = new Configuration(globalConfig);
6451             ci.applyToConfiguration(mNoncompatDensity, globalConfig);
6452         }
6453 
6454         synchronized (sConfigCallbacks) {
6455             for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
6456                 sConfigCallbacks.get(i).onConfigurationChanged(globalConfig);
6457             }
6458         }
6459 
6460         mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
6461         if (mLastReportedActivityWindowInfo != null && activityWindowInfo != null) {
6462             mLastReportedActivityWindowInfo.set(activityWindowInfo);
6463         }
6464 
6465         mForceNextConfigUpdate = force;
6466         if (mActivityConfigCallback != null) {
6467             // An activity callback is set - notify it about override configuration update.
6468             // This basically initiates a round trip to ActivityThread and back, which will ensure
6469             // that corresponding activity and resources are updated before updating inner state of
6470             // ViewRootImpl. Eventually it will call #updateConfiguration().
6471             mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId,
6472                     activityWindowInfo);
6473         } else {
6474             // There is no activity callback - update the configuration right away.
6475             updateConfiguration(newDisplayId);
6476         }
6477         mForceNextConfigUpdate = false;
6478     }
6479 
6480     /**
6481      * Update display and views if last applied merged configuration changed.
6482      * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise.
6483      */
updateConfiguration(int newDisplayId)6484     public void updateConfiguration(int newDisplayId) {
6485         if (mView == null) {
6486             return;
6487         }
6488 
6489         // At this point the resources have been updated to
6490         // have the most recent config, whatever that is.  Use
6491         // the one in them which may be newer.
6492         final Resources localResources = mView.getResources();
6493         final Configuration config = localResources.getConfiguration();
6494 
6495         // Handle move to display.
6496         if (newDisplayId != INVALID_DISPLAY) {
6497             onMovedToDisplay(newDisplayId, config);
6498         }
6499 
6500         // Handle configuration change.
6501         if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
6502             // Update the display with new DisplayAdjustments.
6503             updateInternalDisplay(mDisplay.getDisplayId(), localResources);
6504 
6505             updateLastConfigurationFromResources(config);
6506             mView.dispatchConfigurationChanged(config);
6507 
6508             // We could have gotten this {@link Configuration} update after we called
6509             // {@link #performTraversals} with an older {@link Configuration}. As a result, our
6510             // window frame may be stale. We must ensure the next pass of {@link #performTraversals}
6511             // catches this.
6512             mForceNextWindowRelayout = true;
6513             requestLayout();
6514         }
6515 
6516         updateForceDarkMode();
6517     }
6518 
updateLastConfigurationFromResources(Configuration resConfig)6519     private void updateLastConfigurationFromResources(Configuration resConfig) {
6520         final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
6521         final int currentLayoutDirection = resConfig.getLayoutDirection();
6522         mLastConfigurationFromResources.setTo(resConfig);
6523         // Update layout direction in case the language or screen layout is changed.
6524         if (lastLayoutDirection != currentLayoutDirection && mView != null
6525                 && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
6526             mView.setLayoutDirection(currentLayoutDirection);
6527         }
6528     }
6529 
6530     /**
6531      * Return true if child is an ancestor of parent, (or equal to the parent).
6532      */
isViewDescendantOf(View child, View parent)6533     public static boolean isViewDescendantOf(View child, View parent) {
6534         if (child == parent) {
6535             return true;
6536         }
6537 
6538         final ViewParent theParent = child.getParent();
6539         return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
6540     }
6541 
forceLayout(View view)6542     private static void forceLayout(View view) {
6543         view.forceLayout();
6544         if (view instanceof ViewGroup) {
6545             ViewGroup group = (ViewGroup) view;
6546             final int count = group.getChildCount();
6547             for (int i = 0; i < count; i++) {
6548                 forceLayout(group.getChildAt(i));
6549             }
6550         }
6551     }
6552 
6553     private static final int MSG_INVALIDATE = 1;
6554     private static final int MSG_INVALIDATE_RECT = 2;
6555     private static final int MSG_DIE = 3;
6556     private static final int MSG_RESIZED = 4;
6557     private static final int MSG_RESIZED_REPORT = 5;
6558     private static final int MSG_WINDOW_FOCUS_CHANGED = 6;
6559     private static final int MSG_DISPATCH_INPUT_EVENT = 7;
6560     private static final int MSG_DISPATCH_APP_VISIBILITY = 8;
6561     private static final int MSG_DISPATCH_GET_NEW_SURFACE = 9;
6562     private static final int MSG_DISPATCH_KEY_FROM_IME = 11;
6563     private static final int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12;
6564     private static final int MSG_CHECK_FOCUS = 13;
6565     private static final int MSG_CLOSE_SYSTEM_DIALOGS = 14;
6566     private static final int MSG_DISPATCH_DRAG_EVENT = 15;
6567     private static final int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
6568     private static final int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
6569     private static final int MSG_UPDATE_CONFIGURATION = 18;
6570     private static final int MSG_PROCESS_INPUT_EVENTS = 19;
6571     private static final int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
6572     private static final int MSG_INVALIDATE_WORLD = 22;
6573     private static final int MSG_WINDOW_MOVED = 23;
6574     private static final int MSG_SYNTHESIZE_INPUT_EVENT = 24;
6575     private static final int MSG_DISPATCH_WINDOW_SHOWN = 25;
6576     private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
6577     private static final int MSG_POINTER_CAPTURE_CHANGED = 28;
6578     private static final int MSG_INSETS_CONTROL_CHANGED = 29;
6579     private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 30;
6580     private static final int MSG_SHOW_INSETS = 31;
6581     private static final int MSG_HIDE_INSETS = 32;
6582     private static final int MSG_REQUEST_SCROLL_CAPTURE = 33;
6583     private static final int MSG_WINDOW_TOUCH_MODE_CHANGED = 34;
6584     private static final int MSG_KEEP_CLEAR_RECTS_CHANGED = 35;
6585     private static final int MSG_REPORT_KEEP_CLEAR_RECTS = 36;
6586     private static final int MSG_PAUSED_FOR_SYNC_TIMEOUT = 37;
6587     private static final int MSG_DECOR_VIEW_GESTURE_INTERCEPTION = 38;
6588     private static final int MSG_TOUCH_BOOST_TIMEOUT = 39;
6589     private static final int MSG_CHECK_INVALIDATION_IDLE = 40;
6590     private static final int MSG_REFRESH_POINTER_ICON = 41;
6591     private static final int MSG_FRAME_RATE_SETTING = 42;
6592 
6593     final class ViewRootHandler extends Handler {
6594         @Override
getMessageName(Message message)6595         public String getMessageName(Message message) {
6596             switch (message.what) {
6597                 case MSG_INVALIDATE:
6598                     return "MSG_INVALIDATE";
6599                 case MSG_INVALIDATE_RECT:
6600                     return "MSG_INVALIDATE_RECT";
6601                 case MSG_DIE:
6602                     return "MSG_DIE";
6603                 case MSG_RESIZED:
6604                     return "MSG_RESIZED";
6605                 case MSG_RESIZED_REPORT:
6606                     return "MSG_RESIZED_REPORT";
6607                 case MSG_WINDOW_FOCUS_CHANGED:
6608                     return "MSG_WINDOW_FOCUS_CHANGED";
6609                 case MSG_DISPATCH_INPUT_EVENT:
6610                     return "MSG_DISPATCH_INPUT_EVENT";
6611                 case MSG_DISPATCH_APP_VISIBILITY:
6612                     return "MSG_DISPATCH_APP_VISIBILITY";
6613                 case MSG_DISPATCH_GET_NEW_SURFACE:
6614                     return "MSG_DISPATCH_GET_NEW_SURFACE";
6615                 case MSG_DISPATCH_KEY_FROM_IME:
6616                     return "MSG_DISPATCH_KEY_FROM_IME";
6617                 case MSG_DISPATCH_KEY_FROM_AUTOFILL:
6618                     return "MSG_DISPATCH_KEY_FROM_AUTOFILL";
6619                 case MSG_CHECK_FOCUS:
6620                     return "MSG_CHECK_FOCUS";
6621                 case MSG_CLOSE_SYSTEM_DIALOGS:
6622                     return "MSG_CLOSE_SYSTEM_DIALOGS";
6623                 case MSG_DISPATCH_DRAG_EVENT:
6624                     return "MSG_DISPATCH_DRAG_EVENT";
6625                 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
6626                     return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
6627                 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
6628                     return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
6629                 case MSG_UPDATE_CONFIGURATION:
6630                     return "MSG_UPDATE_CONFIGURATION";
6631                 case MSG_PROCESS_INPUT_EVENTS:
6632                     return "MSG_PROCESS_INPUT_EVENTS";
6633                 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
6634                     return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
6635                 case MSG_WINDOW_MOVED:
6636                     return "MSG_WINDOW_MOVED";
6637                 case MSG_SYNTHESIZE_INPUT_EVENT:
6638                     return "MSG_SYNTHESIZE_INPUT_EVENT";
6639                 case MSG_DISPATCH_WINDOW_SHOWN:
6640                     return "MSG_DISPATCH_WINDOW_SHOWN";
6641                 case MSG_POINTER_CAPTURE_CHANGED:
6642                     return "MSG_POINTER_CAPTURE_CHANGED";
6643                 case MSG_INSETS_CONTROL_CHANGED:
6644                     return "MSG_INSETS_CONTROL_CHANGED";
6645                 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED:
6646                     return "MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED";
6647                 case MSG_SHOW_INSETS:
6648                     return "MSG_SHOW_INSETS";
6649                 case MSG_HIDE_INSETS:
6650                     return "MSG_HIDE_INSETS";
6651                 case MSG_WINDOW_TOUCH_MODE_CHANGED:
6652                     return "MSG_WINDOW_TOUCH_MODE_CHANGED";
6653                 case MSG_KEEP_CLEAR_RECTS_CHANGED:
6654                     return "MSG_KEEP_CLEAR_RECTS_CHANGED";
6655                 case MSG_CHECK_INVALIDATION_IDLE:
6656                     return "MSG_CHECK_INVALIDATION_IDLE";
6657                 case MSG_REFRESH_POINTER_ICON:
6658                     return "MSG_REFRESH_POINTER_ICON";
6659                 case MSG_TOUCH_BOOST_TIMEOUT:
6660                     return "MSG_TOUCH_BOOST_TIMEOUT";
6661                 case MSG_FRAME_RATE_SETTING:
6662                     return "MSG_FRAME_RATE_SETTING";
6663             }
6664             return super.getMessageName(message);
6665         }
6666 
6667         @Override
sendMessageAtTime(Message msg, long uptimeMillis)6668         public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
6669             if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
6670                 // Debugging for b/27963013
6671                 throw new NullPointerException(
6672                         "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
6673             }
6674             return super.sendMessageAtTime(msg, uptimeMillis);
6675         }
6676 
6677         @Override
handleMessage(Message msg)6678         public void handleMessage(Message msg) {
6679             if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
6680                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, getMessageName(msg));
6681             }
6682             try {
6683                 handleMessageImpl(msg);
6684             } finally {
6685                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
6686             }
6687         }
6688 
handleMessageImpl(Message msg)6689         private void handleMessageImpl(Message msg) {
6690             switch (msg.what) {
6691                 case MSG_INVALIDATE:
6692                     ((View) msg.obj).invalidate();
6693                     break;
6694                 case MSG_INVALIDATE_RECT:
6695                     final View.AttachInfo.InvalidateInfo info =
6696                             (View.AttachInfo.InvalidateInfo) msg.obj;
6697                     info.target.invalidate(info.left, info.top, info.right, info.bottom);
6698                     info.recycle();
6699                     break;
6700                 case MSG_PROCESS_INPUT_EVENTS:
6701                     mProcessInputEventsScheduled = false;
6702                     doProcessInputEvents();
6703                     break;
6704                 case MSG_DISPATCH_APP_VISIBILITY:
6705                     handleAppVisibility(msg.arg1 != 0);
6706                     break;
6707                 case MSG_DISPATCH_GET_NEW_SURFACE:
6708                     handleGetNewSurface();
6709                     break;
6710                 case MSG_RESIZED:
6711                 case MSG_RESIZED_REPORT: {
6712                     final SomeArgs args = (SomeArgs) msg.obj;
6713                     final ClientWindowFrames frames = (ClientWindowFrames) args.arg1;
6714                     final boolean reportDraw = msg.what == MSG_RESIZED_REPORT;
6715                     final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2;
6716                     final InsetsState insetsState = (InsetsState) args.arg3;
6717                     final ActivityWindowInfo activityWindowInfo = (ActivityWindowInfo) args.arg4;
6718                     final boolean forceLayout = args.argi1 != 0;
6719                     final boolean alwaysConsumeSystemBars = args.argi2 != 0;
6720                     final int displayId = args.argi3;
6721                     final int syncSeqId = args.argi4;
6722                     final boolean dragResizing = args.argi5 != 0;
6723                     handleResized(frames, reportDraw, mergedConfiguration, insetsState, forceLayout,
6724                             alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing,
6725                             activityWindowInfo);
6726                     args.recycle();
6727                     break;
6728                 }
6729                 case MSG_INSETS_CONTROL_CHANGED: {
6730                     final SomeArgs args = (SomeArgs) msg.obj;
6731                     final InsetsState insetsState = (InsetsState) args.arg1;
6732                     final InsetsSourceControl.Array activeControls =
6733                             (InsetsSourceControl.Array) args.arg2;
6734                     handleInsetsControlChanged(insetsState, activeControls);
6735                     args.recycle();
6736                     break;
6737                 }
6738                 case MSG_SHOW_INSETS: {
6739                     final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj;
6740                     ImeTracker.forLogging().onProgress(statsToken,
6741                             ImeTracker.PHASE_CLIENT_HANDLE_SHOW_INSETS);
6742                     if (mView == null) {
6743                         Log.e(TAG,
6744                                 String.format("Calling showInsets(%d,%b) on window that no longer"
6745                                         + " has views.", msg.arg1, msg.arg2 == 1));
6746                     }
6747                     clearLowProfileModeIfNeeded(msg.arg1, msg.arg2 == 1);
6748                     mInsetsController.show(msg.arg1, msg.arg2 == 1, statsToken);
6749                     break;
6750                 }
6751                 case MSG_HIDE_INSETS: {
6752                     final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj;
6753                     ImeTracker.forLogging().onProgress(statsToken,
6754                             ImeTracker.PHASE_CLIENT_HANDLE_HIDE_INSETS);
6755                     mInsetsController.hide(msg.arg1, msg.arg2 == 1, statsToken);
6756                     break;
6757                 }
6758                 case MSG_WINDOW_MOVED:
6759                     if (mAdded) {
6760                         final int w = mWinFrame.width();
6761                         final int h = mWinFrame.height();
6762                         final int l = msg.arg1;
6763                         final int t = msg.arg2;
6764                         mTmpFrames.frame.left = l;
6765                         mTmpFrames.frame.right = l + w;
6766                         mTmpFrames.frame.top = t;
6767                         mTmpFrames.frame.bottom = t + h;
6768                         setFrame(mTmpFrames.frame, false /* withinRelayout */);
6769                         maybeHandleWindowMove(mWinFrame);
6770                     }
6771                     break;
6772                 case MSG_WINDOW_FOCUS_CHANGED: {
6773                     handleWindowFocusChanged();
6774                 } break;
6775                 case MSG_WINDOW_TOUCH_MODE_CHANGED: {
6776                     handleWindowTouchModeChanged();
6777                 } break;
6778                 case MSG_DIE: {
6779                     doDie();
6780                 } break;
6781                 case MSG_DISPATCH_INPUT_EVENT: {
6782                     SomeArgs args = (SomeArgs) msg.obj;
6783                     InputEvent event = (InputEvent) args.arg1;
6784                     InputEventReceiver receiver = (InputEventReceiver) args.arg2;
6785                     enqueueInputEvent(event, receiver, 0, true);
6786                     args.recycle();
6787                 } break;
6788                 case MSG_SYNTHESIZE_INPUT_EVENT: {
6789                     InputEvent event = (InputEvent) msg.obj;
6790                     enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
6791                 } break;
6792                 case MSG_DISPATCH_KEY_FROM_IME: {
6793                     if (LOCAL_LOGV) {
6794                         Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView);
6795                     }
6796                     KeyEvent event = (KeyEvent) msg.obj;
6797                     if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) {
6798                         // The IME is trying to say this event is from the
6799                         // system!  Bad bad bad!
6800                         //noinspection UnusedAssignment
6801                         event = KeyEvent.changeFlags(event,
6802                                 event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
6803                     }
6804                     enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
6805                 } break;
6806                 case MSG_DISPATCH_KEY_FROM_AUTOFILL: {
6807                     if (LOCAL_LOGV) {
6808                         Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView);
6809                     }
6810                     KeyEvent event = (KeyEvent) msg.obj;
6811                     enqueueInputEvent(event, null, 0, true);
6812                 } break;
6813                 case MSG_CHECK_FOCUS: {
6814                     getImeFocusController().onScheduledCheckFocus();
6815                 } break;
6816                 case MSG_CLOSE_SYSTEM_DIALOGS: {
6817                     if (mView != null) {
6818                         mView.onCloseSystemDialogs((String) msg.obj);
6819                     }
6820                 } break;
6821                 case MSG_DISPATCH_DRAG_EVENT: {
6822                 } // fall through
6823                 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
6824                     DragEvent event = (DragEvent) msg.obj;
6825                     // only present when this app called startDrag()
6826                     event.mLocalState = mLocalDragState;
6827                     final boolean traceDragEvent = event.mAction != ACTION_DRAG_LOCATION;
6828                     try {
6829                         if (traceDragEvent) {
6830                             Trace.traceBegin(TRACE_TAG_VIEW,
6831                                     "c#" + DragEvent.actionToString(event.mAction));
6832                         }
6833                         handleDragEvent(event);
6834                     } finally {
6835                         if (traceDragEvent) {
6836                             Trace.traceEnd(TRACE_TAG_VIEW);
6837                         }
6838                     }
6839                 } break;
6840                 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
6841                     handleDispatchSystemUiVisibilityChanged();
6842                 } break;
6843                 case MSG_UPDATE_CONFIGURATION: {
6844                     Configuration config = (Configuration) msg.obj;
6845                     if (config.isOtherSeqNewer(
6846                             mLastReportedMergedConfiguration.getMergedConfiguration())) {
6847                         // If we already have a newer merged config applied - use its global part.
6848                         config = mLastReportedMergedConfiguration.getGlobalConfiguration();
6849                     }
6850 
6851                     // Use the newer global config and last reported override config.
6852                     mPendingMergedConfiguration.setConfiguration(config,
6853                             mLastReportedMergedConfiguration.getOverrideConfiguration());
6854                     if (mPendingActivityWindowInfo != null) {
6855                         mPendingActivityWindowInfo.set(mLastReportedActivityWindowInfo);
6856                     }
6857 
6858                     performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration),
6859                             false /* force */, INVALID_DISPLAY /* same display */,
6860                             mPendingActivityWindowInfo != null
6861                                     ? new ActivityWindowInfo(mPendingActivityWindowInfo)
6862                                     : null);
6863                 } break;
6864                 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
6865                     setAccessibilityFocus(null, null);
6866                 } break;
6867                 case MSG_INVALIDATE_WORLD: {
6868                     if (mView != null) {
6869                         invalidateWorld(mView);
6870                     }
6871                 } break;
6872                 case MSG_DISPATCH_WINDOW_SHOWN: {
6873                     handleDispatchWindowShown();
6874                 } break;
6875                 case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
6876                     final IResultReceiver receiver = (IResultReceiver) msg.obj;
6877                     final int deviceId = msg.arg1;
6878                     handleRequestKeyboardShortcuts(receiver, deviceId);
6879                 } break;
6880                 case MSG_POINTER_CAPTURE_CHANGED: {
6881                     final boolean hasCapture = msg.arg1 != 0;
6882                     handlePointerCaptureChanged(hasCapture);
6883                 } break;
6884                 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: {
6885                     systemGestureExclusionChanged();
6886                 }   break;
6887                 case MSG_DECOR_VIEW_GESTURE_INTERCEPTION: {
6888                     decorViewInterceptionChanged(/* intercepted= */ msg.arg1 == 1);
6889                 }   break;
6890                 case MSG_KEEP_CLEAR_RECTS_CHANGED: {
6891                     keepClearRectsChanged(/* accessibilityFocusRectChanged= */ msg.arg1 == 1);
6892                 }   break;
6893                 case MSG_REPORT_KEEP_CLEAR_RECTS: {
6894                     reportKeepClearAreasChanged();
6895                 }   break;
6896                 case MSG_REQUEST_SCROLL_CAPTURE:
6897                     handleScrollCaptureRequest((IScrollCaptureResponseListener) msg.obj);
6898                     break;
6899                 case MSG_PAUSED_FOR_SYNC_TIMEOUT:
6900                     Log.e(mTag, "Timedout waiting to unpause for sync");
6901                     mNumPausedForSync = 0;
6902                     scheduleTraversals();
6903                     break;
6904                 case MSG_CHECK_INVALIDATION_IDLE: {
6905                     long delta;
6906                     if (mIsTouchBoosting || mIsFrameRateBoosting || mInsetsAnimationRunning) {
6907                         delta = 0;
6908                     } else {
6909                         delta = System.nanoTime() / NANOS_PER_MILLI - mLastUpdateTimeMillis;
6910                     }
6911                     if (delta >= IDLE_TIME_MILLIS) {
6912                         mFrameRateCategoryHighCount = 0;
6913                         mFrameRateCategoryHighHintCount = 0;
6914                         mFrameRateCategoryNormalCount = 0;
6915                         mFrameRateCategoryLowCount = 0;
6916                         mPreferredFrameRate = 0;
6917                         mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
6918                         updateFrameRateFromThreadedRendererViews();
6919                         setPreferredFrameRate(mPreferredFrameRate);
6920                         setPreferredFrameRateCategory(mPreferredFrameRateCategory);
6921                         mInvalidationIdleMessagePosted = false;
6922                     } else {
6923                         mInvalidationIdleMessagePosted = true;
6924                         mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
6925                                 IDLE_TIME_MILLIS - delta);
6926                     }
6927                     break;
6928                 }
6929                 case MSG_TOUCH_BOOST_TIMEOUT:
6930                     /**
6931                      * Lower the frame rate after the boosting period (FRAME_RATE_TOUCH_BOOST_TIME).
6932                      */
6933                     mIsFrameRateBoosting = false;
6934                     mIsTouchBoosting = false;
6935                     break;
6936                 case MSG_REFRESH_POINTER_ICON:
6937                     if (mPointerIconEvent == null) {
6938                         break;
6939                     }
6940                     updatePointerIcon(mPointerIconEvent);
6941                     break;
6942                 case MSG_FRAME_RATE_SETTING:
6943                     mPreferredFrameRate = 0;
6944                     mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
6945                     break;
6946             }
6947         }
6948     }
6949 
6950     final ViewRootHandler mHandler = new ViewRootHandler();
6951     final Executor mExecutor = (Runnable r) -> {
6952         mHandler.post(r);
6953     };
6954 
6955     /**
6956      * Something in the current window tells us we need to change the touch mode.  For
6957      * example, we are not in touch mode, and the user touches the screen.
6958      *
6959      * If the touch mode has changed, tell the window manager, and handle it locally.
6960      *
6961      * @param inTouchMode Whether we want to be in touch mode.
6962      * @return True if the touch mode changed and focus changed was changed as a result
6963      */
6964     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
ensureTouchMode(boolean inTouchMode)6965     boolean ensureTouchMode(boolean inTouchMode) {
6966         if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
6967                 + "touch mode is " + mAttachInfo.mInTouchMode);
6968         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
6969 
6970         // tell the window manager
6971         try {
6972             IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService();
6973             windowManager.setInTouchMode(inTouchMode, getDisplayId());
6974         } catch (RemoteException e) {
6975             throw new RuntimeException(e);
6976         }
6977 
6978         // handle the change
6979         return ensureTouchModeLocally(inTouchMode);
6980     }
6981 
6982     /**
6983      * Ensure that the touch mode for this window is set, and if it is changing,
6984      * take the appropriate action.
6985      * @param inTouchMode Whether we want to be in touch mode.
6986      * @return True if the touch mode changed and focus changed was changed as a result
6987      */
ensureTouchModeLocally(boolean inTouchMode)6988     private boolean ensureTouchModeLocally(boolean inTouchMode) {
6989         if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
6990                 + "touch mode is " + mAttachInfo.mInTouchMode);
6991 
6992         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
6993 
6994         mAttachInfo.mInTouchMode = inTouchMode;
6995         mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
6996 
6997         return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
6998     }
6999 
enterTouchMode()7000     private boolean enterTouchMode() {
7001         if (mView != null && mView.hasFocus()) {
7002             // note: not relying on mFocusedView here because this could
7003             // be when the window is first being added, and mFocused isn't
7004             // set yet.
7005             final View focused = mView.findFocus();
7006             if (focused != null && !focused.isFocusableInTouchMode()) {
7007                 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
7008                 if (ancestorToTakeFocus != null) {
7009                     // there is an ancestor that wants focus after its
7010                     // descendants that is focusable in touch mode.. give it
7011                     // focus
7012                     return ancestorToTakeFocus.requestFocus();
7013                 } else {
7014                     // There's nothing to focus. Clear and propagate through the
7015                     // hierarchy, but don't attempt to place new focus.
7016                     focused.clearFocusInternal(null, true, false);
7017                     return true;
7018                 }
7019             }
7020         }
7021         return false;
7022     }
7023 
7024     /**
7025      * Find an ancestor of focused that wants focus after its descendants and is
7026      * focusable in touch mode.
7027      * @param focused The currently focused view.
7028      * @return An appropriate view, or null if no such view exists.
7029      */
findAncestorToTakeFocusInTouchMode(View focused)7030     private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
7031         ViewParent parent = focused.getParent();
7032         while (parent instanceof ViewGroup) {
7033             final ViewGroup vgParent = (ViewGroup) parent;
7034             if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
7035                     && vgParent.isFocusableInTouchMode()) {
7036                 return vgParent;
7037             }
7038             if (vgParent.isRootNamespace()) {
7039                 return null;
7040             } else {
7041                 parent = vgParent.getParent();
7042             }
7043         }
7044         return null;
7045     }
7046 
leaveTouchMode()7047     private boolean leaveTouchMode() {
7048         if (mView != null) {
7049             if (mView.hasFocus()) {
7050                 View focusedView = mView.findFocus();
7051                 if (!(focusedView instanceof ViewGroup)) {
7052                     // some view has focus, let it keep it
7053                     return false;
7054                 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
7055                         ViewGroup.FOCUS_AFTER_DESCENDANTS) {
7056                     // some view group has focus, and doesn't prefer its children
7057                     // over itself for focus, so let them keep it.
7058                     return false;
7059                 }
7060             }
7061 
7062             // find the best view to give focus to in this brave new non-touch-mode
7063             // world
7064             return mView.restoreDefaultFocus();
7065         }
7066         return false;
7067     }
7068 
7069     /**
7070      * Base class for implementing a stage in the chain of responsibility
7071      * for processing input events.
7072      * <p>
7073      * Events are delivered to the stage by the {@link #deliver} method.  The stage
7074      * then has the choice of finishing the event or forwarding it to the next stage.
7075      * </p>
7076      */
7077     abstract class InputStage {
7078         private final InputStage mNext;
7079 
7080         protected static final int FORWARD = 0;
7081         protected static final int FINISH_HANDLED = 1;
7082         protected static final int FINISH_NOT_HANDLED = 2;
7083 
7084         private String mTracePrefix;
7085 
7086         /**
7087          * Creates an input stage.
7088          * @param next The next stage to which events should be forwarded.
7089          */
InputStage(InputStage next)7090         public InputStage(InputStage next) {
7091             mNext = next;
7092         }
7093 
7094         /**
7095          * Delivers an event to be processed.
7096          */
deliver(QueuedInputEvent q)7097         public final void deliver(QueuedInputEvent q) {
7098             if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
7099                 forward(q);
7100             } else if (shouldDropInputEvent(q)) {
7101                 finish(q, false);
7102             } else {
7103                 traceEvent(q, Trace.TRACE_TAG_VIEW);
7104                 final int result;
7105                 try {
7106                     result = onProcess(q);
7107                 } finally {
7108                     Trace.traceEnd(Trace.TRACE_TAG_VIEW);
7109                 }
7110                 apply(q, result);
7111             }
7112         }
7113 
7114         /**
7115          * Marks the input event as finished then forwards it to the next stage.
7116          */
finish(QueuedInputEvent q, boolean handled)7117         protected void finish(QueuedInputEvent q, boolean handled) {
7118             q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
7119             if (handled) {
7120                 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
7121             }
7122             forward(q);
7123         }
7124 
7125         /**
7126          * Forwards the event to the next stage.
7127          */
forward(QueuedInputEvent q)7128         protected void forward(QueuedInputEvent q) {
7129             onDeliverToNext(q);
7130         }
7131 
7132         /**
7133          * Applies a result code from {@link #onProcess} to the specified event.
7134          */
apply(QueuedInputEvent q, int result)7135         protected void apply(QueuedInputEvent q, int result) {
7136             if (result == FORWARD) {
7137                 forward(q);
7138             } else if (result == FINISH_HANDLED) {
7139                 finish(q, true);
7140             } else if (result == FINISH_NOT_HANDLED) {
7141                 finish(q, false);
7142             } else {
7143                 throw new IllegalArgumentException("Invalid result: " + result);
7144             }
7145         }
7146 
7147         /**
7148          * Called when an event is ready to be processed.
7149          * @return A result code indicating how the event was handled.
7150          */
onProcess(QueuedInputEvent q)7151         protected int onProcess(QueuedInputEvent q) {
7152             return FORWARD;
7153         }
7154 
7155         /**
7156          * Called when an event is being delivered to the next stage.
7157          */
onDeliverToNext(QueuedInputEvent q)7158         protected void onDeliverToNext(QueuedInputEvent q) {
7159             if (DEBUG_INPUT_STAGES) {
7160                 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
7161             }
7162             if (mNext != null) {
7163                 mNext.deliver(q);
7164             } else {
7165                 finishInputEvent(q);
7166             }
7167         }
7168 
onWindowFocusChanged(boolean hasWindowFocus)7169         protected void onWindowFocusChanged(boolean hasWindowFocus) {
7170             if (mNext != null) {
7171                 mNext.onWindowFocusChanged(hasWindowFocus);
7172             }
7173         }
7174 
onDetachedFromWindow()7175         protected void onDetachedFromWindow() {
7176             if (mNext != null) {
7177                 mNext.onDetachedFromWindow();
7178             }
7179         }
7180 
shouldDropInputEvent(QueuedInputEvent q)7181         protected boolean shouldDropInputEvent(QueuedInputEvent q) {
7182             if (mView == null || !mAdded) {
7183                 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
7184                 return true;
7185             }
7186 
7187             // Find a reason for dropping or canceling the event.
7188             final String reason;
7189             // The embedded window is focused, allow this VRI to handle back key.
7190             if (!mAttachInfo.mHasWindowFocus && !(mProcessingBackKey && isBack(q.mEvent))
7191                     && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
7192                     && !isAutofillUiShowing()) {
7193                 // This is a non-pointer event and the window doesn't currently have input focus
7194                 // This could be an event that came back from the previous stage
7195                 // but the window has lost focus or stopped in the meantime.
7196                 reason = "no window focus";
7197             } else if (mStopped) {
7198                 reason = "window is stopped";
7199             } else if (mIsAmbientMode
7200                     && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) {
7201                 reason = "non-button event in ambient mode";
7202             } else if (mPausedForTransition && !isBack(q.mEvent)) {
7203                 reason = "paused for transition";
7204             } else {
7205                 // Most common path: no reason to drop or cancel the event
7206                 return false;
7207             }
7208 
7209             if (isTerminalInputEvent(q.mEvent)) {
7210                 // Don't drop terminal input events, however mark them as canceled.
7211                 q.mEvent.cancel();
7212                 Slog.w(mTag, "Cancelling event (" + reason + "):" + q.mEvent);
7213                 return false;
7214             }
7215 
7216             // Drop non-terminal input events.
7217             Slog.w(mTag, "Dropping event (" + reason + "):" + q.mEvent);
7218             return true;
7219         }
7220 
dump(String prefix, PrintWriter writer)7221         void dump(String prefix, PrintWriter writer) {
7222             if (mNext != null) {
7223                 mNext.dump(prefix, writer);
7224             }
7225         }
7226 
isBack(InputEvent event)7227         boolean isBack(InputEvent event) {
7228             if (event instanceof KeyEvent) {
7229                 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
7230             } else {
7231                 return false;
7232             }
7233         }
7234 
traceEvent(QueuedInputEvent q, long traceTag)7235         private void traceEvent(QueuedInputEvent q, long traceTag) {
7236             if (!Trace.isTagEnabled(traceTag)) {
7237                 return;
7238             }
7239 
7240             if (mTracePrefix == null) {
7241                 mTracePrefix = getClass().getSimpleName();
7242             }
7243             Trace.traceBegin(traceTag, mTracePrefix + " id=0x"
7244                     + Integer.toHexString(q.mEvent.getId()));
7245         }
7246     }
7247 
7248     /**
7249      * Base class for implementing an input pipeline stage that supports
7250      * asynchronous and out-of-order processing of input events.
7251      * <p>
7252      * In addition to what a normal input stage can do, an asynchronous
7253      * input stage may also defer an input event that has been delivered to it
7254      * and finish or forward it later.
7255      * </p>
7256      */
7257     abstract class AsyncInputStage extends InputStage {
7258         private final String mTraceCounter;
7259 
7260         private QueuedInputEvent mQueueHead;
7261         private QueuedInputEvent mQueueTail;
7262         private int mQueueLength;
7263 
7264         protected static final int DEFER = 3;
7265 
7266         /**
7267          * Creates an asynchronous input stage.
7268          * @param next The next stage to which events should be forwarded.
7269          * @param traceCounter The name of a counter to record the size of
7270          * the queue of pending events.
7271          */
AsyncInputStage(InputStage next, String traceCounter)7272         public AsyncInputStage(InputStage next, String traceCounter) {
7273             super(next);
7274             mTraceCounter = traceCounter;
7275         }
7276 
7277         /**
7278          * Marks the event as deferred, which is to say that it will be handled
7279          * asynchronously.  The caller is responsible for calling {@link #forward}
7280          * or {@link #finish} later when it is done handling the event.
7281          */
defer(QueuedInputEvent q)7282         protected void defer(QueuedInputEvent q) {
7283             q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
7284             enqueue(q);
7285         }
7286 
7287         @Override
forward(QueuedInputEvent q)7288         protected void forward(QueuedInputEvent q) {
7289             // Clear the deferred flag.
7290             q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
7291 
7292             // Fast path if the queue is empty.
7293             QueuedInputEvent curr = mQueueHead;
7294             if (curr == null) {
7295                 super.forward(q);
7296                 return;
7297             }
7298 
7299             // Determine whether the event must be serialized behind any others
7300             // before it can be delivered to the next stage.  This is done because
7301             // deferred events might be handled out of order by the stage.
7302             final int deviceId = q.mEvent.getDeviceId();
7303             QueuedInputEvent prev = null;
7304             boolean blocked = false;
7305             while (curr != null && curr != q) {
7306                 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
7307                     blocked = true;
7308                 }
7309                 prev = curr;
7310                 curr = curr.mNext;
7311             }
7312 
7313             // If the event is blocked, then leave it in the queue to be delivered later.
7314             // Note that the event might not yet be in the queue if it was not previously
7315             // deferred so we will enqueue it if needed.
7316             if (blocked) {
7317                 if (curr == null) {
7318                     enqueue(q);
7319                 }
7320                 return;
7321             }
7322 
7323             // The event is not blocked.  Deliver it immediately.
7324             if (curr != null) {
7325                 curr = curr.mNext;
7326                 dequeue(q, prev);
7327             }
7328             super.forward(q);
7329 
7330             // Dequeuing this event may have unblocked successors.  Deliver them.
7331             while (curr != null) {
7332                 if (deviceId == curr.mEvent.getDeviceId()) {
7333                     if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
7334                         break;
7335                     }
7336                     QueuedInputEvent next = curr.mNext;
7337                     dequeue(curr, prev);
7338                     super.forward(curr);
7339                     curr = next;
7340                 } else {
7341                     prev = curr;
7342                     curr = curr.mNext;
7343                 }
7344             }
7345         }
7346 
7347         @Override
apply(QueuedInputEvent q, int result)7348         protected void apply(QueuedInputEvent q, int result) {
7349             if (result == DEFER) {
7350                 defer(q);
7351             } else {
7352                 super.apply(q, result);
7353             }
7354         }
7355 
enqueue(QueuedInputEvent q)7356         private void enqueue(QueuedInputEvent q) {
7357             if (mQueueTail == null) {
7358                 mQueueHead = q;
7359                 mQueueTail = q;
7360             } else {
7361                 mQueueTail.mNext = q;
7362                 mQueueTail = q;
7363             }
7364 
7365             mQueueLength += 1;
7366             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
7367         }
7368 
dequeue(QueuedInputEvent q, QueuedInputEvent prev)7369         private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
7370             if (prev == null) {
7371                 mQueueHead = q.mNext;
7372             } else {
7373                 prev.mNext = q.mNext;
7374             }
7375             if (mQueueTail == q) {
7376                 mQueueTail = prev;
7377             }
7378             q.mNext = null;
7379 
7380             mQueueLength -= 1;
7381             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
7382         }
7383 
7384         @Override
dump(String prefix, PrintWriter writer)7385         void dump(String prefix, PrintWriter writer) {
7386             writer.print(prefix);
7387             writer.print(getClass().getName());
7388             writer.print(": mQueueLength=");
7389             writer.println(mQueueLength);
7390 
7391             super.dump(prefix, writer);
7392         }
7393     }
7394 
7395     /**
7396      * Delivers pre-ime input events to a native activity.
7397      * Does not support pointer events.
7398      */
7399     final class NativePreImeInputStage extends AsyncInputStage
7400             implements InputQueue.FinishedInputEventCallback {
7401 
NativePreImeInputStage(InputStage next, String traceCounter)7402         public NativePreImeInputStage(InputStage next, String traceCounter) {
7403             super(next, traceCounter);
7404         }
7405 
7406         @Override
onProcess(QueuedInputEvent q)7407         protected int onProcess(QueuedInputEvent q) {
7408             if (q.mEvent instanceof KeyEvent) {
7409                 final KeyEvent keyEvent = (KeyEvent) q.mEvent;
7410 
7411                 // If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the
7412                 // view tree or IME, and invoke the appropriate {@link OnBackInvokedCallback}.
7413                 if (isBack(keyEvent)) {
7414                     if (mWindowlessBackKeyCallback != null) {
7415                         if (mWindowlessBackKeyCallback.test(keyEvent)) {
7416                             return keyEvent.getAction() == KeyEvent.ACTION_UP
7417                                     && !keyEvent.isCanceled()
7418                                     ? FINISH_HANDLED : FINISH_NOT_HANDLED;
7419                         } else {
7420                             // Unable to forward the back key to host, forward to next stage.
7421                             return FORWARD;
7422                         }
7423                     } else if (mContext != null
7424                             && mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
7425                         return doOnBackKeyEvent(keyEvent);
7426                     }
7427                 }
7428 
7429                 if (mInputQueue != null) {
7430                     mInputQueue.sendInputEvent(q.mEvent, q, true, this);
7431                     return DEFER;
7432                 }
7433             }
7434             return FORWARD;
7435         }
7436 
doOnBackKeyEvent(KeyEvent keyEvent)7437         private int doOnBackKeyEvent(KeyEvent keyEvent) {
7438             WindowOnBackInvokedDispatcher dispatcher = getOnBackInvokedDispatcher();
7439             OnBackInvokedCallback topCallback = dispatcher.getTopCallback();
7440             if (dispatcher.isBackGestureInProgress()) {
7441                 return FINISH_NOT_HANDLED;
7442             }
7443             if (topCallback instanceof OnBackAnimationCallback
7444                     && !(topCallback instanceof ImeBackAnimationController)) {
7445                 final OnBackAnimationCallback animationCallback =
7446                         (OnBackAnimationCallback) topCallback;
7447                 switch (keyEvent.getAction()) {
7448                     case KeyEvent.ACTION_DOWN:
7449                         // ACTION_DOWN is emitted twice: once when the user presses the button,
7450                         // and again a few milliseconds later.
7451                         // Based on the result of `keyEvent.getRepeatCount()` we have:
7452                         // - 0 means the button was pressed.
7453                         // - 1 means the button continues to be pressed (long press).
7454                         if (keyEvent.getRepeatCount() == 0) {
7455                             animationCallback.onBackStarted(
7456                                     new BackEvent(0, 0, 0f, BackEvent.EDGE_LEFT));
7457                         }
7458                         break;
7459                     case KeyEvent.ACTION_UP:
7460                         if (keyEvent.isCanceled()) {
7461                             animationCallback.onBackCancelled();
7462                         } else {
7463                             topCallback.onBackInvoked();
7464                             return FINISH_HANDLED;
7465                         }
7466                         break;
7467                 }
7468             } else if (topCallback != null) {
7469                 if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
7470                     if (!keyEvent.isCanceled()) {
7471                         topCallback.onBackInvoked();
7472                         return FINISH_HANDLED;
7473                     } else {
7474                         Log.d(mTag, "Skip onBackInvoked(), reason: keyEvent.isCanceled=true");
7475                     }
7476                 }
7477             }
7478 
7479             return FINISH_NOT_HANDLED;
7480         }
7481 
7482         @Override
onFinishedInputEvent(Object token, boolean handled)7483         public void onFinishedInputEvent(Object token, boolean handled) {
7484             QueuedInputEvent q = (QueuedInputEvent)token;
7485             if (handled) {
7486                 finish(q, true);
7487                 return;
7488             }
7489             forward(q);
7490         }
7491     }
7492 
7493     /**
7494      * Delivers pre-ime input events to the view hierarchy.
7495      * Does not support pointer events.
7496      */
7497     final class ViewPreImeInputStage extends InputStage {
ViewPreImeInputStage(InputStage next)7498         public ViewPreImeInputStage(InputStage next) {
7499             super(next);
7500         }
7501 
7502         @Override
onProcess(QueuedInputEvent q)7503         protected int onProcess(QueuedInputEvent q) {
7504             if (q.mEvent instanceof KeyEvent) {
7505                 return processKeyEvent(q);
7506             }
7507             return FORWARD;
7508         }
7509 
processKeyEvent(QueuedInputEvent q)7510         private int processKeyEvent(QueuedInputEvent q) {
7511             final KeyEvent event = (KeyEvent)q.mEvent;
7512             if (mView.dispatchKeyEventPreIme(event)) {
7513                 return FINISH_HANDLED;
7514             }
7515             return FORWARD;
7516         }
7517     }
7518 
7519     /**
7520      * Delivers input events to the ime.
7521      * Does not support pointer events.
7522      */
7523     final class ImeInputStage extends AsyncInputStage
7524             implements InputMethodManager.FinishedInputEventCallback {
ImeInputStage(InputStage next, String traceCounter)7525         public ImeInputStage(InputStage next, String traceCounter) {
7526             super(next, traceCounter);
7527         }
7528 
7529         @Override
onProcess(QueuedInputEvent q)7530         protected int onProcess(QueuedInputEvent q) {
7531             final int result = mImeFocusController.onProcessImeInputStage(
7532                     q, q.mEvent, mWindowAttributes, this);
7533             switch (result) {
7534                 case InputMethodManager.DISPATCH_IN_PROGRESS:
7535                     // callback will be invoked later
7536                     return DEFER;
7537                 case InputMethodManager.DISPATCH_NOT_HANDLED:
7538                     // The IME could not handle it, so skip along to the next InputStage
7539                     return FORWARD;
7540                 case InputMethodManager.DISPATCH_HANDLED:
7541                     return FINISH_HANDLED;
7542                 default:
7543                     throw new IllegalStateException("Unexpected result=" + result);
7544             }
7545         }
7546 
7547         @Override
onFinishedInputEvent(Object token, boolean handled)7548         public void onFinishedInputEvent(Object token, boolean handled) {
7549             QueuedInputEvent q = (QueuedInputEvent)token;
7550             if (handled) {
7551                 finish(q, true);
7552                 return;
7553             }
7554             forward(q);
7555         }
7556     }
7557 
7558     /**
7559      * Performs early processing of post-ime input events.
7560      */
7561     final class EarlyPostImeInputStage extends InputStage {
EarlyPostImeInputStage(InputStage next)7562         public EarlyPostImeInputStage(InputStage next) {
7563             super(next);
7564         }
7565 
7566         @Override
onProcess(QueuedInputEvent q)7567         protected int onProcess(QueuedInputEvent q) {
7568             if (q.mEvent instanceof KeyEvent) {
7569                 return processKeyEvent(q);
7570             } else if (q.mEvent instanceof MotionEvent) {
7571                 return processMotionEvent(q);
7572             }
7573             return FORWARD;
7574         }
7575 
processKeyEvent(QueuedInputEvent q)7576         private int processKeyEvent(QueuedInputEvent q) {
7577             final KeyEvent event = (KeyEvent)q.mEvent;
7578 
7579             if (mAttachInfo.mTooltipHost != null) {
7580                 mAttachInfo.mTooltipHost.handleTooltipKey(event);
7581             }
7582 
7583             // If the key's purpose is to exit touch mode then we consume it
7584             // and consider it handled.
7585             if (checkForLeavingTouchModeAndConsume(event)) {
7586                 return FINISH_HANDLED;
7587             }
7588 
7589             // Make sure the fallback event policy sees all keys that will be
7590             // delivered to the view hierarchy.
7591             mFallbackEventHandler.preDispatchKeyEvent(event);
7592 
7593             // Reset last tracked MotionEvent click toolType.
7594             if (event.getAction() == KeyEvent.ACTION_DOWN) {
7595                 mLastClickToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
7596             }
7597 
7598             return FORWARD;
7599         }
7600 
processMotionEvent(QueuedInputEvent q)7601         private int processMotionEvent(QueuedInputEvent q) {
7602             final MotionEvent event = (MotionEvent) q.mEvent;
7603 
7604             if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
7605                 return processPointerEvent(q);
7606             }
7607 
7608             // If the motion event is from an absolute position device, exit touch mode
7609             final int action = event.getActionMasked();
7610             if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
7611                 if (event.isFromSource(InputDevice.SOURCE_CLASS_POSITION)) {
7612                     ensureTouchMode(false);
7613                 }
7614             }
7615             return FORWARD;
7616         }
7617 
processPointerEvent(QueuedInputEvent q)7618         private int processPointerEvent(QueuedInputEvent q) {
7619             final MotionEvent event = (MotionEvent)q.mEvent;
7620 
7621             // Translate the pointer event for compatibility, if needed.
7622             if (mTranslator != null) {
7623                 mTranslator.translateEventInScreenToAppWindow(event);
7624             }
7625 
7626             // Enter touch mode on down or scroll from any type of a device.
7627             final int action = event.getAction();
7628             if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
7629                 ensureTouchMode(true);
7630             }
7631 
7632             if (action == MotionEvent.ACTION_DOWN) {
7633                 // Upon motion event within app window, close autofill ui.
7634                 AutofillManager afm = getAutofillManager();
7635                 if (afm != null) {
7636                     afm.requestHideFillUi();
7637                 }
7638             }
7639 
7640             if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
7641                 mAttachInfo.mTooltipHost.hideTooltip();
7642             }
7643 
7644             // Offset the scroll position.
7645             if (mCurScrollY != 0) {
7646                 event.offsetLocation(0, mCurScrollY);
7647             }
7648 
7649             if (event.isTouchEvent()) {
7650                 // Remember the touch position for possible drag-initiation.
7651                 mLastTouchPoint.x = event.getRawX();
7652                 mLastTouchPoint.y = event.getRawY();
7653                 mLastTouchSource = event.getSource();
7654                 mLastTouchDeviceId = event.getDeviceId();
7655                 mLastTouchPointerId = event.getPointerId(0);
7656 
7657                 // Register last ACTION_UP. This will be propagated to IME.
7658                 if (event.getActionMasked() == MotionEvent.ACTION_UP) {
7659                     mLastClickToolType = event.getToolType(event.getActionIndex());
7660                 }
7661             }
7662             return FORWARD;
7663         }
7664     }
7665 
7666     /**
7667      * Delivers post-ime input events to a native activity.
7668      */
7669     final class NativePostImeInputStage extends AsyncInputStage
7670             implements InputQueue.FinishedInputEventCallback {
NativePostImeInputStage(InputStage next, String traceCounter)7671         public NativePostImeInputStage(InputStage next, String traceCounter) {
7672             super(next, traceCounter);
7673         }
7674 
7675         @Override
onProcess(QueuedInputEvent q)7676         protected int onProcess(QueuedInputEvent q) {
7677             if (mInputQueue != null) {
7678                 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
7679                 return DEFER;
7680             }
7681             return FORWARD;
7682         }
7683 
7684         @Override
onFinishedInputEvent(Object token, boolean handled)7685         public void onFinishedInputEvent(Object token, boolean handled) {
7686             QueuedInputEvent q = (QueuedInputEvent)token;
7687             if (handled) {
7688                 finish(q, true);
7689                 return;
7690             }
7691             forward(q);
7692         }
7693     }
7694 
7695     /**
7696      * Delivers post-ime input events to the view hierarchy.
7697      */
7698     final class ViewPostImeInputStage extends InputStage {
ViewPostImeInputStage(InputStage next)7699         public ViewPostImeInputStage(InputStage next) {
7700             super(next);
7701         }
7702 
7703         @Override
onProcess(QueuedInputEvent q)7704         protected int onProcess(QueuedInputEvent q) {
7705             if (q.mEvent instanceof KeyEvent) {
7706                 return processKeyEvent(q);
7707             } else {
7708                 final int source = q.mEvent.getSource();
7709                 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
7710                     return processPointerEvent(q);
7711                 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
7712                     return processTrackballEvent(q);
7713                 } else {
7714                     return processGenericMotionEvent(q);
7715                 }
7716             }
7717         }
7718 
7719         @Override
onDeliverToNext(QueuedInputEvent q)7720         protected void onDeliverToNext(QueuedInputEvent q) {
7721             if (mUnbufferedInputDispatch
7722                     && q.mEvent instanceof MotionEvent
7723                     && ((MotionEvent)q.mEvent).isTouchEvent()
7724                     && isTerminalInputEvent(q.mEvent)) {
7725                 mUnbufferedInputDispatch = false;
7726                 scheduleConsumeBatchedInput();
7727             }
7728             super.onDeliverToNext(q);
7729         }
7730 
performFocusNavigation(KeyEvent event)7731         private boolean performFocusNavigation(KeyEvent event) {
7732             @FocusDirection int direction = 0;
7733             switch (event.getKeyCode()) {
7734                 case KeyEvent.KEYCODE_DPAD_LEFT:
7735                     if (event.hasNoModifiers()) {
7736                         direction = View.FOCUS_LEFT;
7737                     }
7738                     break;
7739                 case KeyEvent.KEYCODE_DPAD_RIGHT:
7740                     if (event.hasNoModifiers()) {
7741                         direction = View.FOCUS_RIGHT;
7742                     }
7743                     break;
7744                 case KeyEvent.KEYCODE_DPAD_UP:
7745                     if (event.hasNoModifiers()) {
7746                         direction = View.FOCUS_UP;
7747                     }
7748                     break;
7749                 case KeyEvent.KEYCODE_DPAD_DOWN:
7750                     if (event.hasNoModifiers()) {
7751                         direction = View.FOCUS_DOWN;
7752                     }
7753                     break;
7754                 case KeyEvent.KEYCODE_TAB:
7755                     if (event.hasNoModifiers()) {
7756                         direction = View.FOCUS_FORWARD;
7757                     } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
7758                         direction = View.FOCUS_BACKWARD;
7759                     }
7760                     break;
7761             }
7762             if (direction != 0) {
7763                 View focused = mView.findFocus();
7764                 if (focused != null) {
7765                     mAttachInfo.mNextFocusLooped = false;
7766                     View v = focused.focusSearch(direction);
7767                     if (v != null && v != focused) {
7768                         if (mAttachInfo.mNextFocusLooped) {
7769                             // The next focus is looped. Let's try to move the focus to the adjacent
7770                             // window. Note: we still need to move the focus in this window
7771                             // regardless of what moveFocusToAdjacentWindow returns, so the focus
7772                             // can be looped back from the focus in the adjacent window to next
7773                             // focus of this window.
7774                             moveFocusToAdjacentWindow(direction);
7775                         }
7776 
7777                         // do the math the get the interesting rect
7778                         // of previous focused into the coord system of
7779                         // newly focused view
7780                         focused.getFocusedRect(mTempRect);
7781                         if (mView instanceof ViewGroup) {
7782                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
7783                                     focused, mTempRect);
7784                             ((ViewGroup) mView).offsetRectIntoDescendantCoords(
7785                                     v, mTempRect);
7786                         }
7787                         if (v.requestFocus(direction, mTempRect)) {
7788                             boolean isFastScrolling = event.getRepeatCount() > 0;
7789                             playSoundEffect(
7790                                     SoundEffectConstants.getConstantForFocusDirection(direction,
7791                                             isFastScrolling));
7792                             return true;
7793                         }
7794                     } else if (moveFocusToAdjacentWindow(direction)) {
7795                         return true;
7796                     }
7797 
7798                     // Give the focused view a last chance to handle the dpad key.
7799                     if (mView.dispatchUnhandledMove(focused, direction)) {
7800                         return true;
7801                     }
7802                 } else {
7803                     if (mView.restoreDefaultFocus()) {
7804                         return true;
7805                     } else if (moveFocusToAdjacentWindow(direction)) {
7806                         return true;
7807                     }
7808                 }
7809             }
7810             return false;
7811         }
7812 
moveFocusToAdjacentWindow(@ocusDirection int direction)7813         private boolean moveFocusToAdjacentWindow(@FocusDirection int direction) {
7814             if (getConfiguration().windowConfiguration.getWindowingMode()
7815                     != WINDOWING_MODE_MULTI_WINDOW) {
7816                 return false;
7817             }
7818             try {
7819                 return mWindowSession.moveFocusToAdjacentWindow(mWindow, direction);
7820             } catch (RemoteException e) {
7821                 return false;
7822             }
7823         }
7824 
performKeyboardGroupNavigation(int direction)7825         private boolean performKeyboardGroupNavigation(int direction) {
7826             final View focused = mView.findFocus();
7827             if (focused == null && mView.restoreDefaultFocus()) {
7828                 return true;
7829             }
7830             View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction)
7831                     : focused.keyboardNavigationClusterSearch(null, direction);
7832 
7833             // Since requestFocus only takes "real" focus directions (and therefore also
7834             // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN.
7835             int realDirection = direction;
7836             if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
7837                 realDirection = View.FOCUS_DOWN;
7838             }
7839 
7840             if (cluster != null && cluster.isRootNamespace()) {
7841                 // the default cluster. Try to find a non-clustered view to focus.
7842                 if (cluster.restoreFocusNotInCluster()) {
7843                     playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
7844                     return true;
7845                 }
7846                 // otherwise skip to next actual cluster
7847                 cluster = keyboardNavigationClusterSearch(null, direction);
7848             }
7849 
7850             if (cluster != null && cluster.restoreFocusInCluster(realDirection)) {
7851                 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
7852                 return true;
7853             }
7854 
7855             return false;
7856         }
7857 
processKeyEvent(QueuedInputEvent q)7858         private int processKeyEvent(QueuedInputEvent q) {
7859             final KeyEvent event = (KeyEvent)q.mEvent;
7860 
7861             if (mUnhandledKeyManager.preViewDispatch(event)) {
7862                 return FINISH_HANDLED;
7863             }
7864 
7865             // Deliver the key to the view hierarchy.
7866             if (mView.dispatchKeyEvent(event)) {
7867                 return FINISH_HANDLED;
7868             }
7869 
7870             if (shouldDropInputEvent(q)) {
7871                 return FINISH_NOT_HANDLED;
7872             }
7873 
7874             // This dispatch is for windows that don't have a Window.Callback. Otherwise,
7875             // the Window.Callback usually will have already called this (see
7876             // DecorView.superDispatchKeyEvent) leaving this call a no-op.
7877             if (mUnhandledKeyManager.dispatch(mView, event)) {
7878                 return FINISH_HANDLED;
7879             }
7880 
7881             int groupNavigationDirection = 0;
7882 
7883             if (event.getAction() == KeyEvent.ACTION_DOWN
7884                     && event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
7885                 if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_CTRL_ON)) {
7886                     groupNavigationDirection = View.FOCUS_FORWARD;
7887                 } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),
7888                         KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) {
7889                     groupNavigationDirection = View.FOCUS_BACKWARD;
7890                 }
7891             }
7892 
7893             // If a modifier is held, try to interpret the key as a shortcut.
7894             if (event.getAction() == KeyEvent.ACTION_DOWN
7895                     && !KeyEvent.metaStateHasNoModifiers(event.getMetaState())
7896                     && event.getRepeatCount() == 0
7897                     && !KeyEvent.isModifierKey(event.getKeyCode())
7898                     && groupNavigationDirection == 0) {
7899                 if (mView.dispatchKeyShortcutEvent(event)) {
7900                     return FINISH_HANDLED;
7901                 }
7902                 if (shouldDropInputEvent(q)) {
7903                     return FINISH_NOT_HANDLED;
7904                 }
7905             }
7906 
7907             // Apply the fallback event policy.
7908             if (mFallbackEventHandler.dispatchKeyEvent(event)) {
7909                 return FINISH_HANDLED;
7910             }
7911             if (shouldDropInputEvent(q)) {
7912                 return FINISH_NOT_HANDLED;
7913             }
7914 
7915             // Handle automatic focus changes.
7916             if (event.getAction() == KeyEvent.ACTION_DOWN) {
7917                 if (groupNavigationDirection != 0) {
7918                     if (performKeyboardGroupNavigation(groupNavigationDirection)) {
7919                         return FINISH_HANDLED;
7920                     }
7921                 } else {
7922                     if (performFocusNavigation(event)) {
7923                         return FINISH_HANDLED;
7924                     }
7925                 }
7926             }
7927             return FORWARD;
7928         }
7929 
processPointerEvent(QueuedInputEvent q)7930         private int processPointerEvent(QueuedInputEvent q) {
7931             final MotionEvent event = (MotionEvent)q.mEvent;
7932             final int action = event.getAction();
7933             boolean handled = false;
7934             if (!disableHandwritingInitiatorForIme()
7935                     || mWindowAttributes.type != TYPE_INPUT_METHOD) {
7936                 handled = mHandwritingInitiator.onTouchEvent(event);
7937             }
7938             if (handled) {
7939                 // If handwriting is started, toolkit doesn't receive ACTION_UP.
7940                 mLastClickToolType = event.getToolType(event.getActionIndex());
7941             }
7942 
7943             mAttachInfo.mUnbufferedDispatchRequested = false;
7944             mAttachInfo.mHandlingPointerEvent = true;
7945             // If the event was fully handled by the handwriting initiator, then don't dispatch it
7946             // to the view tree.
7947             handled = handled || mView.dispatchPointerEvent(event);
7948             maybeUpdatePointerIcon(event);
7949             maybeUpdateTooltip(event);
7950             mAttachInfo.mHandlingPointerEvent = false;
7951             if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
7952                 mUnbufferedInputDispatch = true;
7953                 if (mConsumeBatchedInputScheduled) {
7954                     scheduleConsumeBatchedInputImmediately();
7955                 }
7956             }
7957 
7958             // For the variable refresh rate project
7959             if (handled && shouldTouchBoost(action & MotionEvent.ACTION_MASK,
7960                     mWindowAttributes.type)) {
7961                 // set the frame rate to the maximum value.
7962                 mIsTouchBoosting = true;
7963                 setPreferredFrameRateCategory(mLastPreferredFrameRateCategory);
7964             }
7965             /**
7966              * We want to lower the refresh rate when MotionEvent.ACTION_UP,
7967              * MotionEvent.ACTION_CANCEL is detected.
7968              * Not using ACTION_MOVE to avoid checking and sending messages too frequently.
7969              */
7970             if (mIsTouchBoosting && (action == MotionEvent.ACTION_UP
7971                     || action == MotionEvent.ACTION_CANCEL)) {
7972                 mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT);
7973                 mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT,
7974                         FRAME_RATE_TOUCH_BOOST_TIME);
7975             }
7976             return handled ? FINISH_HANDLED : FORWARD;
7977         }
7978 
maybeUpdatePointerIcon(MotionEvent event)7979         private void maybeUpdatePointerIcon(MotionEvent event) {
7980             if (event.getPointerCount() != 1) {
7981                 return;
7982             }
7983             final int action = event.getActionMasked();
7984             final boolean needsStylusPointerIcon = event.isStylusPointer()
7985                     && event.isHoverEvent()
7986                     && mIsStylusPointerIconEnabled;
7987             if (!needsStylusPointerIcon && !event.isFromSource(InputDevice.SOURCE_MOUSE)) {
7988                 return;
7989             }
7990 
7991             if (action == MotionEvent.ACTION_HOVER_ENTER
7992                     || action == MotionEvent.ACTION_HOVER_EXIT) {
7993                 // Other apps or the window manager may change the icon type outside of
7994                 // this app, therefore the icon type has to be reset on enter/exit event.
7995                 mResolvedPointerIcon = null;
7996             }
7997 
7998             if (action != MotionEvent.ACTION_HOVER_EXIT) {
7999                 // Resolve the pointer icon
8000                 if (!updatePointerIcon(event) && action == MotionEvent.ACTION_HOVER_MOVE) {
8001                     mResolvedPointerIcon = null;
8002                 }
8003             }
8004 
8005             // Keep track of the newest event used to resolve the pointer icon.
8006             switch (action) {
8007                 case MotionEvent.ACTION_HOVER_EXIT:
8008                 case MotionEvent.ACTION_UP:
8009                 case MotionEvent.ACTION_POINTER_UP:
8010                 case MotionEvent.ACTION_CANCEL:
8011                     if (mPointerIconEvent != null) {
8012                         mPointerIconEvent.recycle();
8013                     }
8014                     mPointerIconEvent = null;
8015                     break;
8016                 default:
8017                     mPointerIconEvent = MotionEvent.obtain(event);
8018                     break;
8019             }
8020         }
8021 
processTrackballEvent(QueuedInputEvent q)8022         private int processTrackballEvent(QueuedInputEvent q) {
8023             final MotionEvent event = (MotionEvent)q.mEvent;
8024 
8025             if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
8026                 if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) {
8027                     return FINISH_HANDLED;
8028                 }
8029             }
8030 
8031             if (mView.dispatchTrackballEvent(event)) {
8032                 return FINISH_HANDLED;
8033             }
8034             return FORWARD;
8035         }
8036 
processGenericMotionEvent(QueuedInputEvent q)8037         private int processGenericMotionEvent(QueuedInputEvent q) {
8038             final MotionEvent event = (MotionEvent)q.mEvent;
8039 
8040             if (event.isFromSource(InputDevice.SOURCE_TOUCHPAD)) {
8041                 if (hasPointerCapture() && mView.dispatchCapturedPointerEvent(event)) {
8042                     return FINISH_HANDLED;
8043                 }
8044             }
8045 
8046             // Deliver the event to the view.
8047             if (mView.dispatchGenericMotionEvent(event)) {
8048                 return FINISH_HANDLED;
8049             }
8050             return FORWARD;
8051         }
8052     }
8053 
8054     /**
8055      * Returns whether this view is currently handling a pointer event.
8056      *
8057      * @hide
8058      */
isHandlingPointerEvent()8059     public boolean isHandlingPointerEvent() {
8060         return mAttachInfo.mHandlingPointerEvent;
8061     }
8062 
8063 
8064     /**
8065      * If there is pointer that is showing a PointerIcon in this window, refresh the icon for that
8066      * pointer. This will resolve the PointerIcon through the view hierarchy.
8067      */
refreshPointerIcon()8068     public void refreshPointerIcon() {
8069         mHandler.removeMessages(MSG_REFRESH_POINTER_ICON);
8070         mHandler.sendEmptyMessage(MSG_REFRESH_POINTER_ICON);
8071     }
8072 
updatePointerIcon(MotionEvent event)8073     private boolean updatePointerIcon(MotionEvent event) {
8074         final int pointerIndex = 0;
8075         final float x = event.getX(pointerIndex);
8076         final float y = event.getY(pointerIndex);
8077         if (mView == null) {
8078             // E.g. click outside a popup to dismiss it
8079             Slog.d(mTag, "updatePointerIcon called after view was removed");
8080             return false;
8081         }
8082         if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
8083             // E.g. when moving window divider with mouse
8084             Slog.d(mTag, "updatePointerIcon called with position out of bounds");
8085             return false;
8086         }
8087 
8088         PointerIcon pointerIcon = null;
8089         if (event.isStylusPointer() && mIsStylusPointerIconEnabled
8090                 && (!disableHandwritingInitiatorForIme()
8091                         || mWindowAttributes.type != TYPE_INPUT_METHOD)) {
8092             pointerIcon = mHandwritingInitiator.onResolvePointerIcon(mContext, event);
8093         }
8094         if (pointerIcon == null) {
8095             pointerIcon = mView.onResolvePointerIcon(event, pointerIndex);
8096         }
8097         if (pointerIcon == null) {
8098             pointerIcon = PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_NOT_SPECIFIED);
8099         }
8100         if (Objects.equals(mResolvedPointerIcon, pointerIcon)) {
8101             return true;
8102         }
8103         mResolvedPointerIcon = pointerIcon;
8104 
8105         InputManagerGlobal.getInstance()
8106                 .setPointerIcon(pointerIcon, event.getDisplayId(),
8107                         event.getDeviceId(), event.getPointerId(0), getInputToken());
8108         return true;
8109     }
8110 
maybeUpdateTooltip(MotionEvent event)8111     private void maybeUpdateTooltip(MotionEvent event) {
8112         if (event.getPointerCount() != 1) {
8113             return;
8114         }
8115         final int action = event.getActionMasked();
8116         if (action != MotionEvent.ACTION_HOVER_ENTER
8117                 && action != MotionEvent.ACTION_HOVER_MOVE
8118                 && action != MotionEvent.ACTION_HOVER_EXIT) {
8119             return;
8120         }
8121         if (mAccessibilityManager.isEnabled()
8122                 && mAccessibilityManager.isTouchExplorationEnabled()) {
8123             return;
8124         }
8125         if (mView == null) {
8126             Slog.d(mTag, "maybeUpdateTooltip called after view was removed");
8127             return;
8128         }
8129         mView.dispatchTooltipHoverEvent(event);
8130     }
8131 
8132     @Nullable
getFocusedViewOrNull()8133     private View getFocusedViewOrNull() {
8134         return mView != null ? mView.findFocus() : null;
8135     }
8136 
8137     /**
8138      * Performs synthesis of new input events from unhandled input events.
8139      */
8140     final class SyntheticInputStage extends InputStage {
8141         private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
8142         private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
8143         private final SyntheticTouchNavigationHandler mTouchNavigation =
8144                 new SyntheticTouchNavigationHandler();
8145         private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
8146 
SyntheticInputStage()8147         public SyntheticInputStage() {
8148             super(null);
8149         }
8150 
8151         @Override
onProcess(QueuedInputEvent q)8152         protected int onProcess(QueuedInputEvent q) {
8153             q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
8154             if (q.mEvent instanceof MotionEvent) {
8155                 final MotionEvent event = (MotionEvent)q.mEvent;
8156                 final int source = event.getSource();
8157                 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
8158                     // Do not synthesize events for relative mouse movement. If apps opt into
8159                     // relative mouse movement they must be prepared to handle the events.
8160                     if (!event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
8161                         mTrackball.process(event);
8162                     }
8163                     return FINISH_HANDLED;
8164                 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
8165                     mJoystick.process(event);
8166                     return FINISH_HANDLED;
8167                 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
8168                         == InputDevice.SOURCE_TOUCH_NAVIGATION) {
8169                     mTouchNavigation.process(event);
8170                     return FINISH_HANDLED;
8171                 }
8172             } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
8173                 mKeyboard.process((KeyEvent)q.mEvent);
8174                 return FINISH_HANDLED;
8175             }
8176 
8177             return FORWARD;
8178         }
8179 
8180         @Override
onDeliverToNext(QueuedInputEvent q)8181         protected void onDeliverToNext(QueuedInputEvent q) {
8182             if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
8183                 // Cancel related synthetic events if any prior stage has handled the event.
8184                 if (q.mEvent instanceof MotionEvent) {
8185                     final MotionEvent event = (MotionEvent)q.mEvent;
8186                     final int source = event.getSource();
8187                     if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
8188                         mTrackball.cancel();
8189                     } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
8190                         mJoystick.cancel();
8191                     } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
8192                             == InputDevice.SOURCE_TOUCH_NAVIGATION) {
8193                         // Touch navigation events cannot be cancelled since they are dispatched
8194                         // immediately.
8195                     }
8196                 }
8197             }
8198             super.onDeliverToNext(q);
8199         }
8200 
8201         @Override
onWindowFocusChanged(boolean hasWindowFocus)8202         protected void onWindowFocusChanged(boolean hasWindowFocus) {
8203             if (!hasWindowFocus) {
8204                 mJoystick.cancel();
8205             }
8206         }
8207 
8208         @Override
onDetachedFromWindow()8209         protected void onDetachedFromWindow() {
8210             mJoystick.cancel();
8211         }
8212     }
8213 
8214     /**
8215      * Creates dpad events from unhandled trackball movements.
8216      */
8217     final class SyntheticTrackballHandler {
8218         private final TrackballAxis mX = new TrackballAxis();
8219         private final TrackballAxis mY = new TrackballAxis();
8220         private long mLastTime;
8221 
process(MotionEvent event)8222         public void process(MotionEvent event) {
8223             // Translate the trackball event into DPAD keys and try to deliver those.
8224             long curTime = SystemClock.uptimeMillis();
8225             if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
8226                 // It has been too long since the last movement,
8227                 // so restart at the beginning.
8228                 mX.reset(0);
8229                 mY.reset(0);
8230                 mLastTime = curTime;
8231             }
8232 
8233             final int action = event.getAction();
8234             final int metaState = event.getMetaState();
8235             switch (action) {
8236                 case MotionEvent.ACTION_DOWN:
8237                     mX.reset(2);
8238                     mY.reset(2);
8239                     enqueueInputEvent(new KeyEvent(curTime, curTime,
8240                             KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
8241                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
8242                             InputDevice.SOURCE_KEYBOARD));
8243                     break;
8244                 case MotionEvent.ACTION_UP:
8245                     mX.reset(2);
8246                     mY.reset(2);
8247                     enqueueInputEvent(new KeyEvent(curTime, curTime,
8248                             KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
8249                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
8250                             InputDevice.SOURCE_KEYBOARD));
8251                     break;
8252             }
8253 
8254             if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
8255                     + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
8256                     + " move=" + event.getX()
8257                     + " / Y=" + mY.position + " step="
8258                     + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
8259                     + " move=" + event.getY());
8260             final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
8261             final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
8262 
8263             // Generate DPAD events based on the trackball movement.
8264             // We pick the axis that has moved the most as the direction of
8265             // the DPAD.  When we generate DPAD events for one axis, then the
8266             // other axis is reset -- we don't want to perform DPAD jumps due
8267             // to slight movements in the trackball when making major movements
8268             // along the other axis.
8269             int keycode = 0;
8270             int movement = 0;
8271             float accel = 1;
8272             if (xOff > yOff) {
8273                 movement = mX.generate();
8274                 if (movement != 0) {
8275                     keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
8276                             : KeyEvent.KEYCODE_DPAD_LEFT;
8277                     accel = mX.acceleration;
8278                     mY.reset(2);
8279                 }
8280             } else if (yOff > 0) {
8281                 movement = mY.generate();
8282                 if (movement != 0) {
8283                     keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
8284                             : KeyEvent.KEYCODE_DPAD_UP;
8285                     accel = mY.acceleration;
8286                     mX.reset(2);
8287                 }
8288             }
8289 
8290             if (keycode != 0) {
8291                 if (movement < 0) movement = -movement;
8292                 int accelMovement = (int)(movement * accel);
8293                 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
8294                         + " accelMovement=" + accelMovement
8295                         + " accel=" + accel);
8296                 if (accelMovement > movement) {
8297                     if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
8298                             + keycode);
8299                     movement--;
8300                     int repeatCount = accelMovement - movement;
8301                     enqueueInputEvent(new KeyEvent(curTime, curTime,
8302                             KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
8303                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
8304                             InputDevice.SOURCE_KEYBOARD));
8305                 }
8306                 while (movement > 0) {
8307                     if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
8308                             + keycode);
8309                     movement--;
8310                     curTime = SystemClock.uptimeMillis();
8311                     enqueueInputEvent(new KeyEvent(curTime, curTime,
8312                             KeyEvent.ACTION_DOWN, keycode, 0, metaState,
8313                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
8314                             InputDevice.SOURCE_KEYBOARD));
8315                     enqueueInputEvent(new KeyEvent(curTime, curTime,
8316                             KeyEvent.ACTION_UP, keycode, 0, metaState,
8317                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
8318                             InputDevice.SOURCE_KEYBOARD));
8319                 }
8320                 mLastTime = curTime;
8321             }
8322         }
8323 
cancel()8324         public void cancel() {
8325             mLastTime = Integer.MIN_VALUE;
8326 
8327             // If we reach this, we consumed a trackball event.
8328             // Because we will not translate the trackball event into a key event,
8329             // touch mode will not exit, so we exit touch mode here.
8330             if (mView != null && mAdded) {
8331                 ensureTouchMode(false);
8332             }
8333         }
8334     }
8335 
8336     /**
8337      * Maintains state information for a single trackball axis, generating
8338      * discrete (DPAD) movements based on raw trackball motion.
8339      */
8340     static final class TrackballAxis {
8341         /**
8342          * The maximum amount of acceleration we will apply.
8343          */
8344         static final float MAX_ACCELERATION = 20;
8345 
8346         /**
8347          * The maximum amount of time (in milliseconds) between events in order
8348          * for us to consider the user to be doing fast trackball movements,
8349          * and thus apply an acceleration.
8350          */
8351         static final long FAST_MOVE_TIME = 150;
8352 
8353         /**
8354          * Scaling factor to the time (in milliseconds) between events to how
8355          * much to multiple/divide the current acceleration.  When movement
8356          * is < FAST_MOVE_TIME this multiplies the acceleration; when >
8357          * FAST_MOVE_TIME it divides it.
8358          */
8359         static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
8360 
8361         static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
8362         static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
8363         static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
8364 
8365         float position;
8366         float acceleration = 1;
8367         long lastMoveTime = 0;
8368         int step;
8369         int dir;
8370         int nonAccelMovement;
8371 
reset(int _step)8372         void reset(int _step) {
8373             position = 0;
8374             acceleration = 1;
8375             lastMoveTime = 0;
8376             step = _step;
8377             dir = 0;
8378         }
8379 
8380         /**
8381          * Add trackball movement into the state.  If the direction of movement
8382          * has been reversed, the state is reset before adding the
8383          * movement (so that you don't have to compensate for any previously
8384          * collected movement before see the result of the movement in the
8385          * new direction).
8386          *
8387          * @return Returns the absolute value of the amount of movement
8388          * collected so far.
8389          */
collect(float off, long time, String axis)8390         float collect(float off, long time, String axis) {
8391             long normTime;
8392             if (off > 0) {
8393                 normTime = (long)(off * FAST_MOVE_TIME);
8394                 if (dir < 0) {
8395                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
8396                     position = 0;
8397                     step = 0;
8398                     acceleration = 1;
8399                     lastMoveTime = 0;
8400                 }
8401                 dir = 1;
8402             } else if (off < 0) {
8403                 normTime = (long)((-off) * FAST_MOVE_TIME);
8404                 if (dir > 0) {
8405                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
8406                     position = 0;
8407                     step = 0;
8408                     acceleration = 1;
8409                     lastMoveTime = 0;
8410                 }
8411                 dir = -1;
8412             } else {
8413                 normTime = 0;
8414             }
8415 
8416             // The number of milliseconds between each movement that is
8417             // considered "normal" and will not result in any acceleration
8418             // or deceleration, scaled by the offset we have here.
8419             if (normTime > 0) {
8420                 long delta = time - lastMoveTime;
8421                 lastMoveTime = time;
8422                 float acc = acceleration;
8423                 if (delta < normTime) {
8424                     // The user is scrolling rapidly, so increase acceleration.
8425                     float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
8426                     if (scale > 1) acc *= scale;
8427                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
8428                             + off + " normTime=" + normTime + " delta=" + delta
8429                             + " scale=" + scale + " acc=" + acc);
8430                     acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
8431                 } else {
8432                     // The user is scrolling slowly, so decrease acceleration.
8433                     float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
8434                     if (scale > 1) acc /= scale;
8435                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
8436                             + off + " normTime=" + normTime + " delta=" + delta
8437                             + " scale=" + scale + " acc=" + acc);
8438                     acceleration = acc > 1 ? acc : 1;
8439                 }
8440             }
8441             position += off;
8442             return Math.abs(position);
8443         }
8444 
8445         /**
8446          * Generate the number of discrete movement events appropriate for
8447          * the currently collected trackball movement.
8448          *
8449          * @return Returns the number of discrete movements, either positive
8450          * or negative, or 0 if there is not enough trackball movement yet
8451          * for a discrete movement.
8452          */
generate()8453         int generate() {
8454             int movement = 0;
8455             nonAccelMovement = 0;
8456             do {
8457                 final int dir = position >= 0 ? 1 : -1;
8458                 switch (step) {
8459                     // If we are going to execute the first step, then we want
8460                     // to do this as soon as possible instead of waiting for
8461                     // a full movement, in order to make things look responsive.
8462                     case 0:
8463                         if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
8464                             return movement;
8465                         }
8466                         movement += dir;
8467                         nonAccelMovement += dir;
8468                         step = 1;
8469                         break;
8470                     // If we have generated the first movement, then we need
8471                     // to wait for the second complete trackball motion before
8472                     // generating the second discrete movement.
8473                     case 1:
8474                         if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
8475                             return movement;
8476                         }
8477                         movement += dir;
8478                         nonAccelMovement += dir;
8479                         position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
8480                         step = 2;
8481                         break;
8482                     // After the first two, we generate discrete movements
8483                     // consistently with the trackball, applying an acceleration
8484                     // if the trackball is moving quickly.  This is a simple
8485                     // acceleration on top of what we already compute based
8486                     // on how quickly the wheel is being turned, to apply
8487                     // a longer increasing acceleration to continuous movement
8488                     // in one direction.
8489                     default:
8490                         if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
8491                             return movement;
8492                         }
8493                         movement += dir;
8494                         position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
8495                         float acc = acceleration;
8496                         acc *= 1.1f;
8497                         acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
8498                         break;
8499                 }
8500             } while (true);
8501         }
8502     }
8503 
8504     /**
8505      * Creates dpad events from unhandled joystick movements.
8506      */
8507     final class SyntheticJoystickHandler extends Handler {
8508         private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
8509         private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
8510 
8511         private final JoystickAxesState mJoystickAxesState = new JoystickAxesState();
8512         private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>();
8513 
8514         public SyntheticJoystickHandler() {
8515             super(true);
8516         }
8517 
8518         @Override
8519         public void handleMessage(Message msg) {
8520             switch (msg.what) {
8521                 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
8522                 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
8523                     if (mAttachInfo.mHasWindowFocus) {
8524                         KeyEvent oldEvent = (KeyEvent) msg.obj;
8525                         KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
8526                                 SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1);
8527                         enqueueInputEvent(e);
8528                         Message m = obtainMessage(msg.what, e);
8529                         m.setAsynchronous(true);
8530                         sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
8531                     }
8532                 } break;
8533             }
8534         }
8535 
8536         public void process(MotionEvent event) {
8537             switch(event.getActionMasked()) {
8538                 case MotionEvent.ACTION_CANCEL:
8539                     cancel();
8540                     break;
8541                 case MotionEvent.ACTION_MOVE:
8542                     update(event);
8543                     break;
8544                 default:
8545                     Log.w(mTag, "Unexpected action: " + event.getActionMasked());
8546             }
8547         }
8548 
8549         private void cancel() {
8550             removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
8551             removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
8552             for (int i = 0; i < mDeviceKeyEvents.size(); i++) {
8553                 final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i);
8554                 if (keyEvent != null) {
8555                     enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent,
8556                             SystemClock.uptimeMillis(), 0));
8557                 }
8558             }
8559             mDeviceKeyEvents.clear();
8560             mJoystickAxesState.resetState();
8561         }
8562 
8563         private void update(MotionEvent event) {
8564             final int historySize = event.getHistorySize();
8565             for (int h = 0; h < historySize; h++) {
8566                 final long time = event.getHistoricalEventTime(h);
8567                 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
8568                         event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h));
8569                 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
8570                         event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h));
8571                 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
8572                         event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h));
8573                 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
8574                         event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h));
8575             }
8576             final long time = event.getEventTime();
8577             mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
8578                     event.getAxisValue(MotionEvent.AXIS_X));
8579             mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
8580                     event.getAxisValue(MotionEvent.AXIS_Y));
8581             mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
8582                     event.getAxisValue(MotionEvent.AXIS_HAT_X));
8583             mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
8584                     event.getAxisValue(MotionEvent.AXIS_HAT_Y));
8585         }
8586 
8587         final class JoystickAxesState {
8588             // State machine: from neutral state (no button press) can go into
8589             // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event.
8590             // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state,
8591             // emitting an ACTION_UP event.
8592             private static final int STATE_UP_OR_LEFT = -1;
8593             private static final int STATE_NEUTRAL = 0;
8594             private static final int STATE_DOWN_OR_RIGHT = 1;
8595 
8596             final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y}
8597             final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y}
8598 
8599             void resetState() {
8600                 mAxisStatesHat[0] = STATE_NEUTRAL;
8601                 mAxisStatesHat[1] = STATE_NEUTRAL;
8602                 mAxisStatesStick[0] = STATE_NEUTRAL;
8603                 mAxisStatesStick[1] = STATE_NEUTRAL;
8604             }
8605 
8606             void updateStateForAxis(MotionEvent event, long time, int axis, float value) {
8607                 // Emit KeyEvent if necessary
8608                 // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y
8609                 final int axisStateIndex;
8610                 final int repeatMessage;
8611                 if (isXAxis(axis)) {
8612                     axisStateIndex = 0;
8613                     repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT;
8614                 } else if (isYAxis(axis)) {
8615                     axisStateIndex = 1;
8616                     repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT;
8617                 } else {
8618                     Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!");
8619                     return;
8620                 }
8621                 final int newState = joystickAxisValueToState(value);
8622 
8623                 final int currentState;
8624                 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
8625                     currentState = mAxisStatesStick[axisStateIndex];
8626                 } else {
8627                     currentState = mAxisStatesHat[axisStateIndex];
8628                 }
8629 
8630                 if (currentState == newState) {
8631                     return;
8632                 }
8633 
8634                 final int metaState = event.getMetaState();
8635                 final int deviceId = event.getDeviceId();
8636                 final int source = event.getSource();
8637 
8638                 if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) {
8639                     // send a button release event
8640                     final int keyCode = joystickAxisAndStateToKeycode(axis, currentState);
8641                     if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
8642                         enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
8643                                 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
8644                         // remove the corresponding pending UP event if focus lost/view detached
8645                         mDeviceKeyEvents.put(deviceId, null);
8646                     }
8647                     removeMessages(repeatMessage);
8648                 }
8649 
8650                 if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) {
8651                     // send a button down event
8652                     final int keyCode = joystickAxisAndStateToKeycode(axis, newState);
8653                     if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
8654                         KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode,
8655                                 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
8656                         enqueueInputEvent(keyEvent);
8657                         Message m = obtainMessage(repeatMessage, keyEvent);
8658                         m.setAsynchronous(true);
8659                         sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
8660                         // store the corresponding ACTION_UP event so that it can be sent
8661                         // if focus is lost or root view is removed
8662                         mDeviceKeyEvents.put(deviceId,
8663                                 new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
8664                                         0, metaState, deviceId, 0,
8665                                         KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED,
8666                                         source));
8667                     }
8668                 }
8669                 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
8670                     mAxisStatesStick[axisStateIndex] = newState;
8671                 } else {
8672                     mAxisStatesHat[axisStateIndex] = newState;
8673                 }
8674             }
8675 
8676             private boolean isXAxis(int axis) {
8677                 return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X;
8678             }
8679             private boolean isYAxis(int axis) {
8680                 return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y;
8681             }
8682 
8683             private int joystickAxisAndStateToKeycode(int axis, int state) {
8684                 if (isXAxis(axis) && state == STATE_UP_OR_LEFT) {
8685                     return KeyEvent.KEYCODE_DPAD_LEFT;
8686                 }
8687                 if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
8688                     return KeyEvent.KEYCODE_DPAD_RIGHT;
8689                 }
8690                 if (isYAxis(axis) && state == STATE_UP_OR_LEFT) {
8691                     return KeyEvent.KEYCODE_DPAD_UP;
8692                 }
8693                 if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
8694                     return KeyEvent.KEYCODE_DPAD_DOWN;
8695                 }
8696                 Log.e(mTag, "Unknown axis " + axis + " or direction " + state);
8697                 return KeyEvent.KEYCODE_UNKNOWN; // should never happen
8698             }
8699 
8700             private int joystickAxisValueToState(float value) {
8701                 if (value >= 0.5f) {
8702                     return STATE_DOWN_OR_RIGHT;
8703                 } else if (value <= -0.5f) {
8704                     return STATE_UP_OR_LEFT;
8705                 } else {
8706                     return STATE_NEUTRAL;
8707                 }
8708             }
8709         }
8710     }
8711 
8712     /**
8713      * Creates DPAD events from unhandled touch navigation movements.
8714      */
8715     final class SyntheticTouchNavigationHandler extends Handler {
8716         private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
8717 
8718         // The id of the input device that is being tracked.
8719         private int mCurrentDeviceId = -1;
8720         private int mCurrentSource;
8721 
8722         private int mPendingKeyMetaState;
8723 
8724         private final GestureDetector mGestureDetector;
8725 
8726         SyntheticTouchNavigationHandler() {
8727             super(true);
8728             int gestureDetectorVelocityStrategy =
8729                     android.companion.virtual.flags.Flags
8730                             .impulseVelocityStrategyForTouchNavigation()
8731                     ? VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE
8732                     : VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT;
8733             mGestureDetector = new GestureDetector(mContext,
8734                     new GestureDetector.OnGestureListener() {
8735                         @Override
8736                         public boolean onDown(@NonNull MotionEvent e) {
8737                             // This can be ignored since it's not clear what KeyEvent this will
8738                             // belong to.
8739                             return true;
8740                         }
8741 
8742                         @Override
8743                         public void onShowPress(@NonNull MotionEvent e) {
8744                         }
8745 
8746                         @Override
8747                         public boolean onSingleTapUp(@NonNull MotionEvent e) {
8748                             dispatchTap(e.getEventTime());
8749                             return true;
8750                         }
8751 
8752                         @Override
8753                         public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
8754                                 float distanceX, float distanceY) {
8755                             // Scroll doesn't translate to DPAD events so should be ignored.
8756                             return true;
8757                         }
8758 
8759                         @Override
8760                         public void onLongPress(@NonNull MotionEvent e) {
8761                             // Long presses don't translate to DPAD events so should be ignored.
8762                         }
8763 
8764                         @Override
8765                         public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
8766                                 float velocityX, float velocityY) {
8767                             dispatchFling(velocityX, velocityY, e2.getEventTime());
8768                             return true;
8769                         }
8770                     },
8771                     /* handler= */ null,
8772                     gestureDetectorVelocityStrategy);
8773         }
8774 
8775         public void process(MotionEvent event) {
8776             if (event.getDevice() == null) {
8777                 // The current device is not supported.
8778                 if (DEBUG_TOUCH_NAVIGATION) {
8779                     Log.d(LOCAL_TAG,
8780                             "Current device not supported so motion event is not processed");
8781                 }
8782                 return;
8783             }
8784             mPendingKeyMetaState = event.getMetaState();
8785             // Update the current device information.
8786             final int deviceId = event.getDeviceId();
8787             final int source = event.getSource();
8788             if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
8789                 mCurrentDeviceId = deviceId;
8790                 mCurrentSource = source;
8791             }
8792 
8793             // Interpret the event.
8794             mGestureDetector.onTouchEvent(event);
8795         }
8796 
8797         private void dispatchTap(long time) {
8798             dispatchEvent(time, KeyEvent.KEYCODE_DPAD_CENTER);
8799         }
8800 
8801         private void dispatchFling(float x, float y, long time) {
8802             if (Math.abs(x) > Math.abs(y)) {
8803                 dispatchEvent(time,
8804                         x > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT);
8805             } else {
8806                 dispatchEvent(time, y > 0 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP);
8807             }
8808         }
8809 
dispatchEvent(long time, int keyCode)8810         private void dispatchEvent(long time, int keyCode) {
8811             if (DEBUG_TOUCH_NAVIGATION) {
8812                 Log.d(LOCAL_TAG, "Dispatching DPAD events DOWN and UP with keycode " + keyCode);
8813             }
8814             enqueueInputEvent(new KeyEvent(time, time,
8815                     KeyEvent.ACTION_DOWN, keyCode, /* repeat= */ 0, mPendingKeyMetaState,
8816                     mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK,
8817                     mCurrentSource));
8818             enqueueInputEvent(new KeyEvent(time, time,
8819                     KeyEvent.ACTION_UP, keyCode, /* repeat= */ 0, mPendingKeyMetaState,
8820                     mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK,
8821                     mCurrentSource));
8822         }
8823     }
8824 
8825     final class SyntheticKeyboardHandler {
process(KeyEvent event)8826         public void process(KeyEvent event) {
8827             if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
8828                 return;
8829             }
8830 
8831             final KeyCharacterMap kcm = event.getKeyCharacterMap();
8832             final int keyCode = event.getKeyCode();
8833             final int metaState = event.getMetaState();
8834 
8835             // Check for fallback actions specified by the key character map.
8836             KeyCharacterMap.FallbackAction fallbackAction =
8837                     kcm.getFallbackAction(keyCode, metaState);
8838             if (fallbackAction != null) {
8839                 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
8840                 KeyEvent fallbackEvent = KeyEvent.obtain(
8841                         event.getDownTime(), event.getEventTime(),
8842                         event.getAction(), fallbackAction.keyCode,
8843                         event.getRepeatCount(), fallbackAction.metaState,
8844                         event.getDeviceId(), event.getScanCode(),
8845                         flags, event.getSource(), null);
8846                 fallbackAction.recycle();
8847                 enqueueInputEvent(fallbackEvent);
8848             }
8849         }
8850     }
8851 
8852     /**
8853      * Returns true if the key is used for keyboard navigation.
8854      * @param keyEvent The key event.
8855      * @return True if the key is used for keyboard navigation.
8856      */
isNavigationKey(KeyEvent keyEvent)8857     private static boolean isNavigationKey(KeyEvent keyEvent) {
8858         switch (keyEvent.getKeyCode()) {
8859         case KeyEvent.KEYCODE_DPAD_LEFT:
8860         case KeyEvent.KEYCODE_DPAD_RIGHT:
8861         case KeyEvent.KEYCODE_DPAD_UP:
8862         case KeyEvent.KEYCODE_DPAD_DOWN:
8863         case KeyEvent.KEYCODE_DPAD_CENTER:
8864         case KeyEvent.KEYCODE_PAGE_UP:
8865         case KeyEvent.KEYCODE_PAGE_DOWN:
8866         case KeyEvent.KEYCODE_MOVE_HOME:
8867         case KeyEvent.KEYCODE_MOVE_END:
8868         case KeyEvent.KEYCODE_TAB:
8869         case KeyEvent.KEYCODE_SPACE:
8870         case KeyEvent.KEYCODE_ENTER:
8871             return true;
8872         }
8873         return false;
8874     }
8875 
8876     /**
8877      * Returns true if the key is used for typing.
8878      * @param keyEvent The key event.
8879      * @return True if the key is used for typing.
8880      */
isTypingKey(KeyEvent keyEvent)8881     private static boolean isTypingKey(KeyEvent keyEvent) {
8882         return keyEvent.getUnicodeChar() > 0;
8883     }
8884 
8885     /**
8886      * See if the key event means we should leave touch mode (and leave touch mode if so).
8887      * @param event The key event.
8888      * @return Whether this key event should be consumed (meaning the act of
8889      *   leaving touch mode alone is considered the event).
8890      */
checkForLeavingTouchModeAndConsume(KeyEvent event)8891     private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
8892         // Only relevant in touch mode.
8893         if (!mAttachInfo.mInTouchMode) {
8894             return false;
8895         }
8896 
8897         // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
8898         final int action = event.getAction();
8899         if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
8900             return false;
8901         }
8902 
8903         // Don't leave touch mode if the IME told us not to.
8904         if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
8905             return false;
8906         }
8907 
8908         // If the key can be used for keyboard navigation then leave touch mode
8909         // and select a focused view if needed (in ensureTouchMode).
8910         // When a new focused view is selected, we consume the navigation key because
8911         // navigation doesn't make much sense unless a view already has focus so
8912         // the key's purpose is to set focus.
8913         if (event.hasNoModifiers() && isNavigationKey(event)) {
8914             return ensureTouchMode(false);
8915         }
8916 
8917         // If the key can be used for typing then leave touch mode
8918         // and select a focused view if needed (in ensureTouchMode).
8919         // Always allow the view to process the typing key.
8920         if (isTypingKey(event)) {
8921             ensureTouchMode(false);
8922             return false;
8923         }
8924 
8925         return false;
8926     }
8927 
8928     /* drag/drop */
8929     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setLocalDragState(Object obj)8930     void setLocalDragState(Object obj) {
8931         mLocalDragState = obj;
8932     }
8933 
handleDragEvent(DragEvent event)8934     private void handleDragEvent(DragEvent event) {
8935         // From the root, only drag start/end/location are dispatched.  entered/exited
8936         // are determined and dispatched by the viewgroup hierarchy, who then report
8937         // that back here for ultimate reporting back to the framework.
8938         if (mView != null && mAdded) {
8939             final int what = event.mAction;
8940 
8941             // Cache the drag description when the operation starts, then fill it in
8942             // on subsequent calls as a convenience
8943             if (what == DragEvent.ACTION_DRAG_STARTED) {
8944                 mCurrentDragView = null;    // Start the current-recipient tracking
8945                 mDragDescription = event.mClipDescription;
8946                 if (mStartedDragViewForA11y != null) {
8947                     // Send a drag started a11y event
8948                     mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
8949                             AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_STARTED);
8950                 }
8951             } else {
8952                 if (what == DragEvent.ACTION_DRAG_ENDED) {
8953                     mDragDescription = null;
8954                 }
8955                 event.mClipDescription = mDragDescription;
8956             }
8957 
8958             if (what == DragEvent.ACTION_DRAG_EXITED) {
8959                 // A direct EXITED event means that the window manager knows we've just crossed
8960                 // a window boundary, so the current drag target within this one must have
8961                 // just been exited. Send the EXITED notification to the current drag view, if any.
8962                 if (View.sCascadedDragDrop) {
8963                     mView.dispatchDragEnterExitInPreN(event);
8964                 }
8965                 setDragFocus(null, event);
8966             } else {
8967                 // For events with a [screen] location, translate into window coordinates
8968                 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
8969                     mDragPoint.set(event.mX, event.mY);
8970                     if (mTranslator != null) {
8971                         mTranslator.translatePointInScreenToAppWindow(mDragPoint);
8972                     }
8973 
8974                     if (mCurScrollY != 0) {
8975                         mDragPoint.offset(0, mCurScrollY);
8976                     }
8977 
8978                     event.mX = mDragPoint.x;
8979                     event.mY = mDragPoint.y;
8980                 }
8981 
8982                 // Remember who the current drag target is pre-dispatch
8983                 final View prevDragView = mCurrentDragView;
8984 
8985                 if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
8986                     event.mClipData.prepareToEnterProcess(
8987                             mView.getContext().getAttributionSource());
8988                 }
8989 
8990                 // Now dispatch the drag/drop event
8991                 boolean result = mView.dispatchDragEvent(event);
8992 
8993                 if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
8994                     // If the LOCATION event wasn't delivered to any handler, no view now has a drag
8995                     // focus.
8996                     setDragFocus(null, event);
8997                 }
8998 
8999                 // If we changed apparent drag target, tell the OS about it
9000                 if (prevDragView != mCurrentDragView) {
9001                     try {
9002                         if (prevDragView != null) {
9003                             mWindowSession.dragRecipientExited(mWindow);
9004                         }
9005                         if (mCurrentDragView != null) {
9006                             mWindowSession.dragRecipientEntered(mWindow);
9007                         }
9008                     } catch (RemoteException e) {
9009                         Slog.e(mTag, "Unable to note drag target change");
9010                     }
9011                 }
9012 
9013                 // Report the drop result when we're done
9014                 if (what == DragEvent.ACTION_DROP) {
9015                     try {
9016                         Log.i(mTag, "Reporting drop result: " + result);
9017                         mWindowSession.reportDropResult(mWindow, result);
9018                     } catch (RemoteException e) {
9019                         Log.e(mTag, "Unable to report drop result");
9020                     }
9021                 }
9022 
9023                 // When the drag operation ends, reset drag-related state
9024                 if (what == DragEvent.ACTION_DRAG_ENDED) {
9025                     if (mStartedDragViewForA11y != null) {
9026                         // If the drag failed, send a cancelled event from the source. Otherwise,
9027                         // the View that accepted the drop sends CONTENT_CHANGE_TYPE_DRAG_DROPPED
9028                         if (!event.getResult()) {
9029                             mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
9030                                     AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_CANCELLED);
9031                         }
9032                         mStartedDragViewForA11y.setAccessibilityDragStarted(false);
9033                     }
9034                     mStartedDragViewForA11y = null;
9035                     mCurrentDragView = null;
9036                     setLocalDragState(null);
9037                     mAttachInfo.mDragToken = null;
9038                     if (mAttachInfo.mDragSurface != null) {
9039                         mAttachInfo.mDragSurface.release();
9040                         mAttachInfo.mDragSurface = null;
9041                     }
9042                     if (mAttachInfo.mDragData != null) {
9043                         View.cleanUpPendingIntents(mAttachInfo.mDragData);
9044                         mAttachInfo.mDragData = null;
9045                     }
9046                 }
9047             }
9048         }
9049         event.recycle();
9050     }
9051 
9052     /**
9053      * Notify that the window title changed
9054      */
onWindowTitleChanged()9055     public void onWindowTitleChanged() {
9056         mAttachInfo.mForceReportNewAttributes = true;
9057     }
9058 
handleDispatchWindowShown()9059     public void handleDispatchWindowShown() {
9060         mAttachInfo.mTreeObserver.dispatchOnWindowShown();
9061     }
9062 
handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)9063     public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
9064         Bundle data = new Bundle();
9065         ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
9066         if (mView != null) {
9067             mView.requestKeyboardShortcuts(list, deviceId);
9068         }
9069         int numGroups = list.size();
9070         for (int i = 0; i < numGroups; ++i) {
9071             final KeyboardShortcutGroup group = list.get(i);
9072             group.setPackageName(mBasePackageName);
9073 
9074         }
9075         data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
9076         try {
9077             receiver.send(0, data);
9078         } catch (RemoteException e) {
9079         }
9080     }
9081 
9082     @UnsupportedAppUsage
getLastTouchPoint(Point outLocation)9083     public void getLastTouchPoint(Point outLocation) {
9084         outLocation.x = (int) mLastTouchPoint.x;
9085         outLocation.y = (int) mLastTouchPoint.y;
9086     }
9087 
getLastTouchSource()9088     public int getLastTouchSource() {
9089         return mLastTouchSource;
9090     }
9091 
getLastTouchDeviceId()9092     public int getLastTouchDeviceId() {
9093         return mLastTouchDeviceId;
9094     }
9095 
getLastTouchPointerId()9096     public int getLastTouchPointerId() {
9097         return mLastTouchPointerId;
9098     }
9099 
9100     /**
9101      * Used by InputMethodManager.
9102      * @hide
9103      */
getLastClickToolType()9104     public int getLastClickToolType() {
9105         return mLastClickToolType;
9106     }
9107 
setDragFocus(View newDragTarget, DragEvent event)9108     public void setDragFocus(View newDragTarget, DragEvent event) {
9109         if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
9110             // Send EXITED and ENTERED notifications to the old and new drag focus views.
9111 
9112             final float tx = event.mX;
9113             final float ty = event.mY;
9114             final int action = event.mAction;
9115             final ClipData td = event.mClipData;
9116             // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
9117             event.mX = 0;
9118             event.mY = 0;
9119             event.mClipData = null;
9120 
9121             if (mCurrentDragView != null) {
9122                 event.mAction = DragEvent.ACTION_DRAG_EXITED;
9123                 mCurrentDragView.callDragEventHandler(event);
9124             }
9125 
9126             if (newDragTarget != null) {
9127                 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
9128                 newDragTarget.callDragEventHandler(event);
9129             }
9130 
9131             event.mAction = action;
9132             event.mX = tx;
9133             event.mY = ty;
9134             event.mClipData = td;
9135         }
9136 
9137         mCurrentDragView = newDragTarget;
9138     }
9139 
9140     /** Sets the view that started drag and drop for the purpose of sending AccessibilityEvents */
setDragStartedViewForAccessibility(View view)9141     void setDragStartedViewForAccessibility(View view) {
9142         if (mStartedDragViewForA11y == null) {
9143             mStartedDragViewForA11y = view;
9144         }
9145     }
9146 
getAudioManager()9147     private AudioManager getAudioManager() {
9148         if (mView == null) {
9149             throw new IllegalStateException("getAudioManager called when there is no mView");
9150         }
9151         if (mAudioManager == null) {
9152             mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
9153             mFastScrollSoundEffectsEnabled = mAudioManager.areNavigationRepeatSoundEffectsEnabled();
9154         }
9155         return mAudioManager;
9156     }
9157 
getAutofillManager()9158     private @Nullable AutofillManager getAutofillManager() {
9159         if (mView instanceof ViewGroup) {
9160             ViewGroup decorView = (ViewGroup) mView;
9161             if (decorView.getChildCount() > 0) {
9162                 // We cannot use decorView's Context for querying AutofillManager: DecorView's
9163                 // context is based on Application Context, it would allocate a different
9164                 // AutofillManager instance.
9165                 return decorView.getChildAt(0).getContext()
9166                         .getSystemService(AutofillManager.class);
9167             }
9168         }
9169         return null;
9170     }
9171 
isAutofillUiShowing()9172     private boolean isAutofillUiShowing() {
9173         AutofillManager afm = getAutofillManager();
9174         if (afm == null) {
9175             return false;
9176         }
9177         return afm.isAutofillUiShowing();
9178     }
9179 
getAccessibilityInteractionController()9180     public AccessibilityInteractionController getAccessibilityInteractionController() {
9181         if (mView == null) {
9182             throw new IllegalStateException("getAccessibilityInteractionController"
9183                     + " called when there is no mView");
9184         }
9185         if (mAccessibilityInteractionController == null) {
9186             mAccessibilityInteractionController = new AccessibilityInteractionController(this);
9187         }
9188         return mAccessibilityInteractionController;
9189     }
9190 
relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending)9191     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
9192             boolean insetsPending) throws RemoteException {
9193         final WindowConfiguration winConfigFromAm = getConfiguration().windowConfiguration;
9194         final WindowConfiguration winConfigFromWm =
9195                 mLastReportedMergedConfiguration.getGlobalConfiguration().windowConfiguration;
9196         final WindowConfiguration winConfig = getCompatWindowConfiguration();
9197         final int measuredWidth = mMeasuredWidth;
9198         final int measuredHeight = mMeasuredHeight;
9199         final boolean relayoutAsync;
9200         if ((mViewFrameInfo.flags & FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED) == 0
9201                 && mWindowAttributes.type != TYPE_APPLICATION_STARTING
9202                 && mSyncSeqId <= mLastSyncSeqId
9203                 && winConfigFromAm.diff(winConfigFromWm, false /* compareUndefined */) == 0) {
9204             final InsetsState state = mInsetsController.getState();
9205             final Rect displayCutoutSafe = mTempRect;
9206             state.getDisplayCutoutSafe(displayCutoutSafe);
9207             mWindowLayout.computeFrames(mWindowAttributes.forRotation(winConfig.getRotation()),
9208                     state, displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
9209                     measuredWidth, measuredHeight, mInsetsController.getRequestedVisibleTypes(),
9210                     1f /* compatScale */, mTmpFrames);
9211             mWinFrameInScreen.set(mTmpFrames.frame);
9212             if (mTranslator != null) {
9213                 mTranslator.translateRectInAppWindowToScreen(mWinFrameInScreen);
9214             }
9215 
9216             // If the position and the size of the frame are both changed, it will trigger a BLAST
9217             // sync, and we still need to call relayout to obtain the syncSeqId. Otherwise, we just
9218             // need to send attributes via relayoutAsync.
9219             final Rect oldFrame = mLastLayoutFrame;
9220             final Rect newFrame = mTmpFrames.frame;
9221             final boolean positionChanged =
9222                     newFrame.top != oldFrame.top || newFrame.left != oldFrame.left;
9223             final boolean sizeChanged =
9224                     newFrame.width() != oldFrame.width() || newFrame.height() != oldFrame.height();
9225             relayoutAsync = !positionChanged || !sizeChanged;
9226         } else {
9227             relayoutAsync = false;
9228         }
9229 
9230         float appScale = mAttachInfo.mApplicationScale;
9231         boolean restore = false;
9232         if (params != null && mTranslator != null) {
9233             restore = true;
9234             params.backup();
9235             mTranslator.translateWindowLayout(params);
9236         }
9237 
9238         if (params != null) {
9239             if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
9240 
9241             if (mOrigWindowType != params.type) {
9242                 // For compatibility with old apps, don't crash here.
9243                 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
9244                     Slog.w(mTag, "Window type can not be changed after "
9245                             + "the window is added; ignoring change of " + mView);
9246                     params.type = mOrigWindowType;
9247                 }
9248             }
9249         }
9250 
9251         final int requestedWidth = (int) (measuredWidth * appScale + 0.5f);
9252         final int requestedHeight = (int) (measuredHeight * appScale + 0.5f);
9253         int relayoutResult = 0;
9254         mRelayoutSeq++;
9255         if (relayoutAsync) {
9256             mWindowSession.relayoutAsync(mWindow, params,
9257                     requestedWidth, requestedHeight, viewVisibility,
9258                     insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
9259                     mLastSyncSeqId);
9260         } else {
9261             if (windowSessionRelayoutInfo()) {
9262                 relayoutResult = mWindowSession.relayout(mWindow, params,
9263                         requestedWidth, requestedHeight, viewVisibility,
9264                         insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
9265                         mRelayoutSeq, mLastSyncSeqId, mRelayoutResult);
9266             } else {
9267                 relayoutResult = mWindowSession.relayoutLegacy(mWindow, params,
9268                         requestedWidth, requestedHeight, viewVisibility,
9269                         insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
9270                         mRelayoutSeq, mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration,
9271                         mSurfaceControl, mTempInsets, mTempControls, mRelayoutBundle);
9272             }
9273             mRelayoutRequested = true;
9274 
9275             if (activityWindowInfoFlag() && mPendingActivityWindowInfo != null) {
9276                 ActivityWindowInfo outInfo = null;
9277                 if (windowSessionRelayoutInfo()) {
9278                     outInfo = mRelayoutResult != null ? mRelayoutResult.activityWindowInfo : null;
9279                 } else {
9280                     try {
9281                         outInfo = mRelayoutBundle.getParcelable(
9282                                 IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO,
9283                                 ActivityWindowInfo.class);
9284                         mRelayoutBundle.remove(
9285                                 IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO);
9286                     } catch (IllegalStateException e) {
9287                         Log.e(TAG, "Failed to get ActivityWindowInfo from relayout Bundle", e);
9288                     }
9289                 }
9290                 if (outInfo != null) {
9291                     mPendingActivityWindowInfo.set(outInfo);
9292                 }
9293             }
9294             final int maybeSyncSeqId = windowSessionRelayoutInfo()
9295                     ? mRelayoutResult.syncSeqId
9296                     : mRelayoutBundle.getInt(IWindowSession.KEY_RELAYOUT_BUNDLE_SEQID);
9297             if (maybeSyncSeqId > 0) {
9298                 mSyncSeqId = maybeSyncSeqId;
9299             }
9300 
9301             mWinFrameInScreen.set(mTmpFrames.frame);
9302             if (mTranslator != null) {
9303                 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
9304                 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.displayFrame);
9305                 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.attachedFrame);
9306                 mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
9307                 mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls.get());
9308             }
9309             mInvCompatScale = 1f / mTmpFrames.compatScale;
9310             CompatibilityInfo.applyOverrideScaleIfNeeded(mPendingMergedConfiguration);
9311             mInsetsController.onStateChanged(mTempInsets);
9312             mInsetsController.onControlsChanged(mTempControls.get());
9313 
9314             mPendingAlwaysConsumeSystemBars =
9315                     (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
9316         }
9317 
9318         final int transformHint = SurfaceControl.rotationToBufferTransform(
9319                 (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4);
9320         final boolean transformHintChanged = transformHint != mPreviousTransformHint;
9321         mPreviousTransformHint = transformHint;
9322         mSurfaceControl.setTransformHint(transformHint);
9323 
9324         WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth,
9325                 requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize);
9326 
9327         final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize);
9328         final boolean surfaceControlChanged =
9329                 (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) == RELAYOUT_RES_SURFACE_CHANGED;
9330         if (mAttachInfo.mThreadedRenderer != null &&
9331                 (transformHintChanged || sizeChanged || surfaceControlChanged)) {
9332             if (mAttachInfo.mThreadedRenderer.pause()) {
9333                 // Animations were running so we need to push a frame
9334                 // to resume them
9335                 mDirty.set(0, 0, mWidth, mHeight);
9336             }
9337         }
9338 
9339         if (mSurfaceControl.isValid()) {
9340             if (mPendingDragResizing && !mSurfaceSize.equals(
9341                     mWinFrameInScreen.width(), mWinFrameInScreen.height())) {
9342                 // During drag-resize, a single fullscreen-sized surface is reused for optimization.
9343                 // Crop to the content size instead of the surface size to avoid exposing garbage
9344                 // content that is still on the surface from previous re-layouts (e.g. when
9345                 // resizing to a larger size).
9346                 mTransaction.setWindowCrop(mSurfaceControl,
9347                         mWinFrameInScreen.width(), mWinFrameInScreen.height());
9348             } else if (!HardwareRenderer.isDrawingEnabled()) {
9349                 // When drawing is disabled the window layer won't have a valid buffer.
9350                 // Set a window crop so input can get delivered to the window.
9351                 mTransaction.setWindowCrop(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y).apply();
9352             }
9353         }
9354 
9355         if (mAttachInfo.mContentCaptureManager != null) {
9356             ContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
9357                     .getMainContentCaptureSession();
9358             mainSession.notifyWindowBoundsChanged(mainSession.getId(),
9359                     getConfiguration().windowConfiguration.getBounds());
9360         }
9361 
9362         if (mSurfaceControl.isValid()) {
9363             updateBlastSurfaceIfNeeded();
9364             if (mAttachInfo.mThreadedRenderer != null) {
9365                 mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
9366             }
9367             mHdrRenderState.forceUpdateHdrSdrRatio();
9368             if (transformHintChanged) {
9369                 dispatchTransformHintChanged(transformHint);
9370             }
9371         } else {
9372             if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.pause()) {
9373                 mDirty.set(0, 0, mWidth, mHeight);
9374             }
9375             destroySurface();
9376         }
9377 
9378         if (restore) {
9379             params.restore();
9380         }
9381 
9382         setFrame(mTmpFrames.frame, true /* withinRelayout */);
9383         return relayoutResult;
9384     }
9385 
updateOpacity(WindowManager.LayoutParams params, boolean dragResizing, boolean forceUpdate)9386     private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing,
9387             boolean forceUpdate) {
9388         boolean opaque = false;
9389 
9390         if (!PixelFormat.formatHasAlpha(params.format)
9391                 // Don't make surface with surfaceInsets opaque as they display a
9392                 // translucent shadow.
9393                 && params.surfaceInsets.left == 0
9394                 && params.surfaceInsets.top == 0
9395                 && params.surfaceInsets.right == 0
9396                 && params.surfaceInsets.bottom == 0
9397                 // Don't make surface opaque when resizing to reduce the amount of
9398                 // artifacts shown in areas the app isn't drawing content to.
9399                 && !dragResizing) {
9400             opaque = true;
9401         }
9402 
9403         if (!forceUpdate && mIsSurfaceOpaque == opaque) {
9404             return;
9405         }
9406 
9407         final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
9408         if (renderer != null && renderer.rendererOwnsSurfaceControlOpacity()) {
9409             opaque = renderer.setSurfaceControlOpaque(opaque);
9410         } else {
9411             mTransaction.setOpaque(mSurfaceControl, opaque).apply();
9412         }
9413 
9414         mIsSurfaceOpaque = opaque;
9415     }
9416 
9417     /**
9418      * Set the mWinFrame of this window.
9419      * @param frame the new frame of this window.
9420      * @param withinRelayout {@code true} if this setting is within the relayout, or is the initial
9421      *                       setting. That will make sure in the relayout process, we always compare
9422      *                       the window frame with the last processed window frame.
9423      */
setFrame(Rect frame, boolean withinRelayout)9424     private void setFrame(Rect frame, boolean withinRelayout) {
9425         mWinFrame.set(frame);
9426         if (withinRelayout) {
9427             mLastLayoutFrame.set(frame);
9428         }
9429 
9430         final WindowConfiguration winConfig = getCompatWindowConfiguration();
9431         mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop()
9432                 ? winConfig.getMaxBounds()
9433                 : frame);
9434         // Surface position is now inherited from parent, and BackdropFrameRenderer uses backdrop
9435         // frame to position content. Thus, we just keep the size of backdrop frame, and remove the
9436         // offset to avoid double offset from display origin.
9437         mPendingBackDropFrame.offsetTo(0, 0);
9438 
9439         mInsetsController.onFrameChanged(mOverrideInsetsFrame != null ?
9440                 mOverrideInsetsFrame : frame);
9441     }
9442 
9443     /**
9444      * In the normal course of operations we compute insets relative to
9445      * the frame returned from relayout window. In the case of
9446      * SurfaceControlViewHost, this frame is in local coordinates
9447      * instead of global coordinates. We support this override
9448      * frame so we can allow SurfaceControlViewHost to set a frame
9449      * to be used to calculate insets, without disturbing the main
9450      * mFrame.
9451      */
setOverrideInsetsFrame(Rect frame)9452     void setOverrideInsetsFrame(Rect frame) {
9453         mOverrideInsetsFrame = new Rect(frame);
9454         mInsetsController.onFrameChanged(mOverrideInsetsFrame);
9455     }
9456 
9457     /**
9458      * Gets the current display size in which the window is being laid out, accounting for screen
9459      * decorations around it.
9460      */
getDisplayFrame(Rect outFrame)9461     void getDisplayFrame(Rect outFrame) {
9462         outFrame.set(mTmpFrames.displayFrame);
9463         // Apply sandboxing here (in getter) due to possible layout updates on the client after
9464         // mTmpFrames.displayFrame is received from the server.
9465         applyViewBoundsSandboxingIfNeeded(outFrame);
9466     }
9467 
9468     /**
9469      * Gets the current display size in which the window is being laid out, accounting for screen
9470      * decorations around it.
9471      */
getWindowVisibleDisplayFrame(Rect outFrame)9472     void getWindowVisibleDisplayFrame(Rect outFrame) {
9473         outFrame.set(mTmpFrames.displayFrame);
9474         // XXX This is really broken, and probably all needs to be done
9475         // in the window manager, and we need to know more about whether
9476         // we want the area behind or in front of the IME.
9477         final Rect insets = mAttachInfo.mVisibleInsets;
9478         outFrame.left += insets.left;
9479         outFrame.top += insets.top;
9480         outFrame.right -= insets.right;
9481         outFrame.bottom -= insets.bottom;
9482         // Apply sandboxing here (in getter) due to possible layout updates on the client after
9483         // mTmpFrames.displayFrame is received from the server.
9484         applyViewBoundsSandboxingIfNeeded(outFrame);
9485     }
9486 
9487     /**
9488      * Offset outRect to make it sandboxed within Window's bounds.
9489      *
9490      * <p>This is used by {@link android.view.View#getBoundsOnScreen},
9491      * {@link android.view.ViewRootImpl#getDisplayFrame} and
9492      * {@link android.view.ViewRootImpl#getWindowVisibleDisplayFrame}, which are invoked by
9493      * {@link android.view.View#getWindowDisplayFrame} and
9494      * {@link android.view.View#getWindowVisibleDisplayFrame}, as well as
9495      * {@link android.view.ViewDebug#captureLayers} for debugging.
9496      */
applyViewBoundsSandboxingIfNeeded(final Rect inOutRect)9497     void applyViewBoundsSandboxingIfNeeded(final Rect inOutRect) {
9498         if (mViewBoundsSandboxingEnabled) {
9499             final Rect bounds = getConfiguration().windowConfiguration.getBounds();
9500             inOutRect.offset(-bounds.left, -bounds.top);
9501         }
9502     }
9503 
9504     /**
9505      * Offset outLocation to make it sandboxed within Window's bounds.
9506      *
9507      * <p>This is used by {@link android.view.View#getLocationOnScreen(int[])}
9508      */
applyViewLocationSandboxingIfNeeded(@ize2) int[] outLocation)9509     public void applyViewLocationSandboxingIfNeeded(@Size(2) int[] outLocation) {
9510         if (mViewBoundsSandboxingEnabled) {
9511             final Rect bounds = getConfiguration().windowConfiguration.getBounds();
9512             outLocation[0] -= bounds.left;
9513             outLocation[1] -= bounds.top;
9514         }
9515     }
9516 
getViewBoundsSandboxingEnabled()9517     private boolean getViewBoundsSandboxingEnabled() {
9518         // System dialogs (e.g. ANR) can be created within System process, so handleBindApplication
9519         // may be never called. This results into all app compat changes being enabled
9520         // (see b/268007823) because AppCompatCallbacks.install() is never called with non-empty
9521         // array.
9522         // With ActivityThread.isSystem we verify that it is not the system process,
9523         // then this CompatChange can take effect.
9524         if (ActivityThread.isSystem()
9525                 || !CompatChanges.isChangeEnabled(OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS)) {
9526             // It is a system process or OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS change-id is disabled.
9527             return false;
9528         }
9529 
9530         // OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS is enabled by the device manufacturer.
9531         try {
9532             final List<PackageManager.Property> properties = mContext.getPackageManager()
9533                     .queryApplicationProperty(PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS);
9534 
9535             final boolean isOptedOut = !properties.isEmpty() && !properties.get(0).getBoolean();
9536             if (isOptedOut) {
9537                 // PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS is disabled by the app devs.
9538                 return false;
9539             }
9540         } catch (RuntimeException e) {
9541             // remote exception.
9542         }
9543 
9544         return true;
9545     }
9546 
9547     /**
9548      * {@inheritDoc}
9549      */
9550     @Override
playSoundEffect(@oundEffectConstants.SoundEffect int effectId)9551     public void playSoundEffect(@SoundEffectConstants.SoundEffect int effectId) {
9552         if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
9553             return;
9554         }
9555 
9556         checkThread();
9557 
9558         try {
9559             final AudioManager audioManager = getAudioManager();
9560 
9561             if (mFastScrollSoundEffectsEnabled
9562                     && SoundEffectConstants.isNavigationRepeat(effectId)) {
9563                 audioManager.playSoundEffect(
9564                         SoundEffectConstants.nextNavigationRepeatSoundEffectId());
9565                 return;
9566             }
9567 
9568             switch (effectId) {
9569                 case SoundEffectConstants.CLICK:
9570                     audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
9571                     return;
9572                 case SoundEffectConstants.NAVIGATION_DOWN:
9573                 case SoundEffectConstants.NAVIGATION_REPEAT_DOWN:
9574                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
9575                     return;
9576                 case SoundEffectConstants.NAVIGATION_LEFT:
9577                 case SoundEffectConstants.NAVIGATION_REPEAT_LEFT:
9578                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
9579                     return;
9580                 case SoundEffectConstants.NAVIGATION_RIGHT:
9581                 case SoundEffectConstants.NAVIGATION_REPEAT_RIGHT:
9582                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
9583                     return;
9584                 case SoundEffectConstants.NAVIGATION_UP:
9585                 case SoundEffectConstants.NAVIGATION_REPEAT_UP:
9586                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
9587                     return;
9588                 default:
9589                     throw new IllegalArgumentException("unknown effect id " + effectId +
9590                             " not defined in " + SoundEffectConstants.class.getCanonicalName());
9591             }
9592         } catch (IllegalStateException e) {
9593             // Exception thrown by getAudioManager() when mView is null
9594             Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
9595             e.printStackTrace();
9596         }
9597     }
9598 
9599     /**
9600      * {@inheritDoc}
9601      */
9602     @Override
performHapticFeedback(int effectId, boolean always, boolean fromIme)9603     public boolean performHapticFeedback(int effectId, boolean always, boolean fromIme) {
9604         if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
9605             return false;
9606         }
9607 
9608         try {
9609             if (USE_ASYNC_PERFORM_HAPTIC_FEEDBACK) {
9610                 mWindowSession.performHapticFeedbackAsync(effectId, always, fromIme);
9611                 return true;
9612             } else {
9613                 // Original blocking binder call path.
9614                 return mWindowSession.performHapticFeedback(effectId, always, fromIme);
9615             }
9616         } catch (RemoteException e) {
9617             return false;
9618         }
9619     }
9620 
9621     /**
9622      * {@inheritDoc}
9623      */
9624     @Override
focusSearch(View focused, int direction)9625     public View focusSearch(View focused, int direction) {
9626         checkThread();
9627         if (!(mView instanceof ViewGroup)) {
9628             return null;
9629         }
9630         return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
9631     }
9632 
9633     /**
9634      * {@inheritDoc}
9635      */
9636     @Override
keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)9637     public View keyboardNavigationClusterSearch(View currentCluster,
9638             @FocusDirection int direction) {
9639         checkThread();
9640         return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
9641                 mView, currentCluster, direction);
9642     }
9643 
debug()9644     public void debug() {
9645         mView.debug();
9646     }
9647 
9648     /**
9649      * Export the state of {@link ViewRootImpl} and other relevant classes into a protocol buffer
9650      * output stream.
9651      *
9652      * @param proto Stream to write the state to
9653      * @param fieldId FieldId of ViewRootImpl as defined in the parent message
9654      */
9655     @GuardedBy("this")
dumpDebug(ProtoOutputStream proto, long fieldId)9656     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
9657         final long token = proto.start(fieldId);
9658         proto.write(VIEW, Objects.toString(mView));
9659         proto.write(DISPLAY_ID, mDisplay.getDisplayId());
9660         proto.write(APP_VISIBLE, mAppVisible);
9661         proto.write(HEIGHT, mHeight);
9662         proto.write(WIDTH, mWidth);
9663         proto.write(IS_ANIMATING, mIsAnimating);
9664         mVisRect.dumpDebug(proto, VISIBLE_RECT);
9665         proto.write(IS_DRAWING, mIsDrawing);
9666         proto.write(ADDED, mAdded);
9667         mWinFrame.dumpDebug(proto, WIN_FRAME);
9668         proto.write(LAST_WINDOW_INSETS, Objects.toString(mLastWindowInsets));
9669         proto.write(SOFT_INPUT_MODE, InputMethodDebug.softInputModeToString(mSoftInputMode));
9670         proto.write(SCROLL_Y, mScrollY);
9671         proto.write(CUR_SCROLL_Y, mCurScrollY);
9672         proto.write(REMOVED, mRemoved);
9673         mWindowAttributes.dumpDebug(proto, WINDOW_ATTRIBUTES);
9674         proto.end(token);
9675         mInsetsController.dumpDebug(proto, INSETS_CONTROLLER);
9676         mImeFocusController.dumpDebug(proto, IME_FOCUS_CONTROLLER);
9677     }
9678 
9679     /**
9680      * Dump information about this ViewRootImpl
9681      * @param prefix the prefix that will be prepended to each line of the produced output
9682      * @param writer the writer that will receive the resulting text
9683      */
dump(String prefix, PrintWriter writer)9684     public void dump(String prefix, PrintWriter writer) {
9685         String innerPrefix = prefix + "  ";
9686         writer.println(prefix + "ViewRoot:");
9687         writer.println(innerPrefix + "mAdded=" + mAdded);
9688         writer.println(innerPrefix + "mRemoved=" + mRemoved);
9689         writer.println(innerPrefix + "mStopped=" + mStopped);
9690         writer.println(innerPrefix + "mPausedForTransition=" + mPausedForTransition);
9691         writer.println(innerPrefix + "mConsumeBatchedInputScheduled="
9692                 + mConsumeBatchedInputScheduled);
9693         writer.println(innerPrefix + "mConsumeBatchedInputImmediatelyScheduled="
9694                 + mConsumeBatchedInputImmediatelyScheduled);
9695         writer.println(innerPrefix + "mPendingInputEventCount=" + mPendingInputEventCount);
9696         writer.println(innerPrefix + "mProcessInputEventsScheduled="
9697                 + mProcessInputEventsScheduled);
9698         writer.println(innerPrefix + "mTraversalScheduled=" + mTraversalScheduled);
9699         if (mTraversalScheduled) {
9700             writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")");
9701         }
9702         writer.println(innerPrefix + "mReportNextDraw=" + mReportNextDraw);
9703         if (mReportNextDraw) {
9704             writer.println(innerPrefix + " (reason=" + mLastReportNextDrawReason + ")");
9705         }
9706         if (mLastPerformTraversalsSkipDrawReason != null) {
9707             writer.println(innerPrefix + "mLastPerformTraversalsFailedReason="
9708                 + mLastPerformTraversalsSkipDrawReason);
9709         }
9710         if (mLastPerformDrawSkippedReason != null) {
9711             writer.println(innerPrefix + "mLastPerformDrawFailedReason="
9712                 + mLastPerformDrawSkippedReason);
9713         }
9714         if (mWmsRequestSyncGroupState != WMS_SYNC_NONE) {
9715             writer.println(innerPrefix + "mWmsRequestSyncGroupState=" + mWmsRequestSyncGroupState);
9716         }
9717         writer.println(innerPrefix + "mLastReportedMergedConfiguration="
9718                 + mLastReportedMergedConfiguration);
9719         writer.println(innerPrefix + "mLastConfigurationFromResources="
9720                 + mLastConfigurationFromResources);
9721         if (mLastReportedActivityWindowInfo != null) {
9722             writer.println(innerPrefix + "mLastReportedActivityWindowInfo="
9723                     + mLastReportedActivityWindowInfo);
9724         }
9725         writer.println(innerPrefix + "mIsAmbientMode="  + mIsAmbientMode);
9726         writer.println(innerPrefix + "mUnbufferedInputSource="
9727                 + Integer.toHexString(mUnbufferedInputSource));
9728         if (mAttachInfo != null) {
9729             writer.print(innerPrefix + "mAttachInfo= ");
9730             mAttachInfo.dump(innerPrefix, writer);
9731         } else {
9732             writer.println(innerPrefix + "mAttachInfo=<null>");
9733         }
9734 
9735         mFirstInputStage.dump(innerPrefix, writer);
9736 
9737         if (mInputEventReceiver != null) {
9738             mInputEventReceiver.dump(innerPrefix, writer);
9739         }
9740 
9741         mChoreographer.dump(prefix, writer);
9742 
9743         mInsetsController.dump(prefix, writer);
9744 
9745         mOnBackInvokedDispatcher.dump(prefix, writer);
9746 
9747         mImeBackAnimationController.dump(prefix, writer);
9748 
9749         writer.println(prefix + "View Hierarchy:");
9750         dumpViewHierarchy(innerPrefix, writer, mView);
9751     }
9752 
dumpViewHierarchy(String prefix, PrintWriter writer, View view)9753     private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
9754         writer.print(prefix);
9755         if (view == null) {
9756             writer.println("null");
9757             return;
9758         }
9759         writer.println(view.toString());
9760         if (!(view instanceof ViewGroup)) {
9761             return;
9762         }
9763         ViewGroup grp = (ViewGroup)view;
9764         final int N = grp.getChildCount();
9765         if (N <= 0) {
9766             return;
9767         }
9768         prefix = prefix + "  ";
9769         for (int i=0; i<N; i++) {
9770             dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
9771         }
9772     }
9773 
9774     static final class GfxInfo {
9775         public int viewCount;
9776         public long renderNodeMemoryUsage;
9777         public long renderNodeMemoryAllocated;
9778 
add(GfxInfo other)9779         void add(GfxInfo other) {
9780             viewCount += other.viewCount;
9781             renderNodeMemoryUsage += other.renderNodeMemoryUsage;
9782             renderNodeMemoryAllocated += other.renderNodeMemoryAllocated;
9783         }
9784     }
9785 
getGfxInfo()9786     GfxInfo getGfxInfo() {
9787         GfxInfo info = new GfxInfo();
9788         if (mView != null) {
9789             appendGfxInfo(mView, info);
9790         }
9791         return info;
9792     }
9793 
computeRenderNodeUsage(RenderNode node, GfxInfo info)9794     private static void computeRenderNodeUsage(RenderNode node, GfxInfo info) {
9795         if (node == null) return;
9796         info.renderNodeMemoryUsage += node.computeApproximateMemoryUsage();
9797         info.renderNodeMemoryAllocated += node.computeApproximateMemoryAllocated();
9798     }
9799 
appendGfxInfo(View view, GfxInfo info)9800     private static void appendGfxInfo(View view, GfxInfo info) {
9801         info.viewCount++;
9802         computeRenderNodeUsage(view.mRenderNode, info);
9803         computeRenderNodeUsage(view.mBackgroundRenderNode, info);
9804         if (view instanceof ViewGroup) {
9805             ViewGroup group = (ViewGroup) view;
9806 
9807             int count = group.getChildCount();
9808             for (int i = 0; i < count; i++) {
9809                 appendGfxInfo(group.getChildAt(i), info);
9810             }
9811         }
9812     }
9813 
9814     /**
9815      * @param immediate True, do now if not in traversal. False, put on queue and do later.
9816      * @return True, request has been queued. False, request has been completed.
9817      */
die(boolean immediate)9818     boolean die(boolean immediate) {
9819         // Make sure we do execute immediately if we are in the middle of a traversal or the damage
9820         // done by dispatchDetachedFromWindow will cause havoc on return.
9821         if (immediate && !mIsInTraversal) {
9822             doDie();
9823             return false;
9824         }
9825 
9826         if (!mIsDrawing) {
9827             destroyHardwareRenderer();
9828         } else {
9829             Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
9830                     "  window=" + this + ", title=" + mWindowAttributes.getTitle());
9831         }
9832         mHandler.sendEmptyMessage(MSG_DIE);
9833         return true;
9834     }
9835 
doDie()9836     void doDie() {
9837         checkThread();
9838         if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
9839         synchronized (this) {
9840             if (mRemoved) {
9841                 return;
9842             }
9843             mRemoved = true;
9844             mOnBackInvokedDispatcher.detachFromWindow();
9845             removeVrrMessages();
9846 
9847             if (mAdded) {
9848                 dispatchDetachedFromWindow();
9849             }
9850 
9851             if (mAdded && !mFirst) {
9852                 destroyHardwareRenderer();
9853 
9854                 if (mView != null) {
9855                     int viewVisibility = mView.getVisibility();
9856                     boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
9857                     if (mWindowAttributesChanged || viewVisibilityChanged) {
9858                         // If layout params have been changed, first give them
9859                         // to the window manager to make sure it has the correct
9860                         // animation info.
9861                         try {
9862                             if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
9863                                     & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
9864                                 mWindowSession.finishDrawing(
9865                                     mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
9866                             }
9867                         } catch (RemoteException e) {
9868                         }
9869                     }
9870 
9871                     destroySurface();
9872                 }
9873             }
9874 
9875             // If our window is removed, we might not get notified about losing control.
9876             // Invoking this can release the leashes as soon as possible instead of relying on GC.
9877             mInsetsController.onControlsChanged(null);
9878 
9879             mAdded = false;
9880             AnimationHandler.removeRequestor(this);
9881         }
9882         handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
9883                 mPendingTransaction, "shutting down VRI");
9884         WindowManagerGlobal.getInstance().doRemoveView(this);
9885     }
9886 
requestUpdateConfiguration(Configuration config)9887     public void requestUpdateConfiguration(Configuration config) {
9888         Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
9889         mHandler.sendMessage(msg);
9890     }
9891 
loadSystemProperties()9892     public void loadSystemProperties() {
9893         mHandler.post(new Runnable() {
9894             @Override
9895             public void run() {
9896                 // Profiling
9897                 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
9898                 profileRendering(mAttachInfo.mHasWindowFocus);
9899 
9900                 // Hardware rendering
9901                 if (mAttachInfo.mThreadedRenderer != null) {
9902                     if (mAttachInfo.mThreadedRenderer.loadSystemProperties()) {
9903                         invalidate();
9904                     }
9905                 }
9906 
9907                 // Layout debugging
9908                 boolean layout = DisplayProperties.debug_layout().orElse(false);
9909                 if (layout != mAttachInfo.mDebugLayout) {
9910                     mAttachInfo.mDebugLayout = layout;
9911                     if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
9912                         mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
9913                     }
9914                 }
9915             }
9916         });
9917     }
9918 
destroyHardwareRenderer()9919     private void destroyHardwareRenderer() {
9920         ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
9921 
9922         mHdrRenderState.stopListening();
9923 
9924         if (hardwareRenderer != null) {
9925             if (mHardwareRendererObserver != null) {
9926                 hardwareRenderer.removeObserver(mHardwareRendererObserver);
9927             }
9928             if (mView != null) {
9929                 hardwareRenderer.destroyHardwareResources(mView);
9930             }
9931             hardwareRenderer.destroy();
9932             hardwareRenderer.setRequested(false);
9933 
9934             mAttachInfo.mThreadedRenderer = null;
9935             mAttachInfo.mHardwareAccelerated = false;
9936         }
9937     }
9938 
9939     @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)9940     private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
9941             MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
9942             boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing,
9943             @Nullable ActivityWindowInfo activityWindowInfo) {
9944         Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
9945         SomeArgs args = SomeArgs.obtain();
9946         args.arg1 = frames;
9947         args.arg2 = mergedConfiguration;
9948         args.arg3 = insetsState;
9949         args.arg4 = activityWindowInfo;
9950         args.argi1 = forceLayout ? 1 : 0;
9951         args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
9952         args.argi3 = displayId;
9953         args.argi4 = syncSeqId;
9954         args.argi5 = dragResizing ? 1 : 0;
9955 
9956         msg.obj = args;
9957         mHandler.sendMessage(msg);
9958     }
9959 
dispatchInsetsControlChanged(@onNull InsetsState insetsState, @NonNull InsetsSourceControl.Array activeControls)9960     private void dispatchInsetsControlChanged(@NonNull InsetsState insetsState,
9961             @NonNull InsetsSourceControl.Array activeControls) {
9962         final SomeArgs args = SomeArgs.obtain();
9963         args.arg1 = insetsState;
9964         args.arg2 = activeControls;
9965         mHandler.obtainMessage(MSG_INSETS_CONTROL_CHANGED, args).sendToTarget();
9966     }
9967 
showInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)9968     private void showInsets(@InsetsType int types, boolean fromIme,
9969             @Nullable ImeTracker.Token statsToken) {
9970         mHandler.obtainMessage(MSG_SHOW_INSETS, types, fromIme ? 1 : 0, statsToken).sendToTarget();
9971     }
9972 
hideInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)9973     private void hideInsets(@InsetsType int types, boolean fromIme,
9974             @Nullable ImeTracker.Token statsToken) {
9975         mHandler.obtainMessage(MSG_HIDE_INSETS, types, fromIme ? 1 : 0, statsToken).sendToTarget();
9976     }
9977 
dispatchMoved(int newX, int newY)9978     public void dispatchMoved(int newX, int newY) {
9979         if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
9980         if (mTranslator != null) {
9981             PointF point = new PointF(newX, newY);
9982             mTranslator.translatePointInScreenToAppWindow(point);
9983             newX = (int) (point.x + 0.5);
9984             newY = (int) (point.y + 0.5);
9985         }
9986         Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
9987         mHandler.sendMessage(msg);
9988     }
9989 
9990     /**
9991      * Represents a pending input event that is waiting in a queue.
9992      *
9993      * Input events are processed in serial order by the timestamp specified by
9994      * {@link InputEvent#getEventTimeNanos()}.  In general, the input dispatcher delivers
9995      * one input event to the application at a time and waits for the application
9996      * to finish handling it before delivering the next one.
9997      *
9998      * However, because the application or IME can synthesize and inject multiple
9999      * key events at a time without going through the input dispatcher, we end up
10000      * needing a queue on the application's side.
10001      */
10002     private static final class QueuedInputEvent {
10003         public static final int FLAG_DELIVER_POST_IME = 1 << 0;
10004         public static final int FLAG_DEFERRED = 1 << 1;
10005         public static final int FLAG_FINISHED = 1 << 2;
10006         public static final int FLAG_FINISHED_HANDLED = 1 << 3;
10007         public static final int FLAG_RESYNTHESIZED = 1 << 4;
10008         public static final int FLAG_UNHANDLED = 1 << 5;
10009         public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6;
10010 
10011         public QueuedInputEvent mNext;
10012 
10013         public InputEvent mEvent;
10014         public InputEventReceiver mReceiver;
10015         public int mFlags;
10016 
shouldSkipIme()10017         public boolean shouldSkipIme() {
10018             if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
10019                 return true;
10020             }
10021             return mEvent instanceof MotionEvent
10022                     && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER));
10023         }
10024 
shouldSendToSynthesizer()10025         public boolean shouldSendToSynthesizer() {
10026             if ((mFlags & FLAG_UNHANDLED) != 0) {
10027                 return true;
10028             }
10029 
10030             return false;
10031         }
10032 
10033         @Override
toString()10034         public String toString() {
10035             StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
10036             boolean hasPrevious = false;
10037             hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
10038             hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
10039             hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
10040             hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
10041             hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
10042             hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
10043             if (!hasPrevious) {
10044                 sb.append("0");
10045             }
10046             sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
10047             sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
10048             sb.append(", mEvent=" + mEvent + "}");
10049             return sb.toString();
10050         }
10051 
flagToString(String name, int flag, boolean hasPrevious, StringBuilder sb)10052         private boolean flagToString(String name, int flag,
10053                 boolean hasPrevious, StringBuilder sb) {
10054             if ((mFlags & flag) != 0) {
10055                 if (hasPrevious) {
10056                     sb.append("|");
10057                 }
10058                 sb.append(name);
10059                 return true;
10060             }
10061             return hasPrevious;
10062         }
10063     }
10064 
obtainQueuedInputEvent(InputEvent event, InputEventReceiver receiver, int flags)10065     private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
10066             InputEventReceiver receiver, int flags) {
10067         QueuedInputEvent q = mQueuedInputEventPool;
10068         if (q != null) {
10069             mQueuedInputEventPoolSize -= 1;
10070             mQueuedInputEventPool = q.mNext;
10071             q.mNext = null;
10072         } else {
10073             q = new QueuedInputEvent();
10074         }
10075 
10076         q.mEvent = event;
10077         q.mReceiver = receiver;
10078         q.mFlags = flags;
10079         return q;
10080     }
10081 
recycleQueuedInputEvent(QueuedInputEvent q)10082     private void recycleQueuedInputEvent(QueuedInputEvent q) {
10083         q.mEvent = null;
10084         q.mReceiver = null;
10085 
10086         if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
10087             mQueuedInputEventPoolSize += 1;
10088             q.mNext = mQueuedInputEventPool;
10089             mQueuedInputEventPool = q;
10090         }
10091     }
10092 
10093     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
enqueueInputEvent(InputEvent event)10094     public void enqueueInputEvent(InputEvent event) {
10095         enqueueInputEvent(event, null, 0, false);
10096     }
10097 
10098     @UnsupportedAppUsage
enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately)10099     void enqueueInputEvent(InputEvent event,
10100             InputEventReceiver receiver, int flags, boolean processImmediately) {
10101         QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
10102 
10103         if (event instanceof MotionEvent) {
10104             MotionEvent me = (MotionEvent) event;
10105             if (me.getAction() == MotionEvent.ACTION_CANCEL) {
10106                 EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Motion - Cancel",
10107                         getTitle().toString());
10108             }
10109         } else if (event instanceof KeyEvent) {
10110             KeyEvent ke = (KeyEvent) event;
10111             if (ke.isCanceled()) {
10112                 EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Key - Cancel",
10113                         getTitle().toString());
10114             }
10115         }
10116         // Always enqueue the input event in order, regardless of its time stamp.
10117         // We do this because the application or the IME may inject key events
10118         // in response to touch events and we want to ensure that the injected keys
10119         // are processed in the order they were received and we cannot trust that
10120         // the time stamp of injected events are monotonic.
10121         QueuedInputEvent last = mPendingInputEventTail;
10122         if (last == null) {
10123             mPendingInputEventHead = q;
10124             mPendingInputEventTail = q;
10125         } else {
10126             last.mNext = q;
10127             mPendingInputEventTail = q;
10128         }
10129         mPendingInputEventCount += 1;
10130         Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
10131                 mPendingInputEventCount);
10132 
10133         if (processImmediately) {
10134             doProcessInputEvents();
10135         } else {
10136             scheduleProcessInputEvents();
10137         }
10138     }
10139 
scheduleProcessInputEvents()10140     private void scheduleProcessInputEvents() {
10141         if (!mProcessInputEventsScheduled) {
10142             mProcessInputEventsScheduled = true;
10143             Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
10144             msg.setAsynchronous(true);
10145             mHandler.sendMessage(msg);
10146         }
10147     }
10148 
doProcessInputEvents()10149     void doProcessInputEvents() {
10150         // Deliver all pending input events in the queue.
10151         while (mPendingInputEventHead != null) {
10152             QueuedInputEvent q = mPendingInputEventHead;
10153             mPendingInputEventHead = q.mNext;
10154             if (mPendingInputEventHead == null) {
10155                 mPendingInputEventTail = null;
10156             }
10157             q.mNext = null;
10158 
10159             mPendingInputEventCount -= 1;
10160             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
10161                     mPendingInputEventCount);
10162 
10163             mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
10164 
10165             deliverInputEvent(q);
10166         }
10167 
10168         // We are done processing all input events that we can process right now
10169         // so we can clear the pending flag immediately.
10170         if (mProcessInputEventsScheduled) {
10171             mProcessInputEventsScheduled = false;
10172             mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
10173         }
10174     }
10175 
deliverInputEvent(QueuedInputEvent q)10176     private void deliverInputEvent(QueuedInputEvent q) {
10177         Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
10178                 q.mEvent.getId());
10179 
10180         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
10181             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x"
10182                     + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano="
10183                     + q.mEvent.getEventTimeNanos() + " id=0x"
10184                     + Integer.toHexString(q.mEvent.getId()));
10185         }
10186         try {
10187             if (mInputEventConsistencyVerifier != null) {
10188                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency");
10189                 try {
10190                     mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
10191                 } finally {
10192                     Trace.traceEnd(Trace.TRACE_TAG_VIEW);
10193                 }
10194             }
10195 
10196             InputStage stage;
10197             if (q.shouldSendToSynthesizer()) {
10198                 stage = mSyntheticInputStage;
10199             } else {
10200                 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
10201             }
10202 
10203             if (q.mEvent instanceof KeyEvent) {
10204                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager");
10205                 try {
10206                     mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
10207                 } finally {
10208                     Trace.traceEnd(Trace.TRACE_TAG_VIEW);
10209                 }
10210             }
10211 
10212             if (stage != null) {
10213                 handleWindowFocusChanged();
10214                 stage.deliver(q);
10215             } else {
10216                 finishInputEvent(q);
10217             }
10218         } finally {
10219             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
10220         }
10221     }
10222 
finishInputEvent(QueuedInputEvent q)10223     private void finishInputEvent(QueuedInputEvent q) {
10224         Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
10225                 q.mEvent.getId());
10226 
10227         if (q.mReceiver != null) {
10228             boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
10229             boolean modified = (q.mFlags & QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY) != 0;
10230             if (modified) {
10231                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventBeforeFinish");
10232                 InputEvent processedEvent;
10233                 try {
10234                     processedEvent =
10235                             mInputCompatProcessor.processInputEventBeforeFinish(q.mEvent);
10236                 } finally {
10237                     Trace.traceEnd(Trace.TRACE_TAG_VIEW);
10238                 }
10239                 if (processedEvent != null) {
10240                     q.mReceiver.finishInputEvent(processedEvent, handled);
10241                 }
10242             } else {
10243                 q.mReceiver.finishInputEvent(q.mEvent, handled);
10244             }
10245             if (q.mEvent instanceof KeyEvent) {
10246                 logHandledSystemKey((KeyEvent) q.mEvent, handled);
10247             }
10248         } else {
10249             q.mEvent.recycleIfNeededAfterDispatch();
10250         }
10251 
10252         recycleQueuedInputEvent(q);
10253     }
10254 
logHandledSystemKey(KeyEvent event, boolean handled)10255     private void logHandledSystemKey(KeyEvent event, boolean handled) {
10256         final int keyCode = event.getKeyCode();
10257         if (keyCode != KeyEvent.KEYCODE_STEM_PRIMARY) {
10258             return;
10259         }
10260         if (event.isDown() && event.getRepeatCount() == 0 && handled) {
10261             // Initial DOWN event is handled. Log the stem primary key press.
10262             Counter.logIncrementWithUid(
10263                     "input.value_app_handled_stem_primary_key_gestures_count",
10264                     Process.myUid());
10265         }
10266     }
10267 
isTerminalInputEvent(InputEvent event)10268     static boolean isTerminalInputEvent(InputEvent event) {
10269         if (event instanceof KeyEvent) {
10270             final KeyEvent keyEvent = (KeyEvent)event;
10271             return keyEvent.getAction() == KeyEvent.ACTION_UP;
10272         } else {
10273             final MotionEvent motionEvent = (MotionEvent)event;
10274             final int action = motionEvent.getAction();
10275             return action == MotionEvent.ACTION_UP
10276                     || action == MotionEvent.ACTION_CANCEL
10277                     || action == MotionEvent.ACTION_HOVER_EXIT;
10278         }
10279     }
10280 
scheduleConsumeBatchedInput()10281     void scheduleConsumeBatchedInput() {
10282         // If anything is currently scheduled to consume batched input then there's no point in
10283         // scheduling it again.
10284         if (!mConsumeBatchedInputScheduled && !mConsumeBatchedInputImmediatelyScheduled) {
10285             mConsumeBatchedInputScheduled = true;
10286             mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
10287                     mConsumedBatchedInputRunnable, null);
10288             if (mAttachInfo.mThreadedRenderer != null) {
10289                 mAttachInfo.mThreadedRenderer.notifyCallbackPending();
10290             }
10291         }
10292     }
10293 
unscheduleConsumeBatchedInput()10294     void unscheduleConsumeBatchedInput() {
10295         if (mConsumeBatchedInputScheduled) {
10296             mConsumeBatchedInputScheduled = false;
10297             mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
10298                     mConsumedBatchedInputRunnable, null);
10299         }
10300     }
10301 
scheduleConsumeBatchedInputImmediately()10302     void scheduleConsumeBatchedInputImmediately() {
10303         if (!mConsumeBatchedInputImmediatelyScheduled) {
10304             unscheduleConsumeBatchedInput();
10305             mConsumeBatchedInputImmediatelyScheduled = true;
10306             mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
10307         }
10308     }
10309 
doConsumeBatchedInput(long frameTimeNanos)10310     boolean doConsumeBatchedInput(long frameTimeNanos) {
10311         final boolean consumedBatches;
10312         if (mInputEventReceiver != null) {
10313             consumedBatches = mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos);
10314         } else {
10315             consumedBatches = false;
10316         }
10317         doProcessInputEvents();
10318         return consumedBatches;
10319     }
10320 
10321     final class TraversalRunnable implements Runnable {
10322         @Override
run()10323         public void run() {
10324             doTraversal();
10325         }
10326     }
10327     final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
10328 
10329     final class WindowInputEventReceiver extends InputEventReceiver {
WindowInputEventReceiver(InputChannel inputChannel, Looper looper)10330         public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
10331             super(inputChannel, looper);
10332         }
10333 
10334         @Override
onInputEvent(InputEvent event)10335         public void onInputEvent(InputEvent event) {
10336             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
10337             List<InputEvent> processedEvents;
10338             try {
10339                 processedEvents =
10340                     mInputCompatProcessor.processInputEventForCompatibility(event);
10341             } finally {
10342                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
10343             }
10344             if (processedEvents != null) {
10345                 if (processedEvents.isEmpty()) {
10346                     // InputEvent consumed by mInputCompatProcessor
10347                     finishInputEvent(event, true);
10348                 } else {
10349                     for (int i = 0; i < processedEvents.size(); i++) {
10350                         enqueueInputEvent(
10351                                 processedEvents.get(i), this,
10352                                 QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
10353                     }
10354                 }
10355             } else {
10356                 enqueueInputEvent(event, this, 0, true);
10357             }
10358         }
10359 
10360         @Override
onBatchedInputEventPending(int source)10361         public void onBatchedInputEventPending(int source) {
10362             final boolean unbuffered = mUnbufferedInputDispatch
10363                     || (source & mUnbufferedInputSource) != SOURCE_CLASS_NONE;
10364             if (unbuffered) {
10365                 if (mConsumeBatchedInputScheduled) {
10366                     unscheduleConsumeBatchedInput();
10367                 }
10368                 // Consume event immediately if unbuffered input dispatch has been requested.
10369                 consumeBatchedInputEvents(-1);
10370                 return;
10371             }
10372             scheduleConsumeBatchedInput();
10373         }
10374 
10375         @Override
onFocusEvent(boolean hasFocus)10376         public void onFocusEvent(boolean hasFocus) {
10377             windowFocusChanged(hasFocus);
10378         }
10379 
10380         @Override
onTouchModeChanged(boolean inTouchMode)10381         public void onTouchModeChanged(boolean inTouchMode) {
10382             touchModeChanged(inTouchMode);
10383         }
10384 
10385         @Override
onPointerCaptureEvent(boolean pointerCaptureEnabled)10386         public void onPointerCaptureEvent(boolean pointerCaptureEnabled) {
10387             dispatchPointerCaptureChanged(pointerCaptureEnabled);
10388         }
10389 
10390         @Override
onDragEvent(boolean isExiting, float x, float y)10391         public void onDragEvent(boolean isExiting, float x, float y) {
10392             // force DRAG_EXITED_EVENT if appropriate
10393             DragEvent event = DragEvent.obtain(
10394                     isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION,
10395                     x, y, 0 /* offsetX */, 0 /* offsetY */, 0 /* flags */, null/* localState */,
10396                     null/* description */, null /* data */, null /* dragSurface */,
10397                     null /* dragAndDropPermissions */, false /* result */);
10398             dispatchDragEvent(event);
10399         }
10400 
10401         @Override
dispose()10402         public void dispose() {
10403             unscheduleConsumeBatchedInput();
10404             super.dispose();
10405         }
10406     }
10407     private WindowInputEventReceiver mInputEventReceiver;
10408 
10409     final class InputMetricsListener
10410             implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
10411         public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT];
10412 
10413         @Override
onFrameMetricsAvailable(int dropCountSinceLastInvocation)10414         public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
10415             final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID];
10416             if (inputEventId == INVALID_INPUT_EVENT_ID) {
10417                 return;
10418             }
10419             final long presentTime = data[FrameMetrics.Index.DISPLAY_PRESENT_TIME];
10420             if (presentTime <= 0) {
10421                 // Present time is not available for this frame. If the present time is not
10422                 // available, we cannot compute end-to-end input latency metrics.
10423                 return;
10424             }
10425             final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED];
10426             if (mInputEventReceiver == null) {
10427                 return;
10428             }
10429             if (gpuCompletedTime >= presentTime) {
10430                 final double discrepancyMs = (gpuCompletedTime - presentTime) * 1E-6;
10431                 final long vsyncId = data[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID];
10432                 Log.w(TAG, "Not reporting timeline because gpuCompletedTime is " + discrepancyMs
10433                         + "ms ahead of presentTime. FRAME_TIMELINE_VSYNC_ID=" + vsyncId
10434                         + ", INPUT_EVENT_ID=" + inputEventId);
10435                 // TODO(b/186664409): figure out why this sometimes happens
10436                 return;
10437             }
10438             mInputEventReceiver.reportTimeline(inputEventId, gpuCompletedTime, presentTime);
10439         }
10440     }
10441     HardwareRendererObserver mHardwareRendererObserver;
10442 
10443     final class ConsumeBatchedInputRunnable implements Runnable {
10444         @Override
run()10445         public void run() {
10446             Trace.traceBegin(TRACE_TAG_VIEW, mTag);
10447             try {
10448                 mConsumeBatchedInputScheduled = false;
10449                 if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) {
10450                     // If we consumed a batch here, we want to go ahead and schedule the
10451                     // consumption of batched input events on the next frame. Otherwise, we would
10452                     // wait until we have more input events pending and might get starved by other
10453                     // things occurring in the process.
10454                     scheduleConsumeBatchedInput();
10455                 }
10456             } finally {
10457                 Trace.traceEnd(TRACE_TAG_VIEW);
10458             }
10459         }
10460     }
10461     final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
10462             new ConsumeBatchedInputRunnable();
10463     boolean mConsumeBatchedInputScheduled;
10464 
10465     final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
10466         @Override
run()10467         public void run() {
10468             mConsumeBatchedInputImmediatelyScheduled = false;
10469             doConsumeBatchedInput(-1);
10470         }
10471     }
10472     final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
10473             new ConsumeBatchedInputImmediatelyRunnable();
10474     boolean mConsumeBatchedInputImmediatelyScheduled;
10475 
10476     final class InvalidateOnAnimationRunnable implements Runnable {
10477         private boolean mPosted;
10478         private final ArrayList<View> mViews = new ArrayList<View>();
10479         private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
10480                 new ArrayList<AttachInfo.InvalidateInfo>();
10481         private View[] mTempViews;
10482         private AttachInfo.InvalidateInfo[] mTempViewRects;
10483 
addView(View view)10484         public void addView(View view) {
10485             synchronized (this) {
10486                 mViews.add(view);
10487                 postIfNeededLocked();
10488             }
10489             if (mAttachInfo.mThreadedRenderer != null) {
10490                 mAttachInfo.mThreadedRenderer.notifyCallbackPending();
10491             }
10492         }
10493 
addViewRect(AttachInfo.InvalidateInfo info)10494         public void addViewRect(AttachInfo.InvalidateInfo info) {
10495             synchronized (this) {
10496                 mViewRects.add(info);
10497                 postIfNeededLocked();
10498             }
10499             if (mAttachInfo.mThreadedRenderer != null) {
10500                 mAttachInfo.mThreadedRenderer.notifyCallbackPending();
10501             }
10502         }
10503 
removeView(View view)10504         public void removeView(View view) {
10505             synchronized (this) {
10506                 mViews.remove(view);
10507 
10508                 for (int i = mViewRects.size(); i-- > 0; ) {
10509                     AttachInfo.InvalidateInfo info = mViewRects.get(i);
10510                     if (info.target == view) {
10511                         mViewRects.remove(i);
10512                         info.recycle();
10513                     }
10514                 }
10515 
10516                 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
10517                     mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
10518                     mPosted = false;
10519                 }
10520             }
10521         }
10522 
10523         @Override
run()10524         public void run() {
10525             final int viewCount;
10526             final int viewRectCount;
10527             synchronized (this) {
10528                 mPosted = false;
10529 
10530                 viewCount = mViews.size();
10531                 if (viewCount != 0) {
10532                     mTempViews = mViews.toArray(mTempViews != null
10533                             ? mTempViews : new View[viewCount]);
10534                     mViews.clear();
10535                 }
10536 
10537                 viewRectCount = mViewRects.size();
10538                 if (viewRectCount != 0) {
10539                     mTempViewRects = mViewRects.toArray(mTempViewRects != null
10540                             ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
10541                     mViewRects.clear();
10542                 }
10543             }
10544 
10545             for (int i = 0; i < viewCount; i++) {
10546                 mTempViews[i].invalidate();
10547                 mTempViews[i] = null;
10548             }
10549 
10550             for (int i = 0; i < viewRectCount; i++) {
10551                 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
10552                 info.target.invalidate(info.left, info.top, info.right, info.bottom);
10553                 info.recycle();
10554             }
10555         }
10556 
postIfNeededLocked()10557         private void postIfNeededLocked() {
10558             if (!mPosted) {
10559                 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
10560                 mPosted = true;
10561             }
10562         }
10563     }
10564     final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
10565             new InvalidateOnAnimationRunnable();
10566 
dispatchInvalidateDelayed(View view, long delayMilliseconds)10567     public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
10568         Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
10569         mHandler.sendMessageDelayed(msg, delayMilliseconds);
10570     }
10571 
dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, long delayMilliseconds)10572     public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
10573             long delayMilliseconds) {
10574         final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
10575         mHandler.sendMessageDelayed(msg, delayMilliseconds);
10576     }
10577 
dispatchInvalidateOnAnimation(View view)10578     public void dispatchInvalidateOnAnimation(View view) {
10579         mInvalidateOnAnimationRunnable.addView(view);
10580     }
10581 
dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info)10582     public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
10583         mInvalidateOnAnimationRunnable.addViewRect(info);
10584     }
10585 
10586     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
cancelInvalidate(View view)10587     public void cancelInvalidate(View view) {
10588         mHandler.removeMessages(MSG_INVALIDATE, view);
10589         // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
10590         // them to the pool
10591         mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
10592         mInvalidateOnAnimationRunnable.removeView(view);
10593     }
10594 
10595     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
dispatchInputEvent(InputEvent event)10596     public void dispatchInputEvent(InputEvent event) {
10597         dispatchInputEvent(event, null);
10598     }
10599 
10600     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
dispatchInputEvent(InputEvent event, InputEventReceiver receiver)10601     public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
10602         SomeArgs args = SomeArgs.obtain();
10603         args.arg1 = event;
10604         args.arg2 = receiver;
10605         Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
10606         msg.setAsynchronous(true);
10607         mHandler.sendMessage(msg);
10608     }
10609 
synthesizeInputEvent(InputEvent event)10610     public void synthesizeInputEvent(InputEvent event) {
10611         Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
10612         msg.setAsynchronous(true);
10613         mHandler.sendMessage(msg);
10614     }
10615 
10616     @UnsupportedAppUsage
dispatchKeyFromIme(KeyEvent event)10617     public void dispatchKeyFromIme(KeyEvent event) {
10618         Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
10619         msg.setAsynchronous(true);
10620         mHandler.sendMessage(msg);
10621     }
10622 
dispatchKeyFromAutofill(KeyEvent event)10623     public void dispatchKeyFromAutofill(KeyEvent event) {
10624         Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event);
10625         msg.setAsynchronous(true);
10626         mHandler.sendMessage(msg);
10627     }
10628 
10629     /**
10630      * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
10631      *
10632      * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
10633      * passes in.
10634      */
10635     @UnsupportedAppUsage
dispatchUnhandledInputEvent(InputEvent event)10636     public void dispatchUnhandledInputEvent(InputEvent event) {
10637         if (event instanceof MotionEvent) {
10638             event = MotionEvent.obtain((MotionEvent) event);
10639         }
10640         synthesizeInputEvent(event);
10641     }
10642 
dispatchAppVisibility(boolean visible)10643     public void dispatchAppVisibility(boolean visible) {
10644         Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
10645         msg.arg1 = visible ? 1 : 0;
10646         mHandler.sendMessage(msg);
10647     }
10648 
dispatchGetNewSurface()10649     public void dispatchGetNewSurface() {
10650         Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
10651         mHandler.sendMessage(msg);
10652     }
10653 
10654     /**
10655      * Notifies this {@link ViewRootImpl} object that window focus has changed.
10656      */
windowFocusChanged(boolean hasFocus)10657     public void windowFocusChanged(boolean hasFocus) {
10658         synchronized (this) {
10659             mWindowFocusChanged = true;
10660             mUpcomingWindowFocus = hasFocus;
10661         }
10662         Message msg = Message.obtain();
10663         msg.what = MSG_WINDOW_FOCUS_CHANGED;
10664         mHandler.sendMessage(msg);
10665     }
10666 
10667     /**
10668      * Notifies this {@link ViewRootImpl} object that touch mode state has changed.
10669      */
touchModeChanged(boolean inTouchMode)10670     public void touchModeChanged(boolean inTouchMode) {
10671         synchronized (this) {
10672             mUpcomingInTouchMode = inTouchMode;
10673         }
10674         Message msg = Message.obtain();
10675         msg.what = MSG_WINDOW_TOUCH_MODE_CHANGED;
10676         mHandler.sendMessage(msg);
10677     }
10678 
dispatchWindowShown()10679     public void dispatchWindowShown() {
10680         mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
10681     }
10682 
dispatchCloseSystemDialogs(String reason)10683     public void dispatchCloseSystemDialogs(String reason) {
10684         Message msg = Message.obtain();
10685         msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
10686         msg.obj = reason;
10687         mHandler.sendMessage(msg);
10688     }
10689 
dispatchDragEvent(DragEvent event)10690     public void dispatchDragEvent(DragEvent event) {
10691         final int what;
10692         if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
10693             what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
10694             mHandler.removeMessages(what);
10695         } else {
10696             what = MSG_DISPATCH_DRAG_EVENT;
10697         }
10698         Message msg = mHandler.obtainMessage(what, event);
10699         mHandler.sendMessage(msg);
10700     }
10701 
dispatchCheckFocus()10702     public void dispatchCheckFocus() {
10703         if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
10704             // This will result in a call to checkFocus() below.
10705             mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
10706         }
10707     }
10708 
dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)10709     public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
10710         mHandler.obtainMessage(
10711                 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
10712     }
10713 
dispatchPointerCaptureChanged(boolean on)10714     private void dispatchPointerCaptureChanged(boolean on) {
10715         final int what = MSG_POINTER_CAPTURE_CHANGED;
10716         mHandler.removeMessages(what);
10717         Message msg = mHandler.obtainMessage(what);
10718         msg.arg1 = on ? 1 : 0;
10719         mHandler.sendMessage(msg);
10720     }
10721 
10722     /**
10723      * Post a callback to send a
10724      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
10725      * This event is send at most once every
10726      * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
10727      */
postSendWindowContentChangedCallback(View source, int changeType)10728     private void postSendWindowContentChangedCallback(View source, int changeType) {
10729         if (mSendWindowContentChangedAccessibilityEvent == null) {
10730             mSendWindowContentChangedAccessibilityEvent =
10731                 new SendWindowContentChangedAccessibilityEvent();
10732         }
10733         mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
10734     }
10735 
10736     /**
10737      * Remove a posted callback to send a
10738      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
10739      */
removeSendWindowContentChangedCallback()10740     private void removeSendWindowContentChangedCallback() {
10741         if (mSendWindowContentChangedAccessibilityEvent != null) {
10742             mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
10743         }
10744     }
10745 
10746     /**
10747      * Return the connection ID for the {@link AccessibilityInteractionController} of this instance.
10748      * @see AccessibilityNodeInfo#setQueryFromAppProcessEnabled
10749      */
getDirectAccessibilityConnectionId()10750     public int getDirectAccessibilityConnectionId() {
10751         return mAccessibilityInteractionConnectionManager.ensureDirectConnection();
10752     }
10753 
10754     @Override
showContextMenuForChild(View originalView)10755     public boolean showContextMenuForChild(View originalView) {
10756         return false;
10757     }
10758 
10759     @Override
showContextMenuForChild(View originalView, float x, float y)10760     public boolean showContextMenuForChild(View originalView, float x, float y) {
10761         return false;
10762     }
10763 
10764     @Override
startActionModeForChild(View originalView, ActionMode.Callback callback)10765     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
10766         return null;
10767     }
10768 
10769     @Override
startActionModeForChild( View originalView, ActionMode.Callback callback, int type)10770     public ActionMode startActionModeForChild(
10771             View originalView, ActionMode.Callback callback, int type) {
10772         return null;
10773     }
10774 
10775     @Override
createContextMenu(ContextMenu menu)10776     public void createContextMenu(ContextMenu menu) {
10777     }
10778 
10779     @Override
childDrawableStateChanged(View child)10780     public void childDrawableStateChanged(View child) {
10781     }
10782 
10783     @Override
requestSendAccessibilityEvent(View child, AccessibilityEvent event)10784     public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
10785         if (mView == null || mStopped || mPausedForTransition) {
10786             return false;
10787         }
10788 
10789         // Immediately flush pending content changed event (if any) to preserve event order
10790         if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
10791                 && mSendWindowContentChangedAccessibilityEvent != null
10792                 && mSendWindowContentChangedAccessibilityEvent.mSource != null) {
10793             mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun();
10794         }
10795 
10796         // Intercept accessibility focus events fired by virtual nodes to keep
10797         // track of accessibility focus position in such nodes.
10798         final int eventType = event.getEventType();
10799         final View source = getSourceForAccessibilityEvent(event);
10800         switch (eventType) {
10801             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
10802                 if (source != null) {
10803                     AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
10804                     if (provider != null) {
10805                         final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
10806                                 event.getSourceNodeId());
10807                         final AccessibilityNodeInfo node;
10808                         node = provider.createAccessibilityNodeInfo(virtualNodeId);
10809                         setAccessibilityFocus(source, node);
10810                     }
10811                 }
10812             } break;
10813             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
10814                 if (source != null && source.getAccessibilityNodeProvider() != null) {
10815                     setAccessibilityFocus(null, null);
10816                 }
10817             } break;
10818 
10819 
10820             case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
10821                 handleWindowContentChangedEvent(event);
10822             } break;
10823         }
10824         mAccessibilityManager.sendAccessibilityEvent(event);
10825         return true;
10826     }
10827 
getSourceForAccessibilityEvent(AccessibilityEvent event)10828     private View getSourceForAccessibilityEvent(AccessibilityEvent event) {
10829         final long sourceNodeId = event.getSourceNodeId();
10830         final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
10831                 sourceNodeId);
10832         return AccessibilityNodeIdManager.getInstance().findView(accessibilityViewId);
10833     }
10834 
isAccessibilityFocusDirty()10835     private boolean isAccessibilityFocusDirty() {
10836         final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
10837         if (drawable != null) {
10838             final Rect bounds = mAttachInfo.mTmpInvalRect;
10839             final boolean hasFocus = getAccessibilityFocusedRect(bounds);
10840             if (!hasFocus) {
10841                 bounds.setEmpty();
10842             }
10843             if (!bounds.equals(drawable.getBounds())) {
10844                 return true;
10845             }
10846         }
10847         return false;
10848     }
10849 
10850     /**
10851      * Updates the focused virtual view, when necessary, in response to a
10852      * content changed event.
10853      * <p>
10854      * This is necessary to get updated bounds after a position change.
10855      *
10856      * @param event an accessibility event of type
10857      *              {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
10858      */
handleWindowContentChangedEvent(AccessibilityEvent event)10859     private void handleWindowContentChangedEvent(AccessibilityEvent event) {
10860         final View focusedHost = mAccessibilityFocusedHost;
10861         if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
10862             // No virtual view focused, nothing to do here.
10863             return;
10864         }
10865 
10866         final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
10867         if (provider == null) {
10868             // Error state: virtual view with no provider. Clear focus.
10869             mAccessibilityFocusedHost = null;
10870             mAccessibilityFocusedVirtualView = null;
10871             focusedHost.clearAccessibilityFocusNoCallbacks(0);
10872             return;
10873         }
10874 
10875         // We only care about change types that may affect the bounds of the
10876         // focused virtual view.
10877         final int changes = event.getContentChangeTypes();
10878         if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
10879                 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
10880             return;
10881         }
10882 
10883         final long eventSourceNodeId = event.getSourceNodeId();
10884         final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
10885 
10886         // Search up the tree for subtree containment.
10887         boolean hostInSubtree = false;
10888         View root = mAccessibilityFocusedHost;
10889         while (root != null && !hostInSubtree) {
10890             if (changedViewId == root.getAccessibilityViewId()) {
10891                 hostInSubtree = true;
10892             } else {
10893                 final ViewParent parent = root.getParent();
10894                 if (parent instanceof View) {
10895                     root = (View) parent;
10896                 } else {
10897                     root = null;
10898                 }
10899             }
10900         }
10901 
10902         // We care only about changes in subtrees containing the host view.
10903         if (!hostInSubtree) {
10904             return;
10905         }
10906 
10907         final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
10908         int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
10909 
10910         // Refresh the node for the focused virtual view.
10911         final Rect oldBounds = mTempRect;
10912         mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
10913         mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
10914         if (mAccessibilityFocusedVirtualView == null) {
10915             // Error state: The node no longer exists. Clear focus.
10916             mAccessibilityFocusedHost = null;
10917             focusedHost.clearAccessibilityFocusNoCallbacks(0);
10918 
10919             // This will probably fail, but try to keep the provider's internal
10920             // state consistent by clearing focus.
10921             provider.performAction(focusedChildId,
10922                     AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
10923             invalidateRectOnScreen(oldBounds);
10924         } else {
10925             // The node was refreshed, invalidate bounds if necessary.
10926             final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
10927             if (!oldBounds.equals(newBounds)) {
10928                 oldBounds.union(newBounds);
10929                 invalidateRectOnScreen(oldBounds);
10930             }
10931         }
10932     }
10933 
10934     @Override
notifySubtreeAccessibilityStateChanged(View child, View source, int changeType)10935     public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
10936         postSendWindowContentChangedCallback(Objects.requireNonNull(source), changeType);
10937     }
10938 
10939     @Override
canResolveLayoutDirection()10940     public boolean canResolveLayoutDirection() {
10941         return true;
10942     }
10943 
10944     @Override
isLayoutDirectionResolved()10945     public boolean isLayoutDirectionResolved() {
10946         return true;
10947     }
10948 
10949     @Override
getLayoutDirection()10950     public int getLayoutDirection() {
10951         return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
10952     }
10953 
10954     @Override
canResolveTextDirection()10955     public boolean canResolveTextDirection() {
10956         return true;
10957     }
10958 
10959     @Override
isTextDirectionResolved()10960     public boolean isTextDirectionResolved() {
10961         return true;
10962     }
10963 
10964     @Override
getTextDirection()10965     public int getTextDirection() {
10966         return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
10967     }
10968 
10969     @Override
canResolveTextAlignment()10970     public boolean canResolveTextAlignment() {
10971         return true;
10972     }
10973 
10974     @Override
isTextAlignmentResolved()10975     public boolean isTextAlignmentResolved() {
10976         return true;
10977     }
10978 
10979     @Override
getTextAlignment()10980     public int getTextAlignment() {
10981         return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
10982     }
10983 
getCommonPredecessor(View first, View second)10984     private View getCommonPredecessor(View first, View second) {
10985         if (mTempHashSet == null) {
10986             mTempHashSet = new HashSet<View>();
10987         }
10988         HashSet<View> seen = mTempHashSet;
10989         seen.clear();
10990         View firstCurrent = first;
10991         while (firstCurrent != null) {
10992             seen.add(firstCurrent);
10993             ViewParent firstCurrentParent = firstCurrent.mParent;
10994             if (firstCurrentParent instanceof View) {
10995                 firstCurrent = (View) firstCurrentParent;
10996             } else {
10997                 firstCurrent = null;
10998             }
10999         }
11000         View secondCurrent = second;
11001         while (secondCurrent != null) {
11002             if (seen.contains(secondCurrent)) {
11003                 seen.clear();
11004                 return secondCurrent;
11005             }
11006             ViewParent secondCurrentParent = secondCurrent.mParent;
11007             if (secondCurrentParent instanceof View) {
11008                 secondCurrent = (View) secondCurrentParent;
11009             } else {
11010                 secondCurrent = null;
11011             }
11012         }
11013         seen.clear();
11014         return null;
11015     }
11016 
checkThread()11017     void checkThread() {
11018         Thread current = Thread.currentThread();
11019         if (mThread != current) {
11020             throw new CalledFromWrongThreadException(
11021                     "Only the original thread that created a view hierarchy can touch its views."
11022                             + " Expected: " + mThread.getName()
11023                             + " Calling: " + current.getName());
11024         }
11025     }
11026 
11027     @Override
requestDisallowInterceptTouchEvent(boolean disallowIntercept)11028     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
11029         // ViewAncestor never intercepts touch event, so this can be a no-op
11030     }
11031 
11032     @Override
requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)11033     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
11034         if (rectangle == null) {
11035             return scrollToRectOrFocus(null, immediate);
11036         }
11037         rectangle.offset(child.getLeft() - child.getScrollX(),
11038                 child.getTop() - child.getScrollY());
11039         final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
11040         mTempRect.set(rectangle);
11041         mTempRect.offset(0, -mCurScrollY);
11042         mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
11043         try {
11044             mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
11045         } catch (RemoteException re) {
11046             /* ignore */
11047         }
11048         return scrolled;
11049     }
11050 
11051     @Override
childHasTransientStateChanged(View child, boolean hasTransientState)11052     public void childHasTransientStateChanged(View child, boolean hasTransientState) {
11053         // Do nothing.
11054     }
11055 
11056     @Override
onStartNestedScroll(View child, View target, int nestedScrollAxes)11057     public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
11058         return false;
11059     }
11060 
11061     @Override
onStopNestedScroll(View target)11062     public void onStopNestedScroll(View target) {
11063     }
11064 
11065     @Override
onNestedScrollAccepted(View child, View target, int nestedScrollAxes)11066     public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
11067     }
11068 
11069     @Override
onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)11070     public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
11071             int dxUnconsumed, int dyUnconsumed) {
11072     }
11073 
11074     @Override
onNestedPreScroll(View target, int dx, int dy, int[] consumed)11075     public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
11076     }
11077 
11078     @Override
onNestedFling(View target, float velocityX, float velocityY, boolean consumed)11079     public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
11080         return false;
11081     }
11082 
11083     @Override
onNestedPreFling(View target, float velocityX, float velocityY)11084     public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
11085         return false;
11086     }
11087 
11088     @Override
onNestedPrePerformAccessibilityAction(View target, int action, Bundle args)11089     public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
11090         return false;
11091     }
11092 
11093     /**
11094      * Checks the input event receiver for input availability.
11095      * May return false negatives.
11096      * @hide
11097      */
probablyHasInput()11098     public boolean probablyHasInput() {
11099         if (mInputEventReceiver == null) {
11100             return false;
11101         }
11102         return mInputEventReceiver.probablyHasInput();
11103     }
11104 
11105     /**
11106      * Adds a scroll capture callback to this window.
11107      *
11108      * @param callback the callback to add
11109      */
addScrollCaptureCallback(ScrollCaptureCallback callback)11110     public void addScrollCaptureCallback(ScrollCaptureCallback callback) {
11111         if (mRootScrollCaptureCallbacks == null) {
11112             mRootScrollCaptureCallbacks = new HashSet<>();
11113         }
11114         mRootScrollCaptureCallbacks.add(callback);
11115     }
11116 
11117     /**
11118      * Removes a scroll capture callback from this window.
11119      *
11120      * @param callback the callback to remove
11121      */
removeScrollCaptureCallback(ScrollCaptureCallback callback)11122     public void removeScrollCaptureCallback(ScrollCaptureCallback callback) {
11123         if (mRootScrollCaptureCallbacks != null) {
11124             mRootScrollCaptureCallbacks.remove(callback);
11125             if (mRootScrollCaptureCallbacks.isEmpty()) {
11126                 mRootScrollCaptureCallbacks = null;
11127             }
11128         }
11129     }
11130 
11131     /**
11132      * Dispatches a scroll capture request to the view hierarchy on the ui thread.
11133      *
11134      * @param listener for the response
11135      */
dispatchScrollCaptureRequest(@onNull IScrollCaptureResponseListener listener)11136     public void dispatchScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) {
11137         mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, listener).sendToTarget();
11138     }
11139 
11140     // Make this VRI able to process back key without drop it.
processingBackKey(boolean processing)11141     void processingBackKey(boolean processing) {
11142         mProcessingBackKey = processing;
11143     }
11144 
11145     /**
11146      * Collect and include any ScrollCaptureCallback instances registered with the window.
11147      *
11148      * @see #addScrollCaptureCallback(ScrollCaptureCallback)
11149      * @param results an object to collect the results of the search
11150      */
collectRootScrollCaptureTargets(ScrollCaptureSearchResults results)11151     private void collectRootScrollCaptureTargets(ScrollCaptureSearchResults results) {
11152         if (mRootScrollCaptureCallbacks == null) {
11153             return;
11154         }
11155         for (ScrollCaptureCallback cb : mRootScrollCaptureCallbacks) {
11156             // Add to the list for consideration
11157             Point offset = new Point(mView.getLeft(), mView.getTop());
11158             Rect rect = new Rect(0, 0, mView.getWidth(), mView.getHeight());
11159             results.addTarget(new ScrollCaptureTarget(mView, rect, offset, cb));
11160         }
11161     }
11162 
11163     /**
11164      * Update the timeout for scroll capture requests. Only affects this view root.
11165      * The default value is {@link #SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS}.
11166      *
11167      * @param timeMillis the new timeout in milliseconds
11168      */
setScrollCaptureRequestTimeout(int timeMillis)11169     public void setScrollCaptureRequestTimeout(int timeMillis) {
11170         mScrollCaptureRequestTimeout = timeMillis;
11171     }
11172 
11173     /**
11174      * Get the current timeout for scroll capture requests.
11175      *
11176      * @return the timeout in milliseconds
11177      */
getScrollCaptureRequestTimeout()11178     public long getScrollCaptureRequestTimeout() {
11179         return mScrollCaptureRequestTimeout;
11180     }
11181 
11182     /**
11183      * Handles an inbound request for scroll capture from the system. A search will be
11184      * dispatched through the view tree to locate scrolling content.
11185      * <p>
11186      * A call to
11187      * {@link IScrollCaptureResponseListener#onScrollCaptureResponse} will follow.
11188      *
11189      * @param listener to receive responses
11190      * @see ScrollCaptureSearchResults
11191      */
handleScrollCaptureRequest(@onNull IScrollCaptureResponseListener listener)11192     public void handleScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) {
11193         ScrollCaptureSearchResults results =
11194                 new ScrollCaptureSearchResults(mContext.getMainExecutor());
11195 
11196         // Window (root) level callbacks
11197         collectRootScrollCaptureTargets(results);
11198 
11199         // Search through View-tree
11200         View rootView = getView();
11201         if (rootView != null) {
11202             Point point = new Point();
11203             Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight());
11204             getChildVisibleRect(rootView, rect, point);
11205             rootView.dispatchScrollCaptureSearch(rect, point, results::addTarget);
11206         }
11207         Runnable onComplete = () -> dispatchScrollCaptureSearchResponse(listener, results);
11208         results.setOnCompleteListener(onComplete);
11209         if (!results.isComplete()) {
11210             mHandler.postDelayed(results::finish, getScrollCaptureRequestTimeout());
11211         }
11212     }
11213 
11214     /** Called by {@link #handleScrollCaptureRequest} when a result is returned */
dispatchScrollCaptureSearchResponse( @onNull IScrollCaptureResponseListener listener, @NonNull ScrollCaptureSearchResults results)11215     private void dispatchScrollCaptureSearchResponse(
11216             @NonNull IScrollCaptureResponseListener listener,
11217             @NonNull ScrollCaptureSearchResults results) {
11218 
11219         ScrollCaptureTarget selectedTarget = results.getTopResult();
11220 
11221         ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
11222         response.setWindowTitle(getTitle().toString());
11223         response.setPackageName(mContext.getPackageName());
11224 
11225         StringWriter writer =  new StringWriter();
11226         IndentingPrintWriter pw = new IndentingPrintWriter(writer);
11227         results.dump(pw);
11228         pw.flush();
11229         response.addMessage(writer.toString());
11230 
11231         if (selectedTarget == null) {
11232             response.setDescription("No scrollable targets found in window");
11233             try {
11234                 listener.onScrollCaptureResponse(response.build());
11235             } catch (RemoteException e) {
11236                 Log.e(TAG, "Failed to send scroll capture search result", e);
11237             }
11238             return;
11239         }
11240 
11241         response.setDescription("Connected");
11242 
11243         // Compute area covered by scrolling content within window
11244         Rect boundsInWindow = new Rect();
11245         View containingView = selectedTarget.getContainingView();
11246         containingView.getLocationInWindow(mAttachInfo.mTmpLocation);
11247         boundsInWindow.set(selectedTarget.getScrollBounds());
11248         boundsInWindow.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]);
11249         response.setBoundsInWindow(boundsInWindow);
11250 
11251         // Compute the area on screen covered by the window
11252         Rect boundsOnScreen = new Rect();
11253         mView.getLocationOnScreen(mAttachInfo.mTmpLocation);
11254         boundsOnScreen.set(0, 0, mView.getWidth(), mView.getHeight());
11255         boundsOnScreen.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]);
11256         response.setWindowBounds(boundsOnScreen);
11257 
11258         // Create a connection and return it to the caller
11259         ScrollCaptureConnection connection = new ScrollCaptureConnection(
11260                 mView.getContext().getMainExecutor(), selectedTarget);
11261         response.setConnection(connection);
11262 
11263         try {
11264             listener.onScrollCaptureResponse(response.build());
11265         } catch (RemoteException e) {
11266             if (DEBUG_SCROLL_CAPTURE) {
11267                 Log.w(TAG, "Failed to send scroll capture search response.", e);
11268             }
11269             connection.close();
11270         }
11271     }
11272 
reportNextDraw(String reason)11273     private void reportNextDraw(String reason) {
11274         if (DEBUG_BLAST) {
11275             Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
11276         }
11277         mReportNextDraw = true;
11278         mLastReportNextDrawReason = reason;
11279     }
11280 
11281     /**
11282      * Force the window to report its next draw.
11283      * <p>
11284      * This method is only supposed to be used to speed up the interaction from SystemUI and window
11285      * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
11286      * unless you fully understand this interaction.
11287      *
11288      * @param syncBuffer If true, the transaction that contains the buffer from the draw should be
11289      *                   sent to system to be synced. If false, VRI will not try to sync the buffer,
11290      *                   but only report back that a buffer was drawn.
11291      * @param reason A debug string indicating the reason for reporting the next draw
11292      * @hide
11293      */
setReportNextDraw(boolean syncBuffer, String reason)11294     public void setReportNextDraw(boolean syncBuffer, String reason) {
11295         mSyncBuffer = syncBuffer;
11296         reportNextDraw(reason);
11297         invalidate();
11298     }
11299 
changeCanvasOpacity(boolean opaque)11300     void changeCanvasOpacity(boolean opaque) {
11301         Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
11302         opaque = opaque & ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0);
11303         if (mAttachInfo.mThreadedRenderer != null) {
11304             mAttachInfo.mThreadedRenderer.setOpaque(opaque);
11305         }
11306     }
11307 
11308     /**
11309      * Dispatches a KeyEvent to all registered key fallback handlers.
11310      *
11311      * @param event
11312      * @return {@code true} if the event was handled, {@code false} otherwise.
11313      */
dispatchUnhandledKeyEvent(KeyEvent event)11314     public boolean dispatchUnhandledKeyEvent(KeyEvent event) {
11315         return mUnhandledKeyManager.dispatch(mView, event);
11316     }
11317 
11318     class TakenSurfaceHolder extends BaseSurfaceHolder {
11319         @Override
onAllowLockCanvas()11320         public boolean onAllowLockCanvas() {
11321             return mDrawingAllowed;
11322         }
11323 
11324         @Override
onRelayoutContainer()11325         public void onRelayoutContainer() {
11326             // Not currently interesting -- from changing between fixed and layout size.
11327         }
11328 
11329         @Override
setFormat(int format)11330         public void setFormat(int format) {
11331             ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
11332         }
11333 
11334         @Override
setType(int type)11335         public void setType(int type) {
11336             ((RootViewSurfaceTaker)mView).setSurfaceType(type);
11337         }
11338 
11339         @Override
onUpdateSurface()11340         public void onUpdateSurface() {
11341             // We take care of format and type changes on our own.
11342             throw new IllegalStateException("Shouldn't be here");
11343         }
11344 
11345         @Override
isCreating()11346         public boolean isCreating() {
11347             return mIsCreating;
11348         }
11349 
11350         @Override
setFixedSize(int width, int height)11351         public void setFixedSize(int width, int height) {
11352             throw new UnsupportedOperationException(
11353                     "Currently only support sizing from layout");
11354         }
11355 
11356         @Override
setKeepScreenOn(boolean screenOn)11357         public void setKeepScreenOn(boolean screenOn) {
11358             ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
11359         }
11360     }
11361 
11362     static class W extends IWindow.Stub implements WindowStateTransactionItem.TransactionListener {
11363         private final WeakReference<ViewRootImpl> mViewAncestor;
11364         private final IWindowSession mWindowSession;
11365         private boolean mIsFromTransactionItem;
11366 
W(ViewRootImpl viewAncestor)11367         W(ViewRootImpl viewAncestor) {
11368             mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
11369             mWindowSession = viewAncestor.mWindowSession;
11370         }
11371 
11372         @Override
onExecutingWindowStateTransactionItem()11373         public void onExecutingWindowStateTransactionItem() {
11374             mIsFromTransactionItem = true;
11375         }
11376 
11377         @Override
resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo)11378         public void resized(ClientWindowFrames frames, boolean reportDraw,
11379                 MergedConfiguration mergedConfiguration, InsetsState insetsState,
11380                 boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
11381                 boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo) {
11382             final boolean isFromResizeItem = mIsFromTransactionItem;
11383             mIsFromTransactionItem = false;
11384             // Although this is a AIDL method, it will only be triggered in local process through
11385             // either WindowStateResizeItem or WindowlessWindowManager.
11386             final ViewRootImpl viewAncestor = mViewAncestor.get();
11387             if (viewAncestor == null) {
11388                 return;
11389             }
11390             if (insetsState.isSourceOrDefaultVisible(ID_IME, Type.ime())) {
11391                 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#resized",
11392                         viewAncestor.getInsetsController().getHost().getInputMethodManager(),
11393                         null /* icProto */);
11394             }
11395             // If the UI thread is the same as the current thread that is dispatching
11396             // WindowStateResizeItem, then it can run directly.
11397             if (isFromResizeItem && viewAncestor.mHandler.getLooper()
11398                     == ActivityThread.currentActivityThread().getLooper()) {
11399                 viewAncestor.handleResized(frames, reportDraw, mergedConfiguration, insetsState,
11400                         forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing,
11401                         activityWindowInfo);
11402                 return;
11403             }
11404             // The the parameters from WindowStateResizeItem are already copied.
11405             final boolean needsCopy =
11406                     !isFromResizeItem && (Binder.getCallingPid() == Process.myPid());
11407             if (needsCopy) {
11408                 insetsState = new InsetsState(insetsState, true /* copySource */);
11409                 frames = new ClientWindowFrames(frames);
11410                 mergedConfiguration = new MergedConfiguration(mergedConfiguration);
11411             }
11412             viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState,
11413                     forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing,
11414                     activityWindowInfo);
11415         }
11416 
11417         @Override
insetsControlChanged(InsetsState insetsState, InsetsSourceControl.Array activeControls)11418         public void insetsControlChanged(InsetsState insetsState,
11419                 InsetsSourceControl.Array activeControls) {
11420             final boolean isFromInsetsControlChangeItem;
11421             if (insetsControlChangedItem()) {
11422                 isFromInsetsControlChangeItem = mIsFromTransactionItem;
11423                 mIsFromTransactionItem = false;
11424             } else {
11425                 isFromInsetsControlChangeItem = false;
11426             }
11427             final ViewRootImpl viewAncestor = mViewAncestor.get();
11428             if (viewAncestor == null) {
11429                 if (isFromInsetsControlChangeItem) {
11430                     activeControls.release();
11431                 }
11432                 return;
11433             }
11434             if (insetsState.isSourceOrDefaultVisible(ID_IME, Type.ime())) {
11435                 ImeTracing.getInstance().triggerClientDump(
11436                         "ViewRootImpl#dispatchInsetsControlChanged",
11437                         viewAncestor.getInsetsController().getHost().getInputMethodManager(),
11438                         null /* icProto */);
11439             }
11440             // If the UI thread is the same as the current thread that is dispatching
11441             // WindowStateInsetsControlChangeItem, then it can run directly.
11442             if (isFromInsetsControlChangeItem && viewAncestor.mHandler.getLooper()
11443                     == ActivityThread.currentActivityThread().getLooper()) {
11444                 viewAncestor.handleInsetsControlChanged(insetsState, activeControls);
11445                 return;
11446             }
11447             // The parameters from WindowStateInsetsControlChangeItem are already copied.
11448             final boolean needsCopy =
11449                     !isFromInsetsControlChangeItem && (Binder.getCallingPid() == Process.myPid());
11450             if (needsCopy) {
11451                 insetsState = new InsetsState(insetsState, true /* copySource */);
11452                 activeControls = new InsetsSourceControl.Array(
11453                         activeControls, true /* copyControls */);
11454             }
11455 
11456             viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls);
11457         }
11458 
11459         @Override
showInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)11460         public void showInsets(@InsetsType int types, boolean fromIme,
11461                 @Nullable ImeTracker.Token statsToken) {
11462             final ViewRootImpl viewAncestor = mViewAncestor.get();
11463             if (fromIme) {
11464                 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#showInsets",
11465                         viewAncestor.getInsetsController().getHost().getInputMethodManager(),
11466                         null /* icProto */);
11467             }
11468             if (viewAncestor != null) {
11469                 ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
11470                 viewAncestor.showInsets(types, fromIme, statsToken);
11471             } else {
11472                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
11473             }
11474         }
11475 
11476         @Override
hideInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)11477         public void hideInsets(@InsetsType int types, boolean fromIme,
11478                 @Nullable ImeTracker.Token statsToken) {
11479             final ViewRootImpl viewAncestor = mViewAncestor.get();
11480             if (fromIme) {
11481                 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#hideInsets",
11482                         viewAncestor.getInsetsController().getHost().getInputMethodManager(),
11483                         null /* icProto */);
11484             }
11485             if (viewAncestor != null) {
11486                 ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
11487                 viewAncestor.hideInsets(types, fromIme, statsToken);
11488             } else {
11489                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
11490             }
11491         }
11492 
11493         @Override
moved(int newX, int newY)11494         public void moved(int newX, int newY) {
11495             final ViewRootImpl viewAncestor = mViewAncestor.get();
11496             if (viewAncestor != null) {
11497                 viewAncestor.dispatchMoved(newX, newY);
11498             }
11499         }
11500 
11501         @Override
dispatchAppVisibility(boolean visible)11502         public void dispatchAppVisibility(boolean visible) {
11503             final ViewRootImpl viewAncestor = mViewAncestor.get();
11504             if (viewAncestor != null) {
11505                 viewAncestor.dispatchAppVisibility(visible);
11506             }
11507         }
11508 
11509         @Override
dispatchGetNewSurface()11510         public void dispatchGetNewSurface() {
11511             final ViewRootImpl viewAncestor = mViewAncestor.get();
11512             if (viewAncestor != null) {
11513                 viewAncestor.dispatchGetNewSurface();
11514             }
11515         }
11516 
checkCallingPermission(String permission)11517         private static int checkCallingPermission(String permission) {
11518             try {
11519                 return ActivityManager.getService().checkPermission(
11520                         permission, Binder.getCallingPid(), Binder.getCallingUid());
11521             } catch (RemoteException e) {
11522                 return PackageManager.PERMISSION_DENIED;
11523             }
11524         }
11525 
11526         @Override
executeCommand(String command, String parameters, ParcelFileDescriptor out)11527         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
11528             final ViewRootImpl viewAncestor = mViewAncestor.get();
11529             if (viewAncestor != null) {
11530                 final View view = viewAncestor.mView;
11531                 if (view != null) {
11532                     if (checkCallingPermission(Manifest.permission.DUMP) !=
11533                             PackageManager.PERMISSION_GRANTED) {
11534                         throw new SecurityException("Insufficient permissions to invoke"
11535                                 + " executeCommand() from pid=" + Binder.getCallingPid()
11536                                 + ", uid=" + Binder.getCallingUid());
11537                     }
11538 
11539                     OutputStream clientStream = null;
11540                     try {
11541                         clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
11542                         ViewDebug.dispatchCommand(view, command, parameters, clientStream);
11543                     } catch (IOException e) {
11544                         e.printStackTrace();
11545                     } finally {
11546                         if (clientStream != null) {
11547                             try {
11548                                 clientStream.close();
11549                             } catch (IOException e) {
11550                                 e.printStackTrace();
11551                             }
11552                         }
11553                     }
11554                 }
11555             }
11556         }
11557 
11558         @Override
closeSystemDialogs(String reason)11559         public void closeSystemDialogs(String reason) {
11560             final ViewRootImpl viewAncestor = mViewAncestor.get();
11561             if (viewAncestor != null) {
11562                 viewAncestor.dispatchCloseSystemDialogs(reason);
11563             }
11564         }
11565 
11566         @Override
dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom, boolean sync)11567         public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
11568                 float zoom, boolean sync) {
11569             if (sync) {
11570                 try {
11571                     mWindowSession.wallpaperOffsetsComplete(asBinder());
11572                 } catch (RemoteException e) {
11573                 }
11574             }
11575         }
11576 
11577         @Override
dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync)11578         public void dispatchWallpaperCommand(String action, int x, int y,
11579                 int z, Bundle extras, boolean sync) {
11580             if (sync) {
11581                 try {
11582                     mWindowSession.wallpaperCommandComplete(asBinder(), null);
11583                 } catch (RemoteException e) {
11584                 }
11585             }
11586         }
11587 
11588         /* Drag/drop */
11589         @Override
dispatchDragEvent(DragEvent event)11590         public void dispatchDragEvent(DragEvent event) {
11591             final ViewRootImpl viewAncestor = mViewAncestor.get();
11592             if (viewAncestor != null) {
11593                 viewAncestor.dispatchDragEvent(event);
11594             }
11595         }
11596 
11597         @Override
dispatchWindowShown()11598         public void dispatchWindowShown() {
11599             final ViewRootImpl viewAncestor = mViewAncestor.get();
11600             if (viewAncestor != null) {
11601                 viewAncestor.dispatchWindowShown();
11602             }
11603         }
11604 
11605         @Override
requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId)11606         public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
11607             ViewRootImpl viewAncestor = mViewAncestor.get();
11608             if (viewAncestor != null) {
11609                 viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
11610             }
11611         }
11612 
11613         @Override
requestScrollCapture(IScrollCaptureResponseListener listener)11614         public void requestScrollCapture(IScrollCaptureResponseListener listener) {
11615             final ViewRootImpl viewAncestor = mViewAncestor.get();
11616             if (viewAncestor != null) {
11617                 viewAncestor.dispatchScrollCaptureRequest(listener);
11618             }
11619         }
11620 
11621         @Override
dumpWindow(ParcelFileDescriptor pfd)11622         public void dumpWindow(ParcelFileDescriptor pfd) {
11623             final ViewRootImpl viewAncestor = mViewAncestor.get();
11624             if (viewAncestor == null) {
11625                 return;
11626             }
11627             viewAncestor.mHandler.postAtFrontOfQueue(() -> {
11628                 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
11629                 try {
11630                     PrintWriter pw = new FastPrintWriter(new FileOutputStream(
11631                             pfd.getFileDescriptor()));
11632                     viewAncestor.dump("", pw);
11633                     pw.flush();
11634                 } finally {
11635                     IoUtils.closeQuietly(pfd);
11636                     StrictMode.setThreadPolicy(oldPolicy);
11637                 }
11638             });
11639         }
11640     }
11641 
11642     public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
11643         @UnsupportedAppUsage
CalledFromWrongThreadException(String msg)11644         public CalledFromWrongThreadException(String msg) {
11645             super(msg);
11646         }
11647     }
11648 
getRunQueue()11649     static HandlerActionQueue getRunQueue() {
11650         HandlerActionQueue rq = sRunQueues.get();
11651         if (rq != null) {
11652             return rq;
11653         }
11654         rq = new HandlerActionQueue();
11655         sRunQueues.set(rq);
11656         return rq;
11657     }
11658 
11659     /**
11660      * Start a drag resizing which will inform all listeners that a window resize is taking place.
11661      */
startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, Rect stableInsets)11662     private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
11663             Rect stableInsets) {
11664         if (!mDragResizing) {
11665             mDragResizing = true;
11666             if (mUseMTRenderer) {
11667                 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
11668                     mWindowCallbacks.get(i).onWindowDragResizeStart(
11669                             initialBounds, fullscreen, systemInsets, stableInsets);
11670                 }
11671             }
11672             mFullRedrawNeeded = true;
11673         }
11674     }
11675 
11676     /**
11677      * End a drag resize which will inform all listeners that a window resize has ended.
11678      */
endDragResizing()11679     private void endDragResizing() {
11680         if (mDragResizing) {
11681             mDragResizing = false;
11682             if (mUseMTRenderer) {
11683                 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
11684                     mWindowCallbacks.get(i).onWindowDragResizeEnd();
11685                 }
11686             }
11687             mFullRedrawNeeded = true;
11688         }
11689     }
11690 
updateContentDrawBounds()11691     private boolean updateContentDrawBounds() {
11692         boolean updated = false;
11693         if (mUseMTRenderer) {
11694             for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
11695                 updated |=
11696                         mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left,
11697                                 mWindowAttributes.surfaceInsets.top, mWidth, mHeight);
11698             }
11699         }
11700         return updated | (mDragResizing && mReportNextDraw);
11701     }
11702 
requestDrawWindow()11703     private void requestDrawWindow() {
11704         if (!mUseMTRenderer) {
11705             return;
11706         }
11707         // Only wait if it will report next draw.
11708         if (mReportNextDraw) {
11709             mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
11710         }
11711         for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
11712             mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
11713         }
11714     }
11715 
getSurfaceControl()11716     public SurfaceControl getSurfaceControl() {
11717         return mSurfaceControl;
11718     }
11719 
11720     /**
11721      * @return Returns a token used to identify the windows input channel.
11722      */
getInputToken()11723     public IBinder getInputToken() {
11724         if (mInputEventReceiver == null) {
11725             return null;
11726         }
11727         return mInputEventReceiver.getToken();
11728     }
11729 
11730     /**
11731      * {@inheritDoc}
11732      */
11733     @NonNull
11734     @Override
getInputTransferToken()11735     public InputTransferToken getInputTransferToken() {
11736         IBinder inputToken = getInputToken();
11737         if (inputToken == null) {
11738             throw new IllegalStateException(
11739                     "Called getInputTransferToken for Window with no input channel");
11740         }
11741         return new InputTransferToken(inputToken);
11742     }
11743     @NonNull
getWindowToken()11744     public IBinder getWindowToken() {
11745         return mAttachInfo.mWindowToken;
11746     }
11747 
11748     /**
11749      * Class for managing the accessibility interaction connection
11750      * based on the global accessibility state.
11751      */
11752     final class AccessibilityInteractionConnectionManager
11753             implements AccessibilityStateChangeListener {
11754         private int mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID;
11755 
11756         @Override
onAccessibilityStateChanged(boolean enabled)11757         public void onAccessibilityStateChanged(boolean enabled) {
11758             if (enabled) {
11759                 ensureConnection();
11760                 setAccessibilityWindowAttributesIfNeeded();
11761                 if (mAttachInfo.mHasWindowFocus && (mView != null)) {
11762                     mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
11763                     View focusedView = mView.findFocus();
11764                     if (focusedView != null && focusedView != mView) {
11765                         focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
11766                     }
11767                 }
11768                 if (mAttachInfo.mLeashedParentToken != null) {
11769                     mAccessibilityManager.associateEmbeddedHierarchy(
11770                             mAttachInfo.mLeashedParentToken, mLeashToken);
11771                 }
11772             } else {
11773                 ensureNoConnection();
11774                 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
11775             }
11776         }
11777 
ensureConnection()11778         public void ensureConnection() {
11779             final boolean registered = mAttachInfo.mAccessibilityWindowId
11780                     != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
11781             if (!registered) {
11782                 mAttachInfo.mAccessibilityWindowId =
11783                         mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
11784                                 mLeashToken,
11785                                 mContext.getPackageName(),
11786                                 new AccessibilityInteractionConnection(ViewRootImpl.this));
11787             }
11788         }
11789 
ensureNoConnection()11790         public void ensureNoConnection() {
11791             final boolean registered = mAttachInfo.mAccessibilityWindowId
11792                     != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
11793             if (registered) {
11794                 mAttachInfo.mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
11795                 mAccessibilityWindowAttributes = null;
11796                 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
11797             }
11798         }
11799 
ensureDirectConnection()11800         public int ensureDirectConnection() {
11801             if (mDirectConnectionId == AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) {
11802                 mDirectConnectionId = AccessibilityInteractionClient.addDirectConnection(
11803                         new AccessibilityInteractionConnection(ViewRootImpl.this),
11804                         mAccessibilityManager);
11805                 // Notify listeners in the app process.
11806                 mAccessibilityManager.notifyAccessibilityStateChanged();
11807             }
11808             return mDirectConnectionId;
11809         }
11810 
ensureNoDirectConnection()11811         public void ensureNoDirectConnection() {
11812             if (mDirectConnectionId != AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) {
11813                 AccessibilityInteractionClient.removeConnection(mDirectConnectionId);
11814                 mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID;
11815                 // Notify listeners in the app process.
11816                 mAccessibilityManager.notifyAccessibilityStateChanged();
11817             }
11818         }
11819     }
11820 
11821     final class HighContrastTextManager implements HighTextContrastChangeListener {
HighContrastTextManager()11822         HighContrastTextManager() {
11823             ThreadedRenderer.setHighContrastText(mAccessibilityManager.isHighTextContrastEnabled());
11824         }
11825         @Override
onHighTextContrastStateChanged(boolean enabled)11826         public void onHighTextContrastStateChanged(boolean enabled) {
11827             ThreadedRenderer.setHighContrastText(enabled);
11828 
11829             // Destroy Displaylists so they can be recreated with high contrast recordings
11830             destroyHardwareResources();
11831 
11832             // Schedule redraw, which will rerecord + redraw all text
11833             invalidate();
11834         }
11835     }
11836 
11837     /**
11838      * This class is an interface this ViewAncestor provides to the
11839      * AccessibilityManagerService to the latter can interact with
11840      * the view hierarchy in this ViewAncestor.
11841      */
11842     static final class AccessibilityInteractionConnection
11843             extends IAccessibilityInteractionConnection.Stub {
11844         private final WeakReference<ViewRootImpl> mViewRootImpl;
11845 
AccessibilityInteractionConnection(ViewRootImpl viewRootImpl)11846         AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
11847             mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
11848         }
11849 
11850         @Override
findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix, Bundle args)11851         public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
11852                 Region interactiveRegion, int interactionId,
11853                 IAccessibilityInteractionConnectionCallback callback, int flags,
11854                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix,
11855                 Bundle args) {
11856             ViewRootImpl viewRootImpl = mViewRootImpl.get();
11857             if (viewRootImpl != null && viewRootImpl.mView != null) {
11858                 viewRootImpl.getAccessibilityInteractionController()
11859                     .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
11860                             interactiveRegion, interactionId, callback, flags, interrogatingPid,
11861                             interrogatingTid, spec, matrix, args);
11862             } else {
11863                 // We cannot make the call and notify the caller so it does not wait.
11864                 try {
11865                     callback.setFindAccessibilityNodeInfosResult(null, interactionId);
11866                 } catch (RemoteException re) {
11867                     /* best effort - ignore */
11868                 }
11869             }
11870         }
11871 
11872         @Override
performAccessibilityAction(long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)11873         public void performAccessibilityAction(long accessibilityNodeId, int action,
11874                 Bundle arguments, int interactionId,
11875                 IAccessibilityInteractionConnectionCallback callback, int flags,
11876                 int interrogatingPid, long interrogatingTid) {
11877             ViewRootImpl viewRootImpl = mViewRootImpl.get();
11878             if (viewRootImpl != null && viewRootImpl.mView != null) {
11879                 viewRootImpl.getAccessibilityInteractionController()
11880                     .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
11881                             interactionId, callback, flags, interrogatingPid, interrogatingTid);
11882             } else {
11883                 // We cannot make the call and notify the caller so it does not wait.
11884                 try {
11885                     callback.setPerformAccessibilityActionResult(false, interactionId);
11886                 } catch (RemoteException re) {
11887                     /* best effort - ignore */
11888                 }
11889             }
11890         }
11891 
11892         @Override
findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)11893         public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
11894                 String viewId, Region interactiveRegion, int interactionId,
11895                 IAccessibilityInteractionConnectionCallback callback, int flags,
11896                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
11897                 float[] matrix) {
11898             ViewRootImpl viewRootImpl = mViewRootImpl.get();
11899             if (viewRootImpl != null && viewRootImpl.mView != null) {
11900                 viewRootImpl.getAccessibilityInteractionController()
11901                     .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
11902                             viewId, interactiveRegion, interactionId, callback, flags,
11903                             interrogatingPid, interrogatingTid, spec, matrix);
11904             } else {
11905                 // We cannot make the call and notify the caller so it does not wait.
11906                 try {
11907                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
11908                 } catch (RemoteException re) {
11909                     /* best effort - ignore */
11910                 }
11911             }
11912         }
11913 
11914         @Override
findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)11915         public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
11916                 Region interactiveRegion, int interactionId,
11917                 IAccessibilityInteractionConnectionCallback callback, int flags,
11918                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
11919                 float[] matrix) {
11920             ViewRootImpl viewRootImpl = mViewRootImpl.get();
11921             if (viewRootImpl != null && viewRootImpl.mView != null) {
11922                 viewRootImpl.getAccessibilityInteractionController()
11923                     .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
11924                             interactiveRegion, interactionId, callback, flags, interrogatingPid,
11925                             interrogatingTid, spec, matrix);
11926             } else {
11927                 // We cannot make the call and notify the caller so it does not wait.
11928                 try {
11929                     callback.setFindAccessibilityNodeInfosResult(null, interactionId);
11930                 } catch (RemoteException re) {
11931                     /* best effort - ignore */
11932                 }
11933             }
11934         }
11935 
11936         @Override
findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)11937         public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
11938                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
11939                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
11940                 float[] matrix) {
11941             ViewRootImpl viewRootImpl = mViewRootImpl.get();
11942             if (viewRootImpl != null && viewRootImpl.mView != null) {
11943                 viewRootImpl.getAccessibilityInteractionController()
11944                     .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
11945                             interactionId, callback, flags, interrogatingPid, interrogatingTid,
11946                             spec, matrix);
11947             } else {
11948                 // We cannot make the call and notify the caller so it does not wait.
11949                 try {
11950                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
11951                 } catch (RemoteException re) {
11952                     /* best effort - ignore */
11953                 }
11954             }
11955         }
11956 
11957         @Override
focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)11958         public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
11959                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
11960                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
11961                 float[] matrix) {
11962             ViewRootImpl viewRootImpl = mViewRootImpl.get();
11963             if (viewRootImpl != null && viewRootImpl.mView != null) {
11964                 viewRootImpl.getAccessibilityInteractionController()
11965                     .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
11966                             interactionId, callback, flags, interrogatingPid, interrogatingTid,
11967                             spec, matrix);
11968             } else {
11969                 // We cannot make the call and notify the caller so it does not wait.
11970                 try {
11971                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
11972                 } catch (RemoteException re) {
11973                     /* best effort - ignore */
11974                 }
11975             }
11976         }
11977 
11978         @Override
clearAccessibilityFocus()11979         public void clearAccessibilityFocus() {
11980             ViewRootImpl viewRootImpl = mViewRootImpl.get();
11981             if (viewRootImpl != null && viewRootImpl.mView != null) {
11982                 viewRootImpl.getAccessibilityInteractionController()
11983                         .clearAccessibilityFocusClientThread();
11984             }
11985         }
11986 
11987         @Override
notifyOutsideTouch()11988         public void notifyOutsideTouch() {
11989             ViewRootImpl viewRootImpl = mViewRootImpl.get();
11990             if (viewRootImpl != null && viewRootImpl.mView != null) {
11991                 viewRootImpl.getAccessibilityInteractionController()
11992                         .notifyOutsideTouchClientThread();
11993             }
11994         }
11995 
11996         @Override
takeScreenshotOfWindow(int interactionId, ScreenCapture.ScreenCaptureListener listener, IAccessibilityInteractionConnectionCallback callback)11997         public void takeScreenshotOfWindow(int interactionId,
11998                 ScreenCapture.ScreenCaptureListener listener,
11999                 IAccessibilityInteractionConnectionCallback callback) {
12000             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12001             if (viewRootImpl != null && viewRootImpl.mView != null) {
12002                 viewRootImpl.getAccessibilityInteractionController()
12003                         .takeScreenshotOfWindowClientThread(interactionId, listener, callback);
12004             } else {
12005                 try {
12006                     callback.sendTakeScreenshotOfWindowError(
12007                             AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR,
12008                             interactionId);
12009                 } catch (RemoteException re) {
12010                     /* best effort - ignore */
12011                 }
12012             }
12013         }
12014 
attachAccessibilityOverlayToWindow( SurfaceControl sc, int interactionId, IAccessibilityInteractionConnectionCallback callback)12015         public void attachAccessibilityOverlayToWindow(
12016                 SurfaceControl sc,
12017                 int interactionId,
12018                 IAccessibilityInteractionConnectionCallback callback) {
12019             ViewRootImpl viewRootImpl = mViewRootImpl.get();
12020             if (viewRootImpl != null) {
12021                 viewRootImpl
12022                         .getAccessibilityInteractionController()
12023                         .attachAccessibilityOverlayToWindowClientThread(
12024                                 sc, interactionId, callback);
12025             }
12026         }
12027     }
12028 
12029     /**
12030      * Gets an accessibility embedded connection interface for this ViewRootImpl.
12031      * @hide
12032      */
getAccessibilityEmbeddedConnection()12033     public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
12034         if (mAccessibilityEmbeddedConnection == null) {
12035             mAccessibilityEmbeddedConnection = new AccessibilityEmbeddedConnection(
12036                     ViewRootImpl.this);
12037         }
12038         return mAccessibilityEmbeddedConnection;
12039     }
12040 
12041     private class SendWindowContentChangedAccessibilityEvent implements Runnable {
12042         private int mChangeTypes = 0;
12043 
12044         public View mSource;
12045         public long mLastEventTimeMillis;
12046         /**
12047          * Keep track of action that caused the event.
12048          * This is empty if there's no performing actions for pending events.
12049          * This is zero if there're multiple events performed for pending events.
12050          */
12051         @NonNull public OptionalInt mAction = OptionalInt.empty();
12052         /**
12053          * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace
12054          * of the original {@link #runOrPost} call instead of one for sending the delayed event
12055          * from a looper.
12056          */
12057         public StackTraceElement[] mOrigin;
12058 
12059         @Override
run()12060         public void run() {
12061             // Protect against re-entrant code and attempt to do the right thing in the case that
12062             // we're multithreaded.
12063             View source = mSource;
12064             mSource = null;
12065             if (source == null) {
12066                 Log.e(TAG, "Accessibility content change has no source");
12067                 return;
12068             }
12069             // The accessibility may be turned off while we were waiting so check again.
12070             if (mAccessibilityManager.isEnabled()) {
12071                 mLastEventTimeMillis = SystemClock.uptimeMillis();
12072                 AccessibilityEvent event = AccessibilityEvent.obtain();
12073                 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
12074                 event.setContentChangeTypes(mChangeTypes);
12075                 if (mAction.isPresent()) event.setAction(mAction.getAsInt());
12076                 if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin;
12077                 source.sendAccessibilityEventUnchecked(event);
12078             } else {
12079                 mLastEventTimeMillis = 0;
12080             }
12081             // In any case reset to initial state.
12082             source.resetSubtreeAccessibilityStateChanged();
12083             mChangeTypes = 0;
12084             mAction = OptionalInt.empty();
12085             if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null;
12086         }
12087 
runOrPost(View source, int changeType)12088         public void runOrPost(View source, int changeType) {
12089             if (mHandler.getLooper() != Looper.myLooper()) {
12090                 CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the "
12091                         + "original thread that created a view hierarchy can touch its views.");
12092                 // TODO: Throw the exception
12093                 Log.e(TAG, "Accessibility content change on non-UI thread. Future Android "
12094                         + "versions will throw an exception.", e);
12095                 // Attempt to recover. This code does not eliminate the thread safety issue, but
12096                 // it should force any issues to happen near the above log.
12097                 mHandler.removeCallbacks(this);
12098                 if (mSource != null) {
12099                     // Dispatch whatever was pending. It's still possible that the runnable started
12100                     // just before we removed the callbacks, and bad things will happen, but at
12101                     // least they should happen very close to the logged error.
12102                     run();
12103                 }
12104             }
12105 
12106             if (!canContinueThrottle(source, changeType)) {
12107                 removeCallbacksAndRun();
12108             }
12109 
12110             if (mSource != null) {
12111                 if (fixMergedContentChangeEventV2()) {
12112                     View newSource = getCommonPredecessor(mSource, source);
12113                     if (newSource != null) {
12114                         newSource = newSource.getSelfOrParentImportantForA11y();
12115                     }
12116                     if (newSource == null) {
12117                         // If there is no common predecessor, then mSource points to
12118                         // a removed view, hence in this case always prefer the source.
12119                         newSource = source;
12120                     }
12121 
12122                     mChangeTypes |= changeType;
12123                     if (mSource != newSource) {
12124                         mChangeTypes |= AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
12125                         mSource = newSource;
12126                     }
12127                 } else {
12128                     // If there is no common predecessor, then mSource points to
12129                     // a removed view, hence in this case always prefer the source.
12130                     View predecessor = getCommonPredecessor(mSource, source);
12131                     if (predecessor != null) {
12132                         predecessor = predecessor.getSelfOrParentImportantForA11y();
12133                     }
12134                     mSource = (predecessor != null) ? predecessor : source;
12135                     mChangeTypes |= changeType;
12136                 }
12137 
12138                 final int performingAction = mAccessibilityManager.getPerformingAction();
12139                 if (performingAction != 0) {
12140                     if (mAction.isEmpty()) {
12141                         mAction = OptionalInt.of(performingAction);
12142                     } else if (mAction.getAsInt() != performingAction) {
12143                         // Multiple actions are performed for pending events. We cannot decide one
12144                         // action here.
12145                         // We're doing best effort to set action value, and it's fine to set
12146                         // no action this case.
12147                         mAction = OptionalInt.of(0);
12148                     }
12149                 }
12150 
12151                 return;
12152             }
12153             mSource = source;
12154             mChangeTypes = changeType;
12155             if (mAccessibilityManager.getPerformingAction() != 0) {
12156                 mAction = OptionalInt.of(mAccessibilityManager.getPerformingAction());
12157             }
12158             if (AccessibilityEvent.DEBUG_ORIGIN) {
12159                 mOrigin = Thread.currentThread().getStackTrace();
12160             }
12161             final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
12162             final long minEventIntervalMillis =
12163                     ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
12164             if (timeSinceLastMillis >= minEventIntervalMillis) {
12165                 removeCallbacksAndRun();
12166             } else {
12167                 mHandler.postDelayed(this, minEventIntervalMillis - timeSinceLastMillis);
12168             }
12169         }
12170 
removeCallbacksAndRun()12171         public void removeCallbacksAndRun() {
12172             mHandler.removeCallbacks(this);
12173             run();
12174         }
12175 
canContinueThrottle(View source, int changeType)12176         private boolean canContinueThrottle(View source, int changeType) {
12177             if (!reduceWindowContentChangedEventThrottle()) {
12178                 // Old behavior. Always throttle.
12179                 return true;
12180             }
12181             if (mSource == null) {
12182                 // We don't have a pending event.
12183                 return true;
12184             }
12185             if (mSource == source) {
12186                 // We can merge a new event with a pending event from the same source.
12187                 return true;
12188             }
12189             // We can merge subtree change events.
12190             return changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE
12191                     && mChangeTypes == AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
12192         }
12193     }
12194 
12195     private static class UnhandledKeyManager {
12196         // This is used to ensure that unhandled events are only dispatched once. We attempt
12197         // to dispatch more than once in order to achieve a certain order. Specifically, if we
12198         // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should
12199         // be dispatched after the view hierarchy, but before the Callback. However, if we aren't
12200         // in an activity, we still want unhandled keys to be dispatched.
12201         private boolean mDispatched = true;
12202 
12203         // Keeps track of which Views have unhandled key focus for which keys. This doesn't
12204         // include modifiers.
12205         private final SparseArray<WeakReference<View>> mCapturedKeys = new SparseArray<>();
12206 
12207         // The current receiver. This value is transient and used between the pre-dispatch and
12208         // pre-view phase to ensure that other input-stages don't interfere with tracking.
12209         private WeakReference<View> mCurrentReceiver = null;
12210 
dispatch(View root, KeyEvent event)12211         boolean dispatch(View root, KeyEvent event) {
12212             if (mDispatched) {
12213                 return false;
12214             }
12215             View consumer;
12216             try {
12217                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "UnhandledKeyEvent dispatch");
12218                 mDispatched = true;
12219 
12220                 consumer = root.dispatchUnhandledKeyEvent(event);
12221 
12222                 // If an unhandled listener handles one, then keep track of it so that the
12223                 // consuming view is first to receive its repeats and release as well.
12224                 if (event.getAction() == KeyEvent.ACTION_DOWN) {
12225                     int keycode = event.getKeyCode();
12226                     if (consumer != null && !KeyEvent.isModifierKey(keycode)) {
12227                         mCapturedKeys.put(keycode, new WeakReference<>(consumer));
12228                     }
12229                 }
12230             } finally {
12231                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
12232             }
12233             return consumer != null;
12234         }
12235 
12236         /**
12237          * Called before the event gets dispatched to anything
12238          */
preDispatch(KeyEvent event)12239         void preDispatch(KeyEvent event) {
12240             // Always clean-up 'up' events since it's possible for earlier dispatch stages to
12241             // consume them without consuming the corresponding 'down' event.
12242             mCurrentReceiver = null;
12243             if (event.getAction() == KeyEvent.ACTION_UP) {
12244                 int idx = mCapturedKeys.indexOfKey(event.getKeyCode());
12245                 if (idx >= 0) {
12246                     mCurrentReceiver = mCapturedKeys.valueAt(idx);
12247                     mCapturedKeys.removeAt(idx);
12248                 }
12249             }
12250         }
12251 
12252         /**
12253          * Called before the event gets dispatched to the view hierarchy
12254          * @return {@code true} if an unhandled handler has focus and consumed the event
12255          */
preViewDispatch(KeyEvent event)12256         boolean preViewDispatch(KeyEvent event) {
12257             mDispatched = false;
12258             if (mCurrentReceiver == null) {
12259                 mCurrentReceiver = mCapturedKeys.get(event.getKeyCode());
12260             }
12261             if (mCurrentReceiver != null) {
12262                 View target = mCurrentReceiver.get();
12263                 if (event.getAction() == KeyEvent.ACTION_UP) {
12264                     mCurrentReceiver = null;
12265                 }
12266                 if (target != null && target.isAttachedToWindow()) {
12267                     target.onUnhandledKeyEvent(event);
12268                 }
12269                 // consume anyways so that we don't feed uncaptured key events to other views
12270                 return true;
12271             }
12272             return false;
12273         }
12274     }
12275 
12276     /**
12277      * @hide
12278      */
setDisplayDecoration(boolean displayDecoration)12279     public void setDisplayDecoration(boolean displayDecoration) {
12280         if (displayDecoration == mDisplayDecorationCached) return;
12281 
12282         mDisplayDecorationCached = displayDecoration;
12283 
12284         if (mSurfaceControl.isValid()) {
12285             updateDisplayDecoration();
12286         }
12287     }
12288 
updateDisplayDecoration()12289     private void updateDisplayDecoration() {
12290         mTransaction.setDisplayDecoration(mSurfaceControl, mDisplayDecorationCached).apply();
12291     }
12292 
12293     /**
12294      * Sends a list of blur regions to SurfaceFlinger, tagged with a frame.
12295      *
12296      * @param regionCopy List of regions
12297      * @param frameNumber Frame where it should be applied (or current when using BLAST)
12298      */
dispatchBlurRegions(float[][] regionCopy, long frameNumber)12299     public void dispatchBlurRegions(float[][] regionCopy, long frameNumber) {
12300         final SurfaceControl surfaceControl = getSurfaceControl();
12301         if (!surfaceControl.isValid()) {
12302             return;
12303         }
12304 
12305         SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
12306         transaction.setBlurRegions(surfaceControl, regionCopy);
12307 
12308         if (mBlastBufferQueue != null) {
12309             mBlastBufferQueue.mergeWithNextTransaction(transaction, frameNumber);
12310         }
12311     }
12312 
12313     /**
12314      * Creates a background blur drawable for the backing {@link Surface}.
12315      */
createBackgroundBlurDrawable()12316     public BackgroundBlurDrawable createBackgroundBlurDrawable() {
12317         return mBlurRegionAggregator.createBackgroundBlurDrawable(mContext);
12318     }
12319 
12320     @Override
onDescendantUnbufferedRequested()12321     public void onDescendantUnbufferedRequested() {
12322         mUnbufferedInputSource = mView.mUnbufferedInputSource;
12323     }
12324 
getSurfaceSequenceId()12325     int getSurfaceSequenceId() {
12326         return mSurfaceSequenceId;
12327     }
12328 
12329     /**
12330      * Merges the transaction passed in with the next transaction in BLASTBufferQueue. This ensures
12331      * you can add transactions to the upcoming frame.
12332      */
mergeWithNextTransaction(Transaction t, long frameNumber)12333     public void mergeWithNextTransaction(Transaction t, long frameNumber) {
12334         if (mBlastBufferQueue != null) {
12335             mBlastBufferQueue.mergeWithNextTransaction(t, frameNumber);
12336         } else {
12337             t.apply();
12338         }
12339     }
12340 
12341     @Override
buildReparentTransaction( @onNull SurfaceControl child)12342     @Nullable public SurfaceControl.Transaction buildReparentTransaction(
12343         @NonNull SurfaceControl child) {
12344         if (mSurfaceControl.isValid()) {
12345             Transaction t = new Transaction();
12346             return t.reparent(child, updateAndGetBoundsLayer(t));
12347         }
12348         return null;
12349     }
12350 
12351     @Override
applyTransactionOnDraw(@onNull SurfaceControl.Transaction t)12352     public boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t) {
12353         if (mRemoved || !isHardwareEnabled()) {
12354             logAndTrace("applyTransactionOnDraw applyImmediately");
12355             t.apply();
12356         } else {
12357             Trace.instant(Trace.TRACE_TAG_VIEW, "applyTransactionOnDraw-" + mTag);
12358             // Copy and clear the passed in transaction for thread safety. The new transaction is
12359             // accessed on the render thread.
12360             mPendingTransaction.merge(t);
12361             mHasPendingTransactions = true;
12362         }
12363         return true;
12364     }
12365 
12366     @Override
getBufferTransformHint()12367     public @SurfaceControl.BufferTransform int getBufferTransformHint() {
12368         // TODO(b/326482114) We use mPreviousTransformHint (calculated using mDisplay's rotation)
12369         // instead of mSurfaceControl#getTransformHint because there's a race where SurfaceFlinger
12370         // can set an incorrect transform hint for a few frames before it is aware of the updated
12371         // display rotation.
12372         if (enableBufferTransformHintFromDisplay()) {
12373             return mPreviousTransformHint;
12374         }
12375 
12376         if (mSurfaceControl.isValid()) {
12377             return mSurfaceControl.getTransformHint();
12378         } else {
12379             return SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
12380         }
12381     }
12382 
12383     @Override
addOnBufferTransformHintChangedListener( OnBufferTransformHintChangedListener listener)12384     public void addOnBufferTransformHintChangedListener(
12385             OnBufferTransformHintChangedListener listener) {
12386         Objects.requireNonNull(listener);
12387         if (mTransformHintListeners.contains(listener)) {
12388             throw new IllegalArgumentException(
12389                     "attempt to call addOnBufferTransformHintChangedListener() "
12390                             + "with a previously registered listener");
12391         }
12392         mTransformHintListeners.add(listener);
12393     }
12394 
12395     @Override
removeOnBufferTransformHintChangedListener( OnBufferTransformHintChangedListener listener)12396     public void removeOnBufferTransformHintChangedListener(
12397             OnBufferTransformHintChangedListener listener) {
12398         Objects.requireNonNull(listener);
12399         mTransformHintListeners.remove(listener);
12400     }
12401 
dispatchTransformHintChanged(@urfaceControl.BufferTransform int hint)12402     private void dispatchTransformHintChanged(@SurfaceControl.BufferTransform int hint) {
12403         if (mTransformHintListeners.isEmpty()) {
12404             return;
12405         }
12406         ArrayList<OnBufferTransformHintChangedListener> listeners =
12407                 (ArrayList<OnBufferTransformHintChangedListener>) mTransformHintListeners.clone();
12408         for (int i = 0; i < listeners.size(); i++) {
12409             OnBufferTransformHintChangedListener listener = listeners.get(i);
12410             listener.onBufferTransformHintChanged(hint);
12411         }
12412     }
12413 
12414     /**
12415      * Shows or hides a Camera app compat toggle for stretched issues with the requested state
12416      * for the corresponding activity.
12417      *
12418      * @param showControl Whether the control should be shown or hidden.
12419      * @param transformationApplied Whether the treatment is already applied.
12420      * @param callback The callback executed when the user clicks on a control.
12421     */
requestCompatCameraControl(boolean showControl, boolean transformationApplied, ICompatCameraControlCallback callback)12422     public void requestCompatCameraControl(boolean showControl, boolean transformationApplied,
12423                 ICompatCameraControlCallback callback) {
12424         mActivityConfigCallback.requestCompatCameraControl(
12425                 showControl, transformationApplied, callback);
12426     }
12427 
wasRelayoutRequested()12428     boolean wasRelayoutRequested() {
12429         return mRelayoutRequested;
12430     }
12431 
forceWmRelayout()12432     void forceWmRelayout() {
12433        mForceNextWindowRelayout = true;
12434        scheduleTraversals();
12435     }
12436 
12437     /**
12438      * Returns the {@link OnBackInvokedDispatcher} on the decor view if one exists, or the
12439      * fallback {@link OnBackInvokedDispatcher} instance.
12440      */
12441     @NonNull
getOnBackInvokedDispatcher()12442     public WindowOnBackInvokedDispatcher getOnBackInvokedDispatcher() {
12443         return mOnBackInvokedDispatcher;
12444     }
12445 
12446     @NonNull
12447     @Override
findOnBackInvokedDispatcherForChild( @onNull View child, @NonNull View requester)12448     public OnBackInvokedDispatcher findOnBackInvokedDispatcherForChild(
12449             @NonNull View child, @NonNull View requester) {
12450         return getOnBackInvokedDispatcher();
12451     }
12452 
12453     /**
12454      * When this ViewRootImpl is added to the window manager, transfers the first
12455      * {@link OnBackInvokedCallback} to be called to the server.
12456      */
registerBackCallbackOnWindow()12457     private void registerBackCallbackOnWindow() {
12458         if (OnBackInvokedDispatcher.DEBUG) {
12459             Log.d(OnBackInvokedDispatcher.TAG, TextUtils.formatSimple(
12460                     "ViewRootImpl.registerBackCallbackOnWindow. Dispatcher:%s Package:%s "
12461                             + "IWindow:%s Session:%s",
12462                     mOnBackInvokedDispatcher, mBasePackageName, mWindow, mWindowSession));
12463         }
12464         mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow,
12465                 mImeBackAnimationController);
12466     }
12467 
sendBackKeyEvent(int action)12468     private void sendBackKeyEvent(int action) {
12469         long when = SystemClock.uptimeMillis();
12470         final KeyEvent ev = new KeyEvent(when, when, action,
12471                 KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
12472                 KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
12473                 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
12474                 InputDevice.SOURCE_KEYBOARD);
12475         enqueueInputEvent(ev, null /* receiver */, 0 /* flags */, true /* processImmediately */);
12476     }
12477 
registerCompatOnBackInvokedCallback()12478     private void registerCompatOnBackInvokedCallback() {
12479         mCompatOnBackInvokedCallback = () -> {
12480             try {
12481                 processingBackKey(true);
12482                 sendBackKeyEvent(KeyEvent.ACTION_DOWN);
12483                 sendBackKeyEvent(KeyEvent.ACTION_UP);
12484             } finally {
12485                 processingBackKey(false);
12486             }
12487         };
12488         if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) {
12489             Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher");
12490             return;
12491         }
12492         mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
12493                 OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatOnBackInvokedCallback);
12494     }
12495 
12496     @Override
setTouchableRegion(Region r)12497     public void setTouchableRegion(Region r) {
12498         if (r != null) {
12499             mTouchableRegion = new Region(r);
12500         } else {
12501             mTouchableRegion = null;
12502         }
12503         mLastGivenInsets.reset();
12504         requestLayout();
12505     }
12506 
getWindowSession()12507     IWindowSession getWindowSession() {
12508         return mWindowSession;
12509     }
12510 
registerCallbacksForSync(boolean syncBuffer, final SurfaceSyncGroup surfaceSyncGroup)12511     private void registerCallbacksForSync(boolean syncBuffer,
12512             final SurfaceSyncGroup surfaceSyncGroup) {
12513         if (!isHardwareEnabled()) {
12514             return;
12515         }
12516 
12517         if (DEBUG_BLAST) {
12518             Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer);
12519         }
12520 
12521         final Transaction t;
12522         if (mHasPendingTransactions) {
12523             t = new Transaction();
12524             t.merge(mPendingTransaction);
12525         } else {
12526             t = null;
12527         }
12528 
12529         mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
12530             @Override
12531             public void onFrameDraw(long frame) {
12532             }
12533 
12534             @Override
12535             public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
12536                 if (DEBUG_BLAST) {
12537                     Log.d(mTag,
12538                             "Received frameDrawingCallback syncResult=" + syncResult + " frameNum="
12539                                     + frame + ".");
12540                 }
12541                 if (t != null) {
12542                     mergeWithNextTransaction(t, frame);
12543                 }
12544 
12545                 // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
12546                 // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
12547                 // any blast sync or commit callback, and the code should directly call
12548                 // pendingDrawFinished.
12549                 if ((syncResult
12550                         & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
12551                     surfaceSyncGroup.addTransaction(
12552                             mBlastBufferQueue.gatherPendingTransactions(frame));
12553                     surfaceSyncGroup.markSyncReady();
12554                     return null;
12555                 }
12556 
12557                 if (DEBUG_BLAST) {
12558                     Log.d(mTag, "Setting up sync and frameCommitCallback");
12559                 }
12560 
12561                 if (syncBuffer) {
12562                     boolean result = mBlastBufferQueue.syncNextTransaction(transaction -> {
12563                         Runnable timeoutRunnable = () -> Log.e(mTag,
12564                                 "Failed to submit the sync transaction after 4s. Likely to ANR "
12565                                         + "soon");
12566                         mHandler.postDelayed(timeoutRunnable, 4000L * Build.HW_TIMEOUT_MULTIPLIER);
12567                         transaction.addTransactionCommittedListener(mSimpleExecutor,
12568                                 () -> mHandler.removeCallbacks(timeoutRunnable));
12569                         surfaceSyncGroup.addTransaction(transaction);
12570                         surfaceSyncGroup.markSyncReady();
12571                     });
12572                     if (!result) {
12573                         // syncNextTransaction can only return false if something is already trying
12574                         // to sync the same frame in the same BBQ. That shouldn't be possible, but
12575                         // if it did happen, invoke markSyncReady so the active SSG doesn't get
12576                         // stuck.
12577                         Log.w(mTag, "Unable to syncNextTransaction. Possibly something else is"
12578                                 + " trying to sync?");
12579                         surfaceSyncGroup.markSyncReady();
12580                     }
12581                 }
12582 
12583                 return didProduceBuffer -> {
12584                     if (DEBUG_BLAST) {
12585                         Log.d(mTag, "Received frameCommittedCallback"
12586                                 + " lastAttemptedDrawFrameNum=" + frame
12587                                 + " didProduceBuffer=" + didProduceBuffer);
12588                     }
12589 
12590                     // If frame wasn't drawn, clear out the next transaction so it doesn't affect
12591                     // the next draw attempt. The next transaction and transaction complete callback
12592                     // were only set for the current draw attempt.
12593                     if (!didProduceBuffer) {
12594                         mBlastBufferQueue.clearSyncTransaction();
12595 
12596                         // Gather the transactions that were sent to mergeWithNextTransaction
12597                         // since the frame didn't draw on this vsync. It's possible the frame will
12598                         // draw later, but it's better to not be sync than to block on a frame that
12599                         // may never come.
12600                         surfaceSyncGroup.addTransaction(
12601                                 mBlastBufferQueue.gatherPendingTransactions(frame));
12602                         surfaceSyncGroup.markSyncReady();
12603                         return;
12604                     }
12605 
12606                     // If we didn't request to sync a buffer, then we won't get the
12607                     // syncNextTransaction callback. Instead, just report back to the Syncer so it
12608                     // knows that this sync request is complete.
12609                     if (!syncBuffer) {
12610                         surfaceSyncGroup.markSyncReady();
12611                     }
12612                 };
12613             }
12614         });
12615     }
12616 
12617     /**
12618      * This code will ensure that if multiple SurfaceSyncGroups are created for the same
12619      * ViewRootImpl the SurfaceSyncGroups will maintain an order. The scenario that could occur
12620      * is the following:
12621      * <p>
12622      * 1. SSG1 is created that includes the target VRI. There could be other VRIs in SSG1
12623      * 2. The target VRI draws its frame and marks its own active SSG as ready, but SSG1 is still
12624      *    waiting on other things in the SSG
12625      * 3. Another SSG2 is created for the target VRI. The second frame renders and marks its own
12626      *    second SSG as complete. SSG2 has nothing else to wait on, so it will apply at this point,
12627      *    even though SSG1 has not finished.
12628      * 4. Frame2 will get to SF first and Frame1 will later get to SF when SSG1 completes.
12629      * <p>
12630      * The code below ensures the SSGs that contains the VRI maintain an order. We create a new SSG
12631      * that's a safeguard SSG. Its only job is to prevent the next active SSG from completing.
12632      * The current active SSG for VRI will add a transaction committed callback and when that's
12633      * invoked, it will mark the safeguard SSG as ready. If a new request to create a SSG comes
12634      * in and the safeguard SSG is not null, it's added as part of the new active SSG. A new
12635      * safeguard SSG is created to correspond to the new active SSG. This creates a chain to
12636      * ensure the latter SSG always waits for the former SSG's transaction to get to SF.
12637      */
safeguardOverlappingSyncs(SurfaceSyncGroup activeSurfaceSyncGroup)12638     private void safeguardOverlappingSyncs(SurfaceSyncGroup activeSurfaceSyncGroup) {
12639         SurfaceSyncGroup safeguardSsg = new SurfaceSyncGroup("Safeguard-" + mTag);
12640         // Always disable timeout on the safeguard sync
12641         safeguardSsg.toggleTimeout(false /* enable */);
12642         synchronized (mPreviousSyncSafeguardLock) {
12643             if (mPreviousSyncSafeguard != null) {
12644                 activeSurfaceSyncGroup.add(mPreviousSyncSafeguard, null /* runnable */);
12645                 // Temporarily disable the timeout on the SSG that will contain the buffer. This
12646                 // is to ensure we don't timeout the active SSG before the previous one completes to
12647                 // ensure the order is maintained. The previous SSG has a timeout on its own SSG
12648                 // so it's guaranteed to complete.
12649                 activeSurfaceSyncGroup.toggleTimeout(false /* enable */);
12650                 mPreviousSyncSafeguard.addSyncCompleteCallback(mSimpleExecutor, () -> {
12651                     // Once we receive that the previous sync guard has been invoked, we can re-add
12652                     // the timeout on the active sync to ensure we eventually complete so it's not
12653                     // stuck permanently.
12654                     activeSurfaceSyncGroup.toggleTimeout(true /*enable */);
12655                 });
12656             }
12657             mPreviousSyncSafeguard = safeguardSsg;
12658         }
12659 
12660         Transaction t = new Transaction();
12661         t.addTransactionCommittedListener(mSimpleExecutor, () -> {
12662             safeguardSsg.markSyncReady();
12663             synchronized (mPreviousSyncSafeguardLock) {
12664                 if (mPreviousSyncSafeguard == safeguardSsg) {
12665                     mPreviousSyncSafeguard = null;
12666                 }
12667             }
12668         });
12669         activeSurfaceSyncGroup.addTransaction(t);
12670     }
12671 
12672     @Override
getOrCreateSurfaceSyncGroup()12673     public SurfaceSyncGroup getOrCreateSurfaceSyncGroup() {
12674         boolean newSyncGroup = false;
12675         if (mActiveSurfaceSyncGroup == null) {
12676             mActiveSurfaceSyncGroup = new SurfaceSyncGroup(mTag);
12677             mActiveSurfaceSyncGroup.setAddedToSyncListener(() -> {
12678                 Runnable runnable = () -> {
12679                     // Check if it's already 0 because the timeout could have reset the count to
12680                     // 0 and we don't want to go negative.
12681                     if (mNumPausedForSync > 0) {
12682                         mNumPausedForSync--;
12683                     }
12684                     if (mNumPausedForSync == 0) {
12685                         mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
12686                         if (!mIsInTraversal) {
12687                             scheduleTraversals();
12688                         }
12689                     }
12690                 };
12691 
12692                 if (Thread.currentThread() == mThread) {
12693                     runnable.run();
12694                 } else {
12695                     mHandler.post(runnable);
12696                 }
12697             });
12698             newSyncGroup = true;
12699         }
12700 
12701         Trace.instant(Trace.TRACE_TAG_VIEW,
12702                 "getOrCreateSurfaceSyncGroup isNew=" + newSyncGroup + " " + mTag);
12703 
12704         if (DEBUG_BLAST) {
12705             if (newSyncGroup) {
12706                 Log.d(mTag, "Creating new active sync group " + mActiveSurfaceSyncGroup.getName());
12707             } else {
12708                 Log.d(mTag, "Return already created active sync group "
12709                         + mActiveSurfaceSyncGroup.getName());
12710             }
12711         }
12712 
12713         mNumPausedForSync++;
12714         mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT);
12715         mHandler.sendEmptyMessageDelayed(MSG_PAUSED_FOR_SYNC_TIMEOUT,
12716                 1000 * Build.HW_TIMEOUT_MULTIPLIER);
12717         return mActiveSurfaceSyncGroup;
12718     };
12719 
12720     private final Executor mSimpleExecutor = Runnable::run;
12721 
updateSyncInProgressCount(SurfaceSyncGroup syncGroup)12722     private void updateSyncInProgressCount(SurfaceSyncGroup syncGroup) {
12723         if (mAttachInfo.mThreadedRenderer == null) {
12724             return;
12725         }
12726 
12727         synchronized (sSyncProgressLock) {
12728             if (sNumSyncsInProgress++ == 0) {
12729                 HardwareRenderer.setRtAnimationsEnabled(false);
12730             }
12731         }
12732 
12733         syncGroup.addSyncCompleteCallback(mSimpleExecutor, () -> {
12734             synchronized (sSyncProgressLock) {
12735                 if (--sNumSyncsInProgress == 0) {
12736                     HardwareRenderer.setRtAnimationsEnabled(true);
12737                 }
12738             }
12739         });
12740     }
12741 
addToSync(SurfaceSyncGroup syncable)12742     void addToSync(SurfaceSyncGroup syncable) {
12743         if (mActiveSurfaceSyncGroup == null) {
12744             return;
12745         }
12746         mActiveSurfaceSyncGroup.add(syncable, null /* Runnable */);
12747     }
12748 
12749     @Override
setChildBoundingInsets(@onNull Rect insets)12750     public void setChildBoundingInsets(@NonNull Rect insets) {
12751         if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) {
12752             throw new IllegalArgumentException("Negative insets passed to setChildBoundingInsets.");
12753         }
12754         mChildBoundingInsets.set(insets);
12755         mChildBoundingInsetsChanged = true;
12756         scheduleTraversals();
12757     }
12758 
12759 
logAndTrace(String msg)12760     private void logAndTrace(String msg) {
12761         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
12762             Trace.instant(Trace.TRACE_TAG_VIEW, mTag + "-" + msg);
12763         }
12764         if (DEBUG_BLAST) {
12765             Log.d(mTag, msg);
12766         }
12767         EventLog.writeEvent(LOGTAG_VIEWROOT_DRAW_EVENT, mTag, msg);
12768     }
12769 
12770     /**
12771      * Views that are animating with the ThreadedRenderer don't use the normal invalidation
12772      * path, so the value won't be updated through performTraversals. This reads the votes
12773      * from those views.
12774      */
updateFrameRateFromThreadedRendererViews()12775     private void updateFrameRateFromThreadedRendererViews() {
12776         ArrayList<View> views = mThreadedRendererViews;
12777         for (int i = views.size() - 1; i >= 0; i--) {
12778             View view = views.get(i);
12779             View.AttachInfo attachInfo = view.mAttachInfo;
12780             if (attachInfo == null || attachInfo.mViewRootImpl != this) {
12781                 views.remove(i);
12782             } else {
12783                 view.votePreferredFrameRate();
12784             }
12785         }
12786     }
12787 
12788     /**
12789      * Sets the mPreferredFrameRateCategory from the high, high_hint, normal, and low counts.
12790      */
setCategoryFromCategoryCounts()12791     private void setCategoryFromCategoryCounts() {
12792         switch (mPreferredFrameRateCategory) {
12793             case FRAME_RATE_CATEGORY_LOW -> mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT;
12794             case FRAME_RATE_CATEGORY_NORMAL ->
12795                     mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT;
12796             case FRAME_RATE_CATEGORY_HIGH_HINT ->
12797                     mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT;
12798             case FRAME_RATE_CATEGORY_HIGH ->
12799                     mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
12800         }
12801 
12802         // If it's currently an intermittent update,
12803         // we should keep mPreferredFrameRateCategory as NORMAL
12804         if (intermittentUpdateState() == INTERMITTENT_STATE_INTERMITTENT) {
12805             return;
12806         }
12807 
12808         if (mFrameRateCategoryHighCount > 0) {
12809             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
12810         } else if (mFrameRateCategoryHighHintCount > 0) {
12811             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT;
12812         } else if (mFrameRateCategoryNormalCount > 0) {
12813             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NORMAL;
12814         } else if (mFrameRateCategoryLowCount > 0) {
12815             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW;
12816         }
12817     }
12818 
setPreferredFrameRateCategory(int preferredFrameRateCategory)12819     private void setPreferredFrameRateCategory(int preferredFrameRateCategory) {
12820         if (!shouldSetFrameRateCategory()) {
12821             return;
12822         }
12823 
12824         int frameRateCategory;
12825         int frameRateReason;
12826         String view;
12827 
12828         if (mIsFrameRateBoosting || mInsetsAnimationRunning) {
12829             frameRateCategory = FRAME_RATE_CATEGORY_HIGH;
12830             frameRateReason = FRAME_RATE_CATEGORY_REASON_BOOST;
12831             view = null;
12832         } else if (mIsTouchBoosting && preferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH_HINT) {
12833             frameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT;
12834             frameRateReason = FRAME_RATE_CATEGORY_REASON_TOUCH;
12835             view = null;
12836         } else {
12837             frameRateCategory = preferredFrameRateCategory;
12838             frameRateReason = mFrameRateCategoryChangeReason;
12839             view = mFrameRateCategoryView;
12840         }
12841 
12842         boolean traceFrameRateCategory = false;
12843         try {
12844             if (frameRateCategory != FRAME_RATE_CATEGORY_DEFAULT
12845                     && mLastPreferredFrameRateCategory != frameRateCategory) {
12846                 traceFrameRateCategory = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
12847                 if (traceFrameRateCategory) {
12848                     String reason = reasonToString(frameRateReason);
12849                     String sourceView = view == null ? "-" : view;
12850                     String category = categoryToString(frameRateCategory);
12851                     Trace.traceBegin(
12852                             Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRateCategory "
12853                                     + category + ", reason " + reason + ", "
12854                                     + sourceView);
12855                 }
12856                 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) {
12857                     mFrameRateTransaction.setFrameRateCategory(mSurfaceControl,
12858                         frameRateCategory, false).applyAsyncUnsafe();
12859                 }
12860                 mLastPreferredFrameRateCategory = frameRateCategory;
12861             }
12862         } catch (Exception e) {
12863             Log.e(mTag, "Unable to set frame rate category", e);
12864         } finally {
12865             if (traceFrameRateCategory) {
12866                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
12867             }
12868         }
12869     }
12870 
categoryToString(int frameRateCategory)12871     private static String categoryToString(int frameRateCategory) {
12872         String category;
12873         switch (frameRateCategory) {
12874             case FRAME_RATE_CATEGORY_NO_PREFERENCE -> category = "no preference";
12875             case FRAME_RATE_CATEGORY_LOW -> category = "low";
12876             case FRAME_RATE_CATEGORY_NORMAL -> category = "normal";
12877             case FRAME_RATE_CATEGORY_HIGH_HINT -> category = "high hint";
12878             case FRAME_RATE_CATEGORY_HIGH -> category = "high";
12879             default -> category = "default";
12880         }
12881         return category;
12882     }
12883 
reasonToString(int reason)12884     private static String reasonToString(int reason) {
12885         String str;
12886         switch (reason) {
12887             case FRAME_RATE_CATEGORY_REASON_INTERMITTENT -> str = "intermittent";
12888             case FRAME_RATE_CATEGORY_REASON_SMALL -> str = "small";
12889             case FRAME_RATE_CATEGORY_REASON_LARGE -> str = "large";
12890             case FRAME_RATE_CATEGORY_REASON_REQUESTED -> str = "requested";
12891             case FRAME_RATE_CATEGORY_REASON_INVALID -> str = "invalid frame rate";
12892             case FRAME_RATE_CATEGORY_REASON_VELOCITY -> str = "velocity";
12893             case FRAME_RATE_CATEGORY_REASON_UNKNOWN -> str = "unknown";
12894             case FRAME_RATE_CATEGORY_REASON_BOOST -> str = "boost";
12895             case FRAME_RATE_CATEGORY_REASON_TOUCH -> str = "touch";
12896             case FRAME_RATE_CATEGORY_REASON_CONFLICTED -> str = "conflicted";
12897             default -> str = String.valueOf(reason);
12898         }
12899         return str;
12900     }
12901 
setPreferredFrameRate(float preferredFrameRate)12902     private void setPreferredFrameRate(float preferredFrameRate) {
12903         if (!shouldSetFrameRate() || preferredFrameRate < 0) {
12904             return;
12905         }
12906 
12907         boolean traceFrameRate = false;
12908         try {
12909             if (mLastPreferredFrameRate != preferredFrameRate) {
12910                 traceFrameRate = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
12911                 if (traceFrameRate) {
12912                     Trace.traceBegin(
12913                             Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate "
12914                                 + preferredFrameRate + " compatibility "
12915                                 + mFrameRateCompatibility);
12916                 }
12917                 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) {
12918                     if (preferredFrameRate > 0) {
12919                         mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate,
12920                                 mFrameRateCompatibility);
12921                     } else {
12922                         mFrameRateTransaction.clearFrameRate(mSurfaceControl);
12923                     }
12924                     mFrameRateTransaction.applyAsyncUnsafe();
12925                 }
12926                 mLastPreferredFrameRate = preferredFrameRate;
12927             }
12928         } catch (Exception e) {
12929             Log.e(mTag, "Unable to set frame rate", e);
12930         } finally {
12931             if (traceFrameRate) {
12932                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
12933             }
12934         }
12935     }
12936 
shouldSetFrameRateCategory()12937     private boolean shouldSetFrameRateCategory() {
12938         // use toolkitSetFrameRate flag to gate the change
12939         return shouldEnableDvrr() && mSurface.isValid() && shouldEnableDvrr();
12940     }
12941 
shouldSetFrameRate()12942     private boolean shouldSetFrameRate() {
12943         // use toolkitSetFrameRate flag to gate the change
12944         return shouldEnableDvrr() && mSurface.isValid() && mPreferredFrameRate >= 0
12945                 && !mIsFrameRateConflicted;
12946     }
12947 
shouldTouchBoost(int motionEventAction, int windowType)12948     private boolean shouldTouchBoost(int motionEventAction, int windowType) {
12949         // boost for almost all input
12950         boolean desiredAction = motionEventAction != MotionEvent.ACTION_OUTSIDE;
12951         boolean undesiredType = windowType == TYPE_INPUT_METHOD
12952                 && sToolkitFrameRateTypingReadOnlyFlagValue;
12953         // use toolkitSetFrameRate flag to gate the change
12954         return desiredAction && !undesiredType && shouldEnableDvrr()
12955                 && getFrameRateBoostOnTouchEnabled();
12956     }
12957 
12958     /**
12959      * Allow Views to vote for the preferred frame rate category
12960      *
12961      * @param frameRateCategory the preferred frame rate category of a View
12962      */
12963     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
votePreferredFrameRateCategory(int frameRateCategory, int reason, View view)12964     public void votePreferredFrameRateCategory(int frameRateCategory, int reason, View view) {
12965         if (frameRateCategory > mPreferredFrameRateCategory) {
12966             mPreferredFrameRateCategory = frameRateCategory;
12967             mFrameRateCategoryChangeReason = reason;
12968             // mFrameRateCategoryView = view == null ? "-" : view.getClass().getSimpleName();
12969         }
12970         mDrawnThisFrame = true;
12971     }
12972 
12973     /**
12974      * Mark a View as having an active ThreadedRenderer animation. This is used for
12975      * RenderNodeAnimators and AnimatedVectorDrawables. When the animation stops,
12976      * {@link #removeThreadedRendererView(View)} must be called.
12977      * @param view The View with the ThreadedRenderer animation that started.
12978      */
addThreadedRendererView(View view)12979     public void addThreadedRendererView(View view) {
12980         if (shouldEnableDvrr() && !mThreadedRendererViews.contains(view)) {
12981             mThreadedRendererViews.add(view);
12982         }
12983     }
12984 
12985     /**
12986      * When a ThreadedRenderer animation ends, the View that is associated with it using
12987      * {@link #addThreadedRendererView(View)} must be removed with a call to this method.
12988      * @param view The View whose ThreadedRender animation has stopped.
12989      */
removeThreadedRendererView(View view)12990     public void removeThreadedRendererView(View view) {
12991         mThreadedRendererViews.remove(view);
12992         if (shouldEnableDvrr()
12993                 && !mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) {
12994             mInvalidationIdleMessagePosted = true;
12995             mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS);
12996         }
12997     }
12998 
12999     /**
13000      * Returns {@link #INTERMITTENT_STATE_INTERMITTENT} when the ViewRootImpl has only been
13001      * updated intermittently, {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} when it is
13002      * not updated intermittently, and {@link #INTERMITTENT_STATE_IN_TRANSITION} when it
13003      * is transitioning between {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} and
13004      * {@link #INTERMITTENT_STATE_INTERMITTENT}.
13005      */
intermittentUpdateState()13006     int intermittentUpdateState() {
13007         if (mMinusOneFrameIntervalMillis + mMinusTwoFrameIntervalMillis
13008                 < INFREQUENT_UPDATE_INTERVAL_MILLIS) {
13009             return INTERMITTENT_STATE_NOT_INTERMITTENT;
13010         }
13011         if (mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS) {
13012             return INTERMITTENT_STATE_INTERMITTENT;
13013         }
13014         return INTERMITTENT_STATE_IN_TRANSITION;
13015     }
13016 
13017     /**
13018      * Returns whether a View should vote for frame rate category. When the category is HIGH
13019      * already, there's no need to calculate the category on the View and vote.
13020      */
shouldCheckFrameRateCategory()13021     public boolean shouldCheckFrameRateCategory() {
13022         return mPreferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH;
13023     }
13024 
13025     /**
13026      * Returns whether a View should vote for frame rate. When the maximum frame rate has already
13027      * been voted for, there's no point in calculating and voting for the frame rate. When
13028      * isDirect is false, then it will return false when the velocity-calculated frame rate
13029      * can be avoided.
13030      * @param isDirect true when the frame rate has been set directly on the View or false if
13031      *                 the calculation is based only on velocity.
13032      */
shouldCheckFrameRate(boolean isDirect)13033     public boolean shouldCheckFrameRate(boolean isDirect) {
13034         return mPreferredFrameRate < MAX_FRAME_RATE
13035                 || (!isDirect && !sToolkitFrameRateVelocityMappingReadOnlyFlagValue
13036                 && mPreferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH);
13037     }
13038 
13039     /**
13040      * Allow Views to vote for the preferred frame rate and compatibility.
13041      * When determining the preferred frame rate value,
13042      * we follow this logic: If no preferred frame rate has been set yet,
13043      * we assign the value of frameRate as the preferred frame rate.
13044      * IF there are multiple frame rates are voted:
13045      * 1. There is a frame rate is a multiple of all other frame rates.
13046      * We choose this frmae rate to be the one to be set.
13047      * 2. There is no frame rate can be a multiple of others
13048      * We set category to HIGH if the maximum frame rate is greater than 60.
13049      * Otherwise, we set category to NORMAL.
13050      *
13051      * Use FRAME_RATE_COMPATIBILITY_GTE for velocity and FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
13052      * for TextureView video play and user requested frame rate.
13053      *
13054      * @param frameRate the preferred frame rate of a View
13055      * @param frameRateCompatibility the preferred frame rate compatibility of a View
13056      */
13057     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
votePreferredFrameRate(float frameRate, int frameRateCompatibility)13058     public void votePreferredFrameRate(float frameRate, int frameRateCompatibility) {
13059         if (frameRate <= 0) {
13060             return;
13061         }
13062         if (frameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE) {
13063             mIsTouchBoosting = false;
13064             mIsFrameRateBoosting = false;
13065             if (!sToolkitFrameRateVelocityMappingReadOnlyFlagValue) {
13066                 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
13067                 mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
13068                 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_VELOCITY;
13069                 mFrameRateCategoryView = null;
13070                 mDrawnThisFrame = true;
13071                 return;
13072             }
13073         }
13074         float nextFrameRate;
13075         int nextFrameRateCompatibility;
13076         if (frameRate > mPreferredFrameRate) {
13077             nextFrameRate = frameRate;
13078             nextFrameRateCompatibility = frameRateCompatibility;
13079         } else {
13080             nextFrameRate = mPreferredFrameRate;
13081             nextFrameRateCompatibility = mFrameRateCompatibility;
13082         }
13083 
13084         if (mPreferredFrameRate > 0 && mPreferredFrameRate % frameRate != 0
13085                 && frameRate % mPreferredFrameRate != 0) {
13086             mIsFrameRateConflicted = true;
13087             if (nextFrameRate > 60 && mFrameRateCategoryHighCount != FRAME_RATE_CATEGORY_COUNT) {
13088                 mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
13089                 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_CONFLICTED;
13090                 mFrameRateCategoryView = null;
13091             } else if (mFrameRateCategoryHighCount == 0 && mFrameRateCategoryHighHintCount == 0
13092                     && mFrameRateCategoryNormalCount < FRAME_RATE_CATEGORY_COUNT) {
13093                 mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT;
13094                 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_CONFLICTED;
13095                 mFrameRateCategoryView = null;
13096             }
13097         }
13098 
13099         mPreferredFrameRate = nextFrameRate;
13100         mFrameRateCompatibility = nextFrameRateCompatibility;
13101         mDrawnThisFrame = true;
13102     }
13103 
13104     /**
13105      * Get the value of mPreferredFrameRateCategory
13106      */
13107     @VisibleForTesting
getPreferredFrameRateCategory()13108     public int getPreferredFrameRateCategory() {
13109         return mPreferredFrameRateCategory;
13110     }
13111 
13112     /**
13113      * Get the value of mLastPreferredFrameRateCategory
13114      */
13115     @VisibleForTesting
getLastPreferredFrameRateCategory()13116     public int getLastPreferredFrameRateCategory() {
13117         return mLastPreferredFrameRateCategory;
13118     }
13119 
13120     /**
13121      * Get the value of mPreferredFrameRate
13122      */
13123     @VisibleForTesting
getPreferredFrameRate()13124     public float getPreferredFrameRate() {
13125         return mPreferredFrameRate >= 0 ? mPreferredFrameRate : mLastPreferredFrameRate;
13126     }
13127 
13128     /**
13129      * Get the value of mLastPreferredFrameRate
13130      */
13131     @VisibleForTesting
getLastPreferredFrameRate()13132     public float getLastPreferredFrameRate() {
13133         return mLastPreferredFrameRate;
13134     }
13135 
13136     /**
13137      * Returns whether touch boost is currently enabled.
13138      */
13139     @VisibleForTesting
getIsTouchBoosting()13140     public boolean getIsTouchBoosting() {
13141         return mIsTouchBoosting;
13142     }
13143 
13144     /**
13145      * Get the value of mFrameRateCompatibility
13146      */
13147     @VisibleForTesting
getFrameRateCompatibility()13148     public int getFrameRateCompatibility() {
13149         return mFrameRateCompatibility;
13150     }
13151 
13152     /**
13153      * Get the value of mIsFrameRateBoosting
13154      */
13155     @VisibleForTesting
getIsFrameRateBoosting()13156     public boolean getIsFrameRateBoosting() {
13157         return mIsFrameRateBoosting;
13158     }
13159 
13160     /**
13161      * Get the value of mFrameRateBoostOnTouchEnabled
13162      * Can be used to checked if touch boost is enabled. The default value is true.
13163      */
13164     @VisibleForTesting
getFrameRateBoostOnTouchEnabled()13165     public boolean getFrameRateBoostOnTouchEnabled() {
13166         return mWindowAttributes.getFrameRateBoostOnTouchEnabled();
13167     }
13168 
boostFrameRate(int boostTimeOut)13169     private void boostFrameRate(int boostTimeOut) {
13170         mIsFrameRateBoosting = true;
13171         mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT);
13172         mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT,
13173                 boostTimeOut);
13174     }
13175 
13176     /**
13177      * Set the default back key callback for windowless window, to forward the back key event
13178      * to host app.
13179      * MUST NOT call this method for normal window.
13180      */
setBackKeyCallbackForWindowlessWindow(@onNull Predicate<KeyEvent> callback)13181     void setBackKeyCallbackForWindowlessWindow(@NonNull Predicate<KeyEvent> callback) {
13182         mWindowlessBackKeyCallback = callback;
13183     }
13184 
recordViewPercentage(float percentage)13185     void recordViewPercentage(float percentage) {
13186         if (!Trace.isEnabled()) return;
13187         // Record the largest view of percentage to the display size.
13188         mLargestChildPercentage = Math.max(percentage, mLargestChildPercentage);
13189     }
13190 
13191     /**
13192      * Get the value of mIsFrameRatePowerSavingsBalanced
13193      * Can be used to checked if toolkit dVRR feature is enabled. The default value is true.
13194      */
13195     @VisibleForTesting
isFrameRatePowerSavingsBalanced()13196     public boolean isFrameRatePowerSavingsBalanced() {
13197         if (sToolkitSetFrameRateReadOnlyFlagValue) {
13198             return mWindowAttributes.isFrameRatePowerSavingsBalanced();
13199         }
13200         return true;
13201     }
13202 
13203     /**
13204      * Get the value of mIsFrameRateConflicted
13205      * Can be used to checked if there is a conflict of frame rate votes.
13206      */
13207     @VisibleForTesting
isFrameRateConflicted()13208     public boolean isFrameRateConflicted() {
13209         return mIsFrameRateConflicted;
13210     }
13211 
shouldEnableDvrr()13212     private boolean shouldEnableDvrr() {
13213         // uncomment this when we are ready for enabling dVRR
13214         if (sEnableVrr && sToolkitFrameRateViewEnablingReadOnlyFlagValue) {
13215             return sToolkitSetFrameRateReadOnlyFlagValue && isFrameRatePowerSavingsBalanced();
13216         }
13217         return false;
13218     }
13219 
removeVrrMessages()13220     private void removeVrrMessages() {
13221         mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT);
13222         mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
13223         if (mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) {
13224             mInvalidationIdleMessagePosted = false;
13225             mHandler.removeMessages(MSG_CHECK_INVALIDATION_IDLE);
13226         }
13227     }
13228 
13229     /**
13230      * This function is mainly used for migrating infrequent layer logic
13231      * from SurfaceFlinger to Toolkit.
13232      * The infrequent layer logic includes:
13233      * - NORMAL for infrequent update: FT2-FT1 > 100 && FT3-FT2 > 100.
13234      * - HIGH/NORMAL based on size for frequent update: (FT3-FT2) + (FT2 - FT1) < 100.
13235      * - otherwise, use the previous category value.
13236      */
updateInfrequentCount()13237     private void updateInfrequentCount() {
13238         long currentTimeMillis = mAttachInfo.mDrawingTime;
13239         int timeIntervalMillis =
13240                 (int) Math.min(Integer.MAX_VALUE, currentTimeMillis - mLastUpdateTimeMillis);
13241         mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis;
13242         mMinusOneFrameIntervalMillis = timeIntervalMillis;
13243 
13244         mLastUpdateTimeMillis = currentTimeMillis;
13245         if (mThreadedRendererViews.isEmpty() && timeIntervalMillis + mMinusTwoFrameIntervalMillis
13246                 >= INFREQUENT_UPDATE_INTERVAL_MILLIS) {
13247             int infrequentUpdateCount = mInfrequentUpdateCount;
13248             mInfrequentUpdateCount = infrequentUpdateCount == INFREQUENT_UPDATE_COUNTS
13249                     ? infrequentUpdateCount : infrequentUpdateCount + 1;
13250         } else {
13251             mInfrequentUpdateCount = 0;
13252         }
13253     }
13254 }
13255