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