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