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