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