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