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