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