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