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