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