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