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