ViewRootImpl.java revision e6a026bdfed45b4085410d1ecd042b1214cedb0a
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
3309                // draw(...) might invoke post-draw, which might register the next callback already.
3310                final FrameDrawingCallback callback = mNextRtFrameCallback;
3311                mNextRtFrameCallback = null;
3312                mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this, callback);
3313            } else {
3314                // If we get here with a disabled & requested hardware renderer, something went
3315                // wrong (an invalidate posted right before we destroyed the hardware surface
3316                // for instance) so we should just bail out. Locking the surface with software
3317                // rendering at this point would lock it forever and prevent hardware renderer
3318                // from doing its job when it comes back.
3319                // Before we request a new frame we must however attempt to reinitiliaze the
3320                // hardware renderer if it's in requested state. This would happen after an
3321                // eglTerminate() for instance.
3322                if (mAttachInfo.mThreadedRenderer != null &&
3323                        !mAttachInfo.mThreadedRenderer.isEnabled() &&
3324                        mAttachInfo.mThreadedRenderer.isRequested() &&
3325                        mSurface.isValid()) {
3326
3327                    try {
3328                        mAttachInfo.mThreadedRenderer.initializeIfNeeded(
3329                                mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
3330                    } catch (OutOfResourcesException e) {
3331                        handleOutOfResourcesException(e);
3332                        return false;
3333                    }
3334
3335                    mFullRedrawNeeded = true;
3336                    scheduleTraversals();
3337                    return false;
3338                }
3339
3340                if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
3341                        scalingRequired, dirty, surfaceInsets)) {
3342                    return false;
3343                }
3344            }
3345        }
3346
3347        if (animating) {
3348            mFullRedrawNeeded = true;
3349            scheduleTraversals();
3350        }
3351        return useAsyncReport;
3352    }
3353
3354    /**
3355     * @return true if drawing was successful, false if an error occurred
3356     */
3357    private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
3358            boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
3359
3360        // Draw with software renderer.
3361        final Canvas canvas;
3362
3363        // We already have the offset of surfaceInsets in xoff, yoff and dirty region,
3364        // therefore we need to add it back when moving the dirty region.
3365        int dirtyXOffset = xoff;
3366        int dirtyYOffset = yoff;
3367        if (surfaceInsets != null) {
3368            dirtyXOffset += surfaceInsets.left;
3369            dirtyYOffset += surfaceInsets.top;
3370        }
3371
3372        try {
3373            dirty.offset(-dirtyXOffset, -dirtyYOffset);
3374            final int left = dirty.left;
3375            final int top = dirty.top;
3376            final int right = dirty.right;
3377            final int bottom = dirty.bottom;
3378
3379            canvas = mSurface.lockCanvas(dirty);
3380
3381            // The dirty rectangle can be modified by Surface.lockCanvas()
3382            //noinspection ConstantConditions
3383            if (left != dirty.left || top != dirty.top || right != dirty.right
3384                    || bottom != dirty.bottom) {
3385                attachInfo.mIgnoreDirtyState = true;
3386            }
3387
3388            // TODO: Do this in native
3389            canvas.setDensity(mDensity);
3390        } catch (Surface.OutOfResourcesException e) {
3391            handleOutOfResourcesException(e);
3392            return false;
3393        } catch (IllegalArgumentException e) {
3394            Log.e(mTag, "Could not lock surface", e);
3395            // Don't assume this is due to out of memory, it could be
3396            // something else, and if it is something else then we could
3397            // kill stuff (or ourself) for no reason.
3398            mLayoutRequested = true;    // ask wm for a new surface next time.
3399            return false;
3400        } finally {
3401            dirty.offset(dirtyXOffset, dirtyYOffset);  // Reset to the original value.
3402        }
3403
3404        try {
3405            if (DEBUG_ORIENTATION || DEBUG_DRAW) {
3406                Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
3407                        + canvas.getWidth() + ", h=" + canvas.getHeight());
3408                //canvas.drawARGB(255, 255, 0, 0);
3409            }
3410
3411            // If this bitmap's format includes an alpha channel, we
3412            // need to clear it before drawing so that the child will
3413            // properly re-composite its drawing on a transparent
3414            // background. This automatically respects the clip/dirty region
3415            // or
3416            // If we are applying an offset, we need to clear the area
3417            // where the offset doesn't appear to avoid having garbage
3418            // left in the blank areas.
3419            if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
3420                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
3421            }
3422
3423            dirty.setEmpty();
3424            mIsAnimating = false;
3425            mView.mPrivateFlags |= View.PFLAG_DRAWN;
3426
3427            if (DEBUG_DRAW) {
3428                Context cxt = mView.getContext();
3429                Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
3430                        ", metrics=" + cxt.getResources().getDisplayMetrics() +
3431                        ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
3432            }
3433            try {
3434                canvas.translate(-xoff, -yoff);
3435                if (mTranslator != null) {
3436                    mTranslator.translateCanvas(canvas);
3437                }
3438                canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
3439                attachInfo.mSetIgnoreDirtyState = false;
3440
3441                mView.draw(canvas);
3442
3443                drawAccessibilityFocusedDrawableIfNeeded(canvas);
3444            } finally {
3445                if (!attachInfo.mSetIgnoreDirtyState) {
3446                    // Only clear the flag if it was not set during the mView.draw() call
3447                    attachInfo.mIgnoreDirtyState = false;
3448                }
3449            }
3450        } finally {
3451            try {
3452                surface.unlockCanvasAndPost(canvas);
3453            } catch (IllegalArgumentException e) {
3454                Log.e(mTag, "Could not unlock surface", e);
3455                mLayoutRequested = true;    // ask wm for a new surface next time.
3456                //noinspection ReturnInsideFinallyBlock
3457                return false;
3458            }
3459
3460            if (LOCAL_LOGV) {
3461                Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
3462            }
3463        }
3464        return true;
3465    }
3466
3467    /**
3468     * We want to draw a highlight around the current accessibility focused.
3469     * Since adding a style for all possible view is not a viable option we
3470     * have this specialized drawing method.
3471     *
3472     * Note: We are doing this here to be able to draw the highlight for
3473     *       virtual views in addition to real ones.
3474     *
3475     * @param canvas The canvas on which to draw.
3476     */
3477    private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
3478        final Rect bounds = mAttachInfo.mTmpInvalRect;
3479        if (getAccessibilityFocusedRect(bounds)) {
3480            final Drawable drawable = getAccessibilityFocusedDrawable();
3481            if (drawable != null) {
3482                drawable.setBounds(bounds);
3483                drawable.draw(canvas);
3484            }
3485        } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
3486            mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
3487        }
3488    }
3489
3490    private boolean getAccessibilityFocusedRect(Rect bounds) {
3491        final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
3492        if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
3493            return false;
3494        }
3495
3496        final View host = mAccessibilityFocusedHost;
3497        if (host == null || host.mAttachInfo == null) {
3498            return false;
3499        }
3500
3501        final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
3502        if (provider == null) {
3503            host.getBoundsOnScreen(bounds, true);
3504        } else if (mAccessibilityFocusedVirtualView != null) {
3505            mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
3506        } else {
3507            return false;
3508        }
3509
3510        // Transform the rect into window-relative coordinates.
3511        final AttachInfo attachInfo = mAttachInfo;
3512        bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
3513        bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
3514        if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
3515                attachInfo.mViewRootImpl.mHeight)) {
3516            // If no intersection, set bounds to empty.
3517            bounds.setEmpty();
3518        }
3519        return !bounds.isEmpty();
3520    }
3521
3522    private Drawable getAccessibilityFocusedDrawable() {
3523        // Lazily load the accessibility focus drawable.
3524        if (mAttachInfo.mAccessibilityFocusDrawable == null) {
3525            final TypedValue value = new TypedValue();
3526            final boolean resolved = mView.mContext.getTheme().resolveAttribute(
3527                    R.attr.accessibilityFocusedDrawable, value, true);
3528            if (resolved) {
3529                mAttachInfo.mAccessibilityFocusDrawable =
3530                        mView.mContext.getDrawable(value.resourceId);
3531            }
3532        }
3533        return mAttachInfo.mAccessibilityFocusDrawable;
3534    }
3535
3536    /**
3537     * Requests that the root render node is invalidated next time we perform a draw, such that
3538     * {@link WindowCallbacks#onPostDraw} gets called.
3539     */
3540    public void requestInvalidateRootRenderNode() {
3541        mInvalidateRootRequested = true;
3542    }
3543
3544    boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
3545        final Rect ci = mAttachInfo.mContentInsets;
3546        final Rect vi = mAttachInfo.mVisibleInsets;
3547        int scrollY = 0;
3548        boolean handled = false;
3549
3550        if (vi.left > ci.left || vi.top > ci.top
3551                || vi.right > ci.right || vi.bottom > ci.bottom) {
3552            // We'll assume that we aren't going to change the scroll
3553            // offset, since we want to avoid that unless it is actually
3554            // going to make the focus visible...  otherwise we scroll
3555            // all over the place.
3556            scrollY = mScrollY;
3557            // We can be called for two different situations: during a draw,
3558            // to update the scroll position if the focus has changed (in which
3559            // case 'rectangle' is null), or in response to a
3560            // requestChildRectangleOnScreen() call (in which case 'rectangle'
3561            // is non-null and we just want to scroll to whatever that
3562            // rectangle is).
3563            final View focus = mView.findFocus();
3564            if (focus == null) {
3565                return false;
3566            }
3567            View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
3568            if (focus != lastScrolledFocus) {
3569                // If the focus has changed, then ignore any requests to scroll
3570                // to a rectangle; first we want to make sure the entire focus
3571                // view is visible.
3572                rectangle = null;
3573            }
3574            if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
3575                    + " rectangle=" + rectangle + " ci=" + ci
3576                    + " vi=" + vi);
3577            if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
3578                // Optimization: if the focus hasn't changed since last
3579                // time, and no layout has happened, then just leave things
3580                // as they are.
3581                if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
3582                        + mScrollY + " vi=" + vi.toShortString());
3583            } else {
3584                // We need to determine if the currently focused view is
3585                // within the visible part of the window and, if not, apply
3586                // a pan so it can be seen.
3587                mLastScrolledFocus = new WeakReference<View>(focus);
3588                mScrollMayChange = false;
3589                if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
3590                // Try to find the rectangle from the focus view.
3591                if (focus.getGlobalVisibleRect(mVisRect, null)) {
3592                    if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
3593                            + mView.getWidth() + " h=" + mView.getHeight()
3594                            + " ci=" + ci.toShortString()
3595                            + " vi=" + vi.toShortString());
3596                    if (rectangle == null) {
3597                        focus.getFocusedRect(mTempRect);
3598                        if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
3599                                + ": focusRect=" + mTempRect.toShortString());
3600                        if (mView instanceof ViewGroup) {
3601                            ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3602                                    focus, mTempRect);
3603                        }
3604                        if (DEBUG_INPUT_RESIZE) Log.v(mTag,
3605                                "Focus in window: focusRect="
3606                                + mTempRect.toShortString()
3607                                + " visRect=" + mVisRect.toShortString());
3608                    } else {
3609                        mTempRect.set(rectangle);
3610                        if (DEBUG_INPUT_RESIZE) Log.v(mTag,
3611                                "Request scroll to rect: "
3612                                + mTempRect.toShortString()
3613                                + " visRect=" + mVisRect.toShortString());
3614                    }
3615                    if (mTempRect.intersect(mVisRect)) {
3616                        if (DEBUG_INPUT_RESIZE) Log.v(mTag,
3617                                "Focus window visible rect: "
3618                                + mTempRect.toShortString());
3619                        if (mTempRect.height() >
3620                                (mView.getHeight()-vi.top-vi.bottom)) {
3621                            // If the focus simply is not going to fit, then
3622                            // best is probably just to leave things as-is.
3623                            if (DEBUG_INPUT_RESIZE) Log.v(mTag,
3624                                    "Too tall; leaving scrollY=" + scrollY);
3625                        }
3626                        // Next, check whether top or bottom is covered based on the non-scrolled
3627                        // position, and calculate new scrollY (or set it to 0).
3628                        // We can't keep using mScrollY here. For example mScrollY is non-zero
3629                        // due to IME, then IME goes away. The current value of mScrollY leaves top
3630                        // and bottom both visible, but we still need to scroll it back to 0.
3631                        else if (mTempRect.top < vi.top) {
3632                            scrollY = mTempRect.top - vi.top;
3633                            if (DEBUG_INPUT_RESIZE) Log.v(mTag,
3634                                    "Top covered; scrollY=" + scrollY);
3635                        } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) {
3636                            scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom);
3637                            if (DEBUG_INPUT_RESIZE) Log.v(mTag,
3638                                    "Bottom covered; scrollY=" + scrollY);
3639                        } else {
3640                            scrollY = 0;
3641                        }
3642                        handled = true;
3643                    }
3644                }
3645            }
3646        }
3647
3648        if (scrollY != mScrollY) {
3649            if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
3650                    + mScrollY + " , new=" + scrollY);
3651            if (!immediate) {
3652                if (mScroller == null) {
3653                    mScroller = new Scroller(mView.getContext());
3654                }
3655                mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
3656            } else if (mScroller != null) {
3657                mScroller.abortAnimation();
3658            }
3659            mScrollY = scrollY;
3660        }
3661
3662        return handled;
3663    }
3664
3665    /**
3666     * @hide
3667     */
3668    public View getAccessibilityFocusedHost() {
3669        return mAccessibilityFocusedHost;
3670    }
3671
3672    /**
3673     * @hide
3674     */
3675    public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
3676        return mAccessibilityFocusedVirtualView;
3677    }
3678
3679    void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
3680        // If we have a virtual view with accessibility focus we need
3681        // to clear the focus and invalidate the virtual view bounds.
3682        if (mAccessibilityFocusedVirtualView != null) {
3683
3684            AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
3685            View focusHost = mAccessibilityFocusedHost;
3686
3687            // Wipe the state of the current accessibility focus since
3688            // the call into the provider to clear accessibility focus
3689            // will fire an accessibility event which will end up calling
3690            // this method and we want to have clean state when this
3691            // invocation happens.
3692            mAccessibilityFocusedHost = null;
3693            mAccessibilityFocusedVirtualView = null;
3694
3695            // Clear accessibility focus on the host after clearing state since
3696            // this method may be reentrant.
3697            focusHost.clearAccessibilityFocusNoCallbacks(
3698                    AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
3699
3700            AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
3701            if (provider != null) {
3702                // Invalidate the area of the cleared accessibility focus.
3703                focusNode.getBoundsInParent(mTempRect);
3704                focusHost.invalidate(mTempRect);
3705                // Clear accessibility focus in the virtual node.
3706                final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
3707                        focusNode.getSourceNodeId());
3708                provider.performAction(virtualNodeId,
3709                        AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
3710            }
3711            focusNode.recycle();
3712        }
3713        if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view))  {
3714            // Clear accessibility focus in the view.
3715            mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(
3716                    AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
3717        }
3718
3719        // Set the new focus host and node.
3720        mAccessibilityFocusedHost = view;
3721        mAccessibilityFocusedVirtualView = node;
3722
3723        if (mAttachInfo.mThreadedRenderer != null) {
3724            mAttachInfo.mThreadedRenderer.invalidateRoot();
3725        }
3726    }
3727
3728    boolean hasPointerCapture() {
3729        return mPointerCapture;
3730    }
3731
3732    void requestPointerCapture(boolean enabled) {
3733        if (mPointerCapture == enabled) {
3734            return;
3735        }
3736        InputManager.getInstance().requestPointerCapture(mAttachInfo.mWindowToken, enabled);
3737    }
3738
3739    private void handlePointerCaptureChanged(boolean hasCapture) {
3740        if (mPointerCapture == hasCapture) {
3741            return;
3742        }
3743        mPointerCapture = hasCapture;
3744        if (mView != null) {
3745            mView.dispatchPointerCaptureChanged(hasCapture);
3746        }
3747    }
3748
3749    @Override
3750    public void requestChildFocus(View child, View focused) {
3751        if (DEBUG_INPUT_RESIZE) {
3752            Log.v(mTag, "Request child focus: focus now " + focused);
3753        }
3754        checkThread();
3755        scheduleTraversals();
3756    }
3757
3758    @Override
3759    public void clearChildFocus(View child) {
3760        if (DEBUG_INPUT_RESIZE) {
3761            Log.v(mTag, "Clearing child focus");
3762        }
3763        checkThread();
3764        scheduleTraversals();
3765    }
3766
3767    @Override
3768    public ViewParent getParentForAccessibility() {
3769        return null;
3770    }
3771
3772    @Override
3773    public void focusableViewAvailable(View v) {
3774        checkThread();
3775        if (mView != null) {
3776            if (!mView.hasFocus()) {
3777                if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) {
3778                    v.requestFocus();
3779                }
3780            } else {
3781                // the one case where will transfer focus away from the current one
3782                // is if the current view is a view group that prefers to give focus
3783                // to its children first AND the view is a descendant of it.
3784                View focused = mView.findFocus();
3785                if (focused instanceof ViewGroup) {
3786                    ViewGroup group = (ViewGroup) focused;
3787                    if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3788                            && isViewDescendantOf(v, focused)) {
3789                        v.requestFocus();
3790                    }
3791                }
3792            }
3793        }
3794    }
3795
3796    @Override
3797    public void recomputeViewAttributes(View child) {
3798        checkThread();
3799        if (mView == child) {
3800            mAttachInfo.mRecomputeGlobalAttributes = true;
3801            if (!mWillDrawSoon) {
3802                scheduleTraversals();
3803            }
3804        }
3805    }
3806
3807    void dispatchDetachedFromWindow() {
3808        mFirstInputStage.onDetachedFromWindow();
3809        if (mView != null && mView.mAttachInfo != null) {
3810            mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
3811            mView.dispatchDetachedFromWindow();
3812        }
3813
3814        mAccessibilityInteractionConnectionManager.ensureNoConnection();
3815        mAccessibilityManager.removeAccessibilityStateChangeListener(
3816                mAccessibilityInteractionConnectionManager);
3817        mAccessibilityManager.removeHighTextContrastStateChangeListener(
3818                mHighContrastTextManager);
3819        removeSendWindowContentChangedCallback();
3820
3821        destroyHardwareRenderer();
3822
3823        setAccessibilityFocus(null, null);
3824
3825        mView.assignParent(null);
3826        mView = null;
3827        mAttachInfo.mRootView = null;
3828
3829        mSurface.release();
3830
3831        if (mInputQueueCallback != null && mInputQueue != null) {
3832            mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
3833            mInputQueue.dispose();
3834            mInputQueueCallback = null;
3835            mInputQueue = null;
3836        }
3837        if (mInputEventReceiver != null) {
3838            mInputEventReceiver.dispose();
3839            mInputEventReceiver = null;
3840        }
3841        try {
3842            mWindowSession.remove(mWindow);
3843        } catch (RemoteException e) {
3844        }
3845
3846        // Dispose the input channel after removing the window so the Window Manager
3847        // doesn't interpret the input channel being closed as an abnormal termination.
3848        if (mInputChannel != null) {
3849            mInputChannel.dispose();
3850            mInputChannel = null;
3851        }
3852
3853        mDisplayManager.unregisterDisplayListener(mDisplayListener);
3854
3855        unscheduleTraversals();
3856    }
3857
3858    /**
3859     * Notifies all callbacks that configuration and/or display has changed and updates internal
3860     * state.
3861     * @param mergedConfiguration New global and override config in {@link MergedConfiguration}
3862     *                            container.
3863     * @param force Flag indicating if we should force apply the config.
3864     * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not
3865     *                     changed.
3866     */
3867    private void performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force,
3868            int newDisplayId) {
3869        if (mergedConfiguration == null) {
3870            throw new IllegalArgumentException("No merged config provided.");
3871        }
3872
3873        Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
3874        final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration();
3875        if (DEBUG_CONFIGURATION) Log.v(mTag,
3876                "Applying new config to window " + mWindowAttributes.getTitle()
3877                        + ", globalConfig: " + globalConfig
3878                        + ", overrideConfig: " + overrideConfig);
3879
3880        final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
3881        if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
3882            globalConfig = new Configuration(globalConfig);
3883            ci.applyToConfiguration(mNoncompatDensity, globalConfig);
3884        }
3885
3886        synchronized (sConfigCallbacks) {
3887            for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
3888                sConfigCallbacks.get(i).onConfigurationChanged(globalConfig);
3889            }
3890        }
3891
3892        mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
3893
3894        mForceNextConfigUpdate = force;
3895        if (mActivityConfigCallback != null) {
3896            // An activity callback is set - notify it about override configuration update.
3897            // This basically initiates a round trip to ActivityThread and back, which will ensure
3898            // that corresponding activity and resources are updated before updating inner state of
3899            // ViewRootImpl. Eventually it will call #updateConfiguration().
3900            mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId);
3901        } else {
3902            // There is no activity callback - update the configuration right away.
3903            updateConfiguration(newDisplayId);
3904        }
3905        mForceNextConfigUpdate = false;
3906    }
3907
3908    /**
3909     * Update display and views if last applied merged configuration changed.
3910     * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise.
3911     */
3912    public void updateConfiguration(int newDisplayId) {
3913        if (mView == null) {
3914            return;
3915        }
3916
3917        // At this point the resources have been updated to
3918        // have the most recent config, whatever that is.  Use
3919        // the one in them which may be newer.
3920        final Resources localResources = mView.getResources();
3921        final Configuration config = localResources.getConfiguration();
3922
3923        // Handle move to display.
3924        if (newDisplayId != INVALID_DISPLAY) {
3925            onMovedToDisplay(newDisplayId, config);
3926        }
3927
3928        // Handle configuration change.
3929        if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
3930            // Update the display with new DisplayAdjustments.
3931            mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
3932                    mDisplay.getDisplayId(), localResources);
3933
3934            final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
3935            final int currentLayoutDirection = config.getLayoutDirection();
3936            mLastConfigurationFromResources.setTo(config);
3937            if (lastLayoutDirection != currentLayoutDirection
3938                    && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
3939                mView.setLayoutDirection(currentLayoutDirection);
3940            }
3941            mView.dispatchConfigurationChanged(config);
3942
3943            // We could have gotten this {@link Configuration} update after we called
3944            // {@link #performTraversals} with an older {@link Configuration}. As a result, our
3945            // window frame may be stale. We must ensure the next pass of {@link #performTraversals}
3946            // catches this.
3947            mForceNextWindowRelayout = true;
3948            requestLayout();
3949        }
3950    }
3951
3952    /**
3953     * Return true if child is an ancestor of parent, (or equal to the parent).
3954     */
3955    public static boolean isViewDescendantOf(View child, View parent) {
3956        if (child == parent) {
3957            return true;
3958        }
3959
3960        final ViewParent theParent = child.getParent();
3961        return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
3962    }
3963
3964    private static void forceLayout(View view) {
3965        view.forceLayout();
3966        if (view instanceof ViewGroup) {
3967            ViewGroup group = (ViewGroup) view;
3968            final int count = group.getChildCount();
3969            for (int i = 0; i < count; i++) {
3970                forceLayout(group.getChildAt(i));
3971            }
3972        }
3973    }
3974
3975    private final static int MSG_INVALIDATE = 1;
3976    private final static int MSG_INVALIDATE_RECT = 2;
3977    private final static int MSG_DIE = 3;
3978    private final static int MSG_RESIZED = 4;
3979    private final static int MSG_RESIZED_REPORT = 5;
3980    private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
3981    private final static int MSG_DISPATCH_INPUT_EVENT = 7;
3982    private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
3983    private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
3984    private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
3985    private final static int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12;
3986    private final static int MSG_CHECK_FOCUS = 13;
3987    private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
3988    private final static int MSG_DISPATCH_DRAG_EVENT = 15;
3989    private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
3990    private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
3991    private final static int MSG_UPDATE_CONFIGURATION = 18;
3992    private final static int MSG_PROCESS_INPUT_EVENTS = 19;
3993    private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
3994    private final static int MSG_INVALIDATE_WORLD = 22;
3995    private final static int MSG_WINDOW_MOVED = 23;
3996    private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
3997    private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
3998    private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
3999    private final static int MSG_UPDATE_POINTER_ICON = 27;
4000    private final static int MSG_POINTER_CAPTURE_CHANGED = 28;
4001    private final static int MSG_DRAW_FINISHED = 29;
4002
4003    final class ViewRootHandler extends Handler {
4004        @Override
4005        public String getMessageName(Message message) {
4006            switch (message.what) {
4007                case MSG_INVALIDATE:
4008                    return "MSG_INVALIDATE";
4009                case MSG_INVALIDATE_RECT:
4010                    return "MSG_INVALIDATE_RECT";
4011                case MSG_DIE:
4012                    return "MSG_DIE";
4013                case MSG_RESIZED:
4014                    return "MSG_RESIZED";
4015                case MSG_RESIZED_REPORT:
4016                    return "MSG_RESIZED_REPORT";
4017                case MSG_WINDOW_FOCUS_CHANGED:
4018                    return "MSG_WINDOW_FOCUS_CHANGED";
4019                case MSG_DISPATCH_INPUT_EVENT:
4020                    return "MSG_DISPATCH_INPUT_EVENT";
4021                case MSG_DISPATCH_APP_VISIBILITY:
4022                    return "MSG_DISPATCH_APP_VISIBILITY";
4023                case MSG_DISPATCH_GET_NEW_SURFACE:
4024                    return "MSG_DISPATCH_GET_NEW_SURFACE";
4025                case MSG_DISPATCH_KEY_FROM_IME:
4026                    return "MSG_DISPATCH_KEY_FROM_IME";
4027                case MSG_DISPATCH_KEY_FROM_AUTOFILL:
4028                    return "MSG_DISPATCH_KEY_FROM_AUTOFILL";
4029                case MSG_CHECK_FOCUS:
4030                    return "MSG_CHECK_FOCUS";
4031                case MSG_CLOSE_SYSTEM_DIALOGS:
4032                    return "MSG_CLOSE_SYSTEM_DIALOGS";
4033                case MSG_DISPATCH_DRAG_EVENT:
4034                    return "MSG_DISPATCH_DRAG_EVENT";
4035                case MSG_DISPATCH_DRAG_LOCATION_EVENT:
4036                    return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
4037                case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
4038                    return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
4039                case MSG_UPDATE_CONFIGURATION:
4040                    return "MSG_UPDATE_CONFIGURATION";
4041                case MSG_PROCESS_INPUT_EVENTS:
4042                    return "MSG_PROCESS_INPUT_EVENTS";
4043                case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
4044                    return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
4045                case MSG_WINDOW_MOVED:
4046                    return "MSG_WINDOW_MOVED";
4047                case MSG_SYNTHESIZE_INPUT_EVENT:
4048                    return "MSG_SYNTHESIZE_INPUT_EVENT";
4049                case MSG_DISPATCH_WINDOW_SHOWN:
4050                    return "MSG_DISPATCH_WINDOW_SHOWN";
4051                case MSG_UPDATE_POINTER_ICON:
4052                    return "MSG_UPDATE_POINTER_ICON";
4053                case MSG_POINTER_CAPTURE_CHANGED:
4054                    return "MSG_POINTER_CAPTURE_CHANGED";
4055                case MSG_DRAW_FINISHED:
4056                    return "MSG_DRAW_FINISHED";
4057            }
4058            return super.getMessageName(message);
4059        }
4060
4061        @Override
4062        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
4063            if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
4064                // Debugging for b/27963013
4065                throw new NullPointerException(
4066                        "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
4067            }
4068            return super.sendMessageAtTime(msg, uptimeMillis);
4069        }
4070
4071        @Override
4072        public void handleMessage(Message msg) {
4073            switch (msg.what) {
4074                case MSG_INVALIDATE:
4075                    ((View) msg.obj).invalidate();
4076                    break;
4077                case MSG_INVALIDATE_RECT:
4078                    final View.AttachInfo.InvalidateInfo info =
4079                            (View.AttachInfo.InvalidateInfo) msg.obj;
4080                    info.target.invalidate(info.left, info.top, info.right, info.bottom);
4081                    info.recycle();
4082                    break;
4083                case MSG_PROCESS_INPUT_EVENTS:
4084                    mProcessInputEventsScheduled = false;
4085                    doProcessInputEvents();
4086                    break;
4087                case MSG_DISPATCH_APP_VISIBILITY:
4088                    handleAppVisibility(msg.arg1 != 0);
4089                    break;
4090                case MSG_DISPATCH_GET_NEW_SURFACE:
4091                    handleGetNewSurface();
4092                    break;
4093                case MSG_RESIZED: {
4094                    // Recycled in the fall through...
4095                    SomeArgs args = (SomeArgs) msg.obj;
4096                    if (mWinFrame.equals(args.arg1)
4097                            && mPendingOverscanInsets.equals(args.arg5)
4098                            && mPendingContentInsets.equals(args.arg2)
4099                            && mPendingStableInsets.equals(args.arg6)
4100                            && mPendingDisplayCutout.get().equals(args.arg9)
4101                            && mPendingVisibleInsets.equals(args.arg3)
4102                            && mPendingOutsets.equals(args.arg7)
4103                            && mPendingBackDropFrame.equals(args.arg8)
4104                            && args.arg4 == null
4105                            && args.argi1 == 0
4106                            && mDisplay.getDisplayId() == args.argi3) {
4107                        break;
4108                    }
4109                } // fall through...
4110                case MSG_RESIZED_REPORT:
4111                    if (mAdded) {
4112                        SomeArgs args = (SomeArgs) msg.obj;
4113
4114                        final int displayId = args.argi3;
4115                        MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
4116                        final boolean displayChanged = mDisplay.getDisplayId() != displayId;
4117
4118                        if (!mLastReportedMergedConfiguration.equals(mergedConfiguration)) {
4119                            // If configuration changed - notify about that and, maybe,
4120                            // about move to display.
4121                            performConfigurationChange(mergedConfiguration, false /* force */,
4122                                    displayChanged
4123                                            ? displayId : INVALID_DISPLAY /* same display */);
4124                        } else if (displayChanged) {
4125                            // Moved to display without config change - report last applied one.
4126                            onMovedToDisplay(displayId, mLastConfigurationFromResources);
4127                        }
4128
4129                        final boolean framesChanged = !mWinFrame.equals(args.arg1)
4130                                || !mPendingOverscanInsets.equals(args.arg5)
4131                                || !mPendingContentInsets.equals(args.arg2)
4132                                || !mPendingStableInsets.equals(args.arg6)
4133                                || !mPendingDisplayCutout.get().equals(args.arg9)
4134                                || !mPendingVisibleInsets.equals(args.arg3)
4135                                || !mPendingOutsets.equals(args.arg7);
4136
4137                        mWinFrame.set((Rect) args.arg1);
4138                        mPendingOverscanInsets.set((Rect) args.arg5);
4139                        mPendingContentInsets.set((Rect) args.arg2);
4140                        mPendingStableInsets.set((Rect) args.arg6);
4141                        mPendingDisplayCutout.set((DisplayCutout) args.arg9);
4142                        mPendingVisibleInsets.set((Rect) args.arg3);
4143                        mPendingOutsets.set((Rect) args.arg7);
4144                        mPendingBackDropFrame.set((Rect) args.arg8);
4145                        mForceNextWindowRelayout = args.argi1 != 0;
4146                        mPendingAlwaysConsumeNavBar = args.argi2 != 0;
4147
4148                        args.recycle();
4149
4150                        if (msg.what == MSG_RESIZED_REPORT) {
4151                            reportNextDraw();
4152                        }
4153
4154                        if (mView != null && framesChanged) {
4155                            forceLayout(mView);
4156                        }
4157                        requestLayout();
4158                    }
4159                    break;
4160                case MSG_WINDOW_MOVED:
4161                    if (mAdded) {
4162                        final int w = mWinFrame.width();
4163                        final int h = mWinFrame.height();
4164                        final int l = msg.arg1;
4165                        final int t = msg.arg2;
4166                        mWinFrame.left = l;
4167                        mWinFrame.right = l + w;
4168                        mWinFrame.top = t;
4169                        mWinFrame.bottom = t + h;
4170
4171                        mPendingBackDropFrame.set(mWinFrame);
4172                        maybeHandleWindowMove(mWinFrame);
4173                    }
4174                    break;
4175                case MSG_WINDOW_FOCUS_CHANGED: {
4176                    handleWindowFocusChanged();
4177                } break;
4178                case MSG_DIE:
4179                    doDie();
4180                    break;
4181                case MSG_DISPATCH_INPUT_EVENT: {
4182                    SomeArgs args = (SomeArgs) msg.obj;
4183                    InputEvent event = (InputEvent) args.arg1;
4184                    InputEventReceiver receiver = (InputEventReceiver) args.arg2;
4185                    enqueueInputEvent(event, receiver, 0, true);
4186                    args.recycle();
4187                } break;
4188                case MSG_SYNTHESIZE_INPUT_EVENT: {
4189                    InputEvent event = (InputEvent) msg.obj;
4190                    enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
4191                } break;
4192                case MSG_DISPATCH_KEY_FROM_IME: {
4193                    if (LOCAL_LOGV) {
4194                        Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView);
4195                    }
4196                    KeyEvent event = (KeyEvent) msg.obj;
4197                    if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) {
4198                        // The IME is trying to say this event is from the
4199                        // system!  Bad bad bad!
4200                        //noinspection UnusedAssignment
4201                        event = KeyEvent.changeFlags(event,
4202                                event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
4203                    }
4204                    enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
4205                } break;
4206                case MSG_DISPATCH_KEY_FROM_AUTOFILL: {
4207                    if (LOCAL_LOGV) {
4208                        Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView);
4209                    }
4210                    KeyEvent event = (KeyEvent) msg.obj;
4211                    enqueueInputEvent(event, null, 0, true);
4212                } break;
4213                case MSG_CHECK_FOCUS: {
4214                    InputMethodManager imm = InputMethodManager.peekInstance();
4215                    if (imm != null) {
4216                        imm.checkFocus();
4217                    }
4218                } break;
4219                case MSG_CLOSE_SYSTEM_DIALOGS: {
4220                    if (mView != null) {
4221                        mView.onCloseSystemDialogs((String) msg.obj);
4222                    }
4223                } break;
4224                case MSG_DISPATCH_DRAG_EVENT: {
4225                } // fall through
4226                case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
4227                    DragEvent event = (DragEvent) msg.obj;
4228                    // only present when this app called startDrag()
4229                    event.mLocalState = mLocalDragState;
4230                    handleDragEvent(event);
4231                } break;
4232                case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
4233                    handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
4234                } break;
4235                case MSG_UPDATE_CONFIGURATION: {
4236                    Configuration config = (Configuration) msg.obj;
4237                    if (config.isOtherSeqNewer(
4238                            mLastReportedMergedConfiguration.getMergedConfiguration())) {
4239                        // If we already have a newer merged config applied - use its global part.
4240                        config = mLastReportedMergedConfiguration.getGlobalConfiguration();
4241                    }
4242
4243                    // Use the newer global config and last reported override config.
4244                    mPendingMergedConfiguration.setConfiguration(config,
4245                            mLastReportedMergedConfiguration.getOverrideConfiguration());
4246
4247                    performConfigurationChange(mPendingMergedConfiguration, false /* force */,
4248                            INVALID_DISPLAY /* same display */);
4249                } break;
4250                case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
4251                    setAccessibilityFocus(null, null);
4252                } break;
4253                case MSG_INVALIDATE_WORLD: {
4254                    if (mView != null) {
4255                        invalidateWorld(mView);
4256                    }
4257                } break;
4258                case MSG_DISPATCH_WINDOW_SHOWN: {
4259                    handleDispatchWindowShown();
4260                } break;
4261                case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
4262                    final IResultReceiver receiver = (IResultReceiver) msg.obj;
4263                    final int deviceId = msg.arg1;
4264                    handleRequestKeyboardShortcuts(receiver, deviceId);
4265                } break;
4266                case MSG_UPDATE_POINTER_ICON: {
4267                    MotionEvent event = (MotionEvent) msg.obj;
4268                    resetPointerIcon(event);
4269                } break;
4270                case MSG_POINTER_CAPTURE_CHANGED: {
4271                    final boolean hasCapture = msg.arg1 != 0;
4272                    handlePointerCaptureChanged(hasCapture);
4273                } break;
4274                case MSG_DRAW_FINISHED: {
4275                    pendingDrawFinished();
4276                } break;
4277            }
4278        }
4279    }
4280
4281    final ViewRootHandler mHandler = new ViewRootHandler();
4282
4283    /**
4284     * Something in the current window tells us we need to change the touch mode.  For
4285     * example, we are not in touch mode, and the user touches the screen.
4286     *
4287     * If the touch mode has changed, tell the window manager, and handle it locally.
4288     *
4289     * @param inTouchMode Whether we want to be in touch mode.
4290     * @return True if the touch mode changed and focus changed was changed as a result
4291     */
4292    boolean ensureTouchMode(boolean inTouchMode) {
4293        if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
4294                + "touch mode is " + mAttachInfo.mInTouchMode);
4295        if (mAttachInfo.mInTouchMode == inTouchMode) return false;
4296
4297        // tell the window manager
4298        try {
4299            mWindowSession.setInTouchMode(inTouchMode);
4300        } catch (RemoteException e) {
4301            throw new RuntimeException(e);
4302        }
4303
4304        // handle the change
4305        return ensureTouchModeLocally(inTouchMode);
4306    }
4307
4308    /**
4309     * Ensure that the touch mode for this window is set, and if it is changing,
4310     * take the appropriate action.
4311     * @param inTouchMode Whether we want to be in touch mode.
4312     * @return True if the touch mode changed and focus changed was changed as a result
4313     */
4314    private boolean ensureTouchModeLocally(boolean inTouchMode) {
4315        if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
4316                + "touch mode is " + mAttachInfo.mInTouchMode);
4317
4318        if (mAttachInfo.mInTouchMode == inTouchMode) return false;
4319
4320        mAttachInfo.mInTouchMode = inTouchMode;
4321        mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
4322
4323        return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
4324    }
4325
4326    private boolean enterTouchMode() {
4327        if (mView != null && mView.hasFocus()) {
4328            // note: not relying on mFocusedView here because this could
4329            // be when the window is first being added, and mFocused isn't
4330            // set yet.
4331            final View focused = mView.findFocus();
4332            if (focused != null && !focused.isFocusableInTouchMode()) {
4333                final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
4334                if (ancestorToTakeFocus != null) {
4335                    // there is an ancestor that wants focus after its
4336                    // descendants that is focusable in touch mode.. give it
4337                    // focus
4338                    return ancestorToTakeFocus.requestFocus();
4339                } else {
4340                    // There's nothing to focus. Clear and propagate through the
4341                    // hierarchy, but don't attempt to place new focus.
4342                    focused.clearFocusInternal(null, true, false);
4343                    return true;
4344                }
4345            }
4346        }
4347        return false;
4348    }
4349
4350    /**
4351     * Find an ancestor of focused that wants focus after its descendants and is
4352     * focusable in touch mode.
4353     * @param focused The currently focused view.
4354     * @return An appropriate view, or null if no such view exists.
4355     */
4356    private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
4357        ViewParent parent = focused.getParent();
4358        while (parent instanceof ViewGroup) {
4359            final ViewGroup vgParent = (ViewGroup) parent;
4360            if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
4361                    && vgParent.isFocusableInTouchMode()) {
4362                return vgParent;
4363            }
4364            if (vgParent.isRootNamespace()) {
4365                return null;
4366            } else {
4367                parent = vgParent.getParent();
4368            }
4369        }
4370        return null;
4371    }
4372
4373    private boolean leaveTouchMode() {
4374        if (mView != null) {
4375            if (mView.hasFocus()) {
4376                View focusedView = mView.findFocus();
4377                if (!(focusedView instanceof ViewGroup)) {
4378                    // some view has focus, let it keep it
4379                    return false;
4380                } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
4381                        ViewGroup.FOCUS_AFTER_DESCENDANTS) {
4382                    // some view group has focus, and doesn't prefer its children
4383                    // over itself for focus, so let them keep it.
4384                    return false;
4385                }
4386            }
4387
4388            // find the best view to give focus to in this brave new non-touch-mode
4389            // world
4390            return mView.restoreDefaultFocus();
4391        }
4392        return false;
4393    }
4394
4395    /**
4396     * Base class for implementing a stage in the chain of responsibility
4397     * for processing input events.
4398     * <p>
4399     * Events are delivered to the stage by the {@link #deliver} method.  The stage
4400     * then has the choice of finishing the event or forwarding it to the next stage.
4401     * </p>
4402     */
4403    abstract class InputStage {
4404        private final InputStage mNext;
4405
4406        protected static final int FORWARD = 0;
4407        protected static final int FINISH_HANDLED = 1;
4408        protected static final int FINISH_NOT_HANDLED = 2;
4409
4410        /**
4411         * Creates an input stage.
4412         * @param next The next stage to which events should be forwarded.
4413         */
4414        public InputStage(InputStage next) {
4415            mNext = next;
4416        }
4417
4418        /**
4419         * Delivers an event to be processed.
4420         */
4421        public final void deliver(QueuedInputEvent q) {
4422            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
4423                forward(q);
4424            } else if (shouldDropInputEvent(q)) {
4425                finish(q, false);
4426            } else {
4427                apply(q, onProcess(q));
4428            }
4429        }
4430
4431        /**
4432         * Marks the the input event as finished then forwards it to the next stage.
4433         */
4434        protected void finish(QueuedInputEvent q, boolean handled) {
4435            q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
4436            if (handled) {
4437                q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
4438            }
4439            forward(q);
4440        }
4441
4442        /**
4443         * Forwards the event to the next stage.
4444         */
4445        protected void forward(QueuedInputEvent q) {
4446            onDeliverToNext(q);
4447        }
4448
4449        /**
4450         * Applies a result code from {@link #onProcess} to the specified event.
4451         */
4452        protected void apply(QueuedInputEvent q, int result) {
4453            if (result == FORWARD) {
4454                forward(q);
4455            } else if (result == FINISH_HANDLED) {
4456                finish(q, true);
4457            } else if (result == FINISH_NOT_HANDLED) {
4458                finish(q, false);
4459            } else {
4460                throw new IllegalArgumentException("Invalid result: " + result);
4461            }
4462        }
4463
4464        /**
4465         * Called when an event is ready to be processed.
4466         * @return A result code indicating how the event was handled.
4467         */
4468        protected int onProcess(QueuedInputEvent q) {
4469            return FORWARD;
4470        }
4471
4472        /**
4473         * Called when an event is being delivered to the next stage.
4474         */
4475        protected void onDeliverToNext(QueuedInputEvent q) {
4476            if (DEBUG_INPUT_STAGES) {
4477                Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
4478            }
4479            if (mNext != null) {
4480                mNext.deliver(q);
4481            } else {
4482                finishInputEvent(q);
4483            }
4484        }
4485
4486        protected void onWindowFocusChanged(boolean hasWindowFocus) {
4487            if (mNext != null) {
4488                mNext.onWindowFocusChanged(hasWindowFocus);
4489            }
4490        }
4491
4492        protected void onDetachedFromWindow() {
4493            if (mNext != null) {
4494                mNext.onDetachedFromWindow();
4495            }
4496        }
4497
4498        protected boolean shouldDropInputEvent(QueuedInputEvent q) {
4499            if (mView == null || !mAdded) {
4500                Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
4501                return true;
4502            } else if ((!mAttachInfo.mHasWindowFocus
4503                    && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
4504                    && !isAutofillUiShowing()) || mStopped
4505                    || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
4506                    || (mPausedForTransition && !isBack(q.mEvent))) {
4507                // This is a focus event and the window doesn't currently have input focus or
4508                // has stopped. This could be an event that came back from the previous stage
4509                // but the window has lost focus or stopped in the meantime.
4510                if (isTerminalInputEvent(q.mEvent)) {
4511                    // Don't drop terminal input events, however mark them as canceled.
4512                    q.mEvent.cancel();
4513                    Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
4514                    return false;
4515                }
4516
4517                // Drop non-terminal input events.
4518                Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
4519                return true;
4520            }
4521            return false;
4522        }
4523
4524        void dump(String prefix, PrintWriter writer) {
4525            if (mNext != null) {
4526                mNext.dump(prefix, writer);
4527            }
4528        }
4529
4530        private boolean isBack(InputEvent event) {
4531            if (event instanceof KeyEvent) {
4532                return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
4533            } else {
4534                return false;
4535            }
4536        }
4537    }
4538
4539    /**
4540     * Base class for implementing an input pipeline stage that supports
4541     * asynchronous and out-of-order processing of input events.
4542     * <p>
4543     * In addition to what a normal input stage can do, an asynchronous
4544     * input stage may also defer an input event that has been delivered to it
4545     * and finish or forward it later.
4546     * </p>
4547     */
4548    abstract class AsyncInputStage extends InputStage {
4549        private final String mTraceCounter;
4550
4551        private QueuedInputEvent mQueueHead;
4552        private QueuedInputEvent mQueueTail;
4553        private int mQueueLength;
4554
4555        protected static final int DEFER = 3;
4556
4557        /**
4558         * Creates an asynchronous input stage.
4559         * @param next The next stage to which events should be forwarded.
4560         * @param traceCounter The name of a counter to record the size of
4561         * the queue of pending events.
4562         */
4563        public AsyncInputStage(InputStage next, String traceCounter) {
4564            super(next);
4565            mTraceCounter = traceCounter;
4566        }
4567
4568        /**
4569         * Marks the event as deferred, which is to say that it will be handled
4570         * asynchronously.  The caller is responsible for calling {@link #forward}
4571         * or {@link #finish} later when it is done handling the event.
4572         */
4573        protected void defer(QueuedInputEvent q) {
4574            q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
4575            enqueue(q);
4576        }
4577
4578        @Override
4579        protected void forward(QueuedInputEvent q) {
4580            // Clear the deferred flag.
4581            q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
4582
4583            // Fast path if the queue is empty.
4584            QueuedInputEvent curr = mQueueHead;
4585            if (curr == null) {
4586                super.forward(q);
4587                return;
4588            }
4589
4590            // Determine whether the event must be serialized behind any others
4591            // before it can be delivered to the next stage.  This is done because
4592            // deferred events might be handled out of order by the stage.
4593            final int deviceId = q.mEvent.getDeviceId();
4594            QueuedInputEvent prev = null;
4595            boolean blocked = false;
4596            while (curr != null && curr != q) {
4597                if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
4598                    blocked = true;
4599                }
4600                prev = curr;
4601                curr = curr.mNext;
4602            }
4603
4604            // If the event is blocked, then leave it in the queue to be delivered later.
4605            // Note that the event might not yet be in the queue if it was not previously
4606            // deferred so we will enqueue it if needed.
4607            if (blocked) {
4608                if (curr == null) {
4609                    enqueue(q);
4610                }
4611                return;
4612            }
4613
4614            // The event is not blocked.  Deliver it immediately.
4615            if (curr != null) {
4616                curr = curr.mNext;
4617                dequeue(q, prev);
4618            }
4619            super.forward(q);
4620
4621            // Dequeuing this event may have unblocked successors.  Deliver them.
4622            while (curr != null) {
4623                if (deviceId == curr.mEvent.getDeviceId()) {
4624                    if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
4625                        break;
4626                    }
4627                    QueuedInputEvent next = curr.mNext;
4628                    dequeue(curr, prev);
4629                    super.forward(curr);
4630                    curr = next;
4631                } else {
4632                    prev = curr;
4633                    curr = curr.mNext;
4634                }
4635            }
4636        }
4637
4638        @Override
4639        protected void apply(QueuedInputEvent q, int result) {
4640            if (result == DEFER) {
4641                defer(q);
4642            } else {
4643                super.apply(q, result);
4644            }
4645        }
4646
4647        private void enqueue(QueuedInputEvent q) {
4648            if (mQueueTail == null) {
4649                mQueueHead = q;
4650                mQueueTail = q;
4651            } else {
4652                mQueueTail.mNext = q;
4653                mQueueTail = q;
4654            }
4655
4656            mQueueLength += 1;
4657            Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
4658        }
4659
4660        private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
4661            if (prev == null) {
4662                mQueueHead = q.mNext;
4663            } else {
4664                prev.mNext = q.mNext;
4665            }
4666            if (mQueueTail == q) {
4667                mQueueTail = prev;
4668            }
4669            q.mNext = null;
4670
4671            mQueueLength -= 1;
4672            Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
4673        }
4674
4675        @Override
4676        void dump(String prefix, PrintWriter writer) {
4677            writer.print(prefix);
4678            writer.print(getClass().getName());
4679            writer.print(": mQueueLength=");
4680            writer.println(mQueueLength);
4681
4682            super.dump(prefix, writer);
4683        }
4684    }
4685
4686    /**
4687     * Delivers pre-ime input events to a native activity.
4688     * Does not support pointer events.
4689     */
4690    final class NativePreImeInputStage extends AsyncInputStage
4691            implements InputQueue.FinishedInputEventCallback {
4692        public NativePreImeInputStage(InputStage next, String traceCounter) {
4693            super(next, traceCounter);
4694        }
4695
4696        @Override
4697        protected int onProcess(QueuedInputEvent q) {
4698            if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
4699                mInputQueue.sendInputEvent(q.mEvent, q, true, this);
4700                return DEFER;
4701            }
4702            return FORWARD;
4703        }
4704
4705        @Override
4706        public void onFinishedInputEvent(Object token, boolean handled) {
4707            QueuedInputEvent q = (QueuedInputEvent)token;
4708            if (handled) {
4709                finish(q, true);
4710                return;
4711            }
4712            forward(q);
4713        }
4714    }
4715
4716    /**
4717     * Delivers pre-ime input events to the view hierarchy.
4718     * Does not support pointer events.
4719     */
4720    final class ViewPreImeInputStage extends InputStage {
4721        public ViewPreImeInputStage(InputStage next) {
4722            super(next);
4723        }
4724
4725        @Override
4726        protected int onProcess(QueuedInputEvent q) {
4727            if (q.mEvent instanceof KeyEvent) {
4728                return processKeyEvent(q);
4729            }
4730            return FORWARD;
4731        }
4732
4733        private int processKeyEvent(QueuedInputEvent q) {
4734            final KeyEvent event = (KeyEvent)q.mEvent;
4735            if (mView.dispatchKeyEventPreIme(event)) {
4736                return FINISH_HANDLED;
4737            }
4738            return FORWARD;
4739        }
4740    }
4741
4742    /**
4743     * Delivers input events to the ime.
4744     * Does not support pointer events.
4745     */
4746    final class ImeInputStage extends AsyncInputStage
4747            implements InputMethodManager.FinishedInputEventCallback {
4748        public ImeInputStage(InputStage next, String traceCounter) {
4749            super(next, traceCounter);
4750        }
4751
4752        @Override
4753        protected int onProcess(QueuedInputEvent q) {
4754            if (mLastWasImTarget && !isInLocalFocusMode()) {
4755                InputMethodManager imm = InputMethodManager.peekInstance();
4756                if (imm != null) {
4757                    final InputEvent event = q.mEvent;
4758                    if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
4759                    int result = imm.dispatchInputEvent(event, q, this, mHandler);
4760                    if (result == InputMethodManager.DISPATCH_HANDLED) {
4761                        return FINISH_HANDLED;
4762                    } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
4763                        // The IME could not handle it, so skip along to the next InputStage
4764                        return FORWARD;
4765                    } else {
4766                        return DEFER; // callback will be invoked later
4767                    }
4768                }
4769            }
4770            return FORWARD;
4771        }
4772
4773        @Override
4774        public void onFinishedInputEvent(Object token, boolean handled) {
4775            QueuedInputEvent q = (QueuedInputEvent)token;
4776            if (handled) {
4777                finish(q, true);
4778                return;
4779            }
4780            forward(q);
4781        }
4782    }
4783
4784    /**
4785     * Performs early processing of post-ime input events.
4786     */
4787    final class EarlyPostImeInputStage extends InputStage {
4788        public EarlyPostImeInputStage(InputStage next) {
4789            super(next);
4790        }
4791
4792        @Override
4793        protected int onProcess(QueuedInputEvent q) {
4794            if (q.mEvent instanceof KeyEvent) {
4795                return processKeyEvent(q);
4796            } else {
4797                final int source = q.mEvent.getSource();
4798                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
4799                    return processPointerEvent(q);
4800                }
4801            }
4802            return FORWARD;
4803        }
4804
4805        private int processKeyEvent(QueuedInputEvent q) {
4806            final KeyEvent event = (KeyEvent)q.mEvent;
4807
4808            if (mAttachInfo.mTooltipHost != null) {
4809                mAttachInfo.mTooltipHost.handleTooltipKey(event);
4810            }
4811
4812            // If the key's purpose is to exit touch mode then we consume it
4813            // and consider it handled.
4814            if (checkForLeavingTouchModeAndConsume(event)) {
4815                return FINISH_HANDLED;
4816            }
4817
4818            // Make sure the fallback event policy sees all keys that will be
4819            // delivered to the view hierarchy.
4820            mFallbackEventHandler.preDispatchKeyEvent(event);
4821            return FORWARD;
4822        }
4823
4824        private int processPointerEvent(QueuedInputEvent q) {
4825            final MotionEvent event = (MotionEvent)q.mEvent;
4826
4827            // Translate the pointer event for compatibility, if needed.
4828            if (mTranslator != null) {
4829                mTranslator.translateEventInScreenToAppWindow(event);
4830            }
4831
4832            // Enter touch mode on down or scroll, if it is coming from a touch screen device,
4833            // exit otherwise.
4834            final int action = event.getAction();
4835            if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
4836                ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
4837            }
4838
4839            if (action == MotionEvent.ACTION_DOWN) {
4840                // Upon motion event within app window, close autofill ui.
4841                AutofillManager afm = getAutofillManager();
4842                if (afm != null) {
4843                    afm.requestHideFillUi();
4844                }
4845            }
4846
4847            if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
4848                mAttachInfo.mTooltipHost.hideTooltip();
4849            }
4850
4851            // Offset the scroll position.
4852            if (mCurScrollY != 0) {
4853                event.offsetLocation(0, mCurScrollY);
4854            }
4855
4856            // Remember the touch position for possible drag-initiation.
4857            if (event.isTouchEvent()) {
4858                mLastTouchPoint.x = event.getRawX();
4859                mLastTouchPoint.y = event.getRawY();
4860                mLastTouchSource = event.getSource();
4861            }
4862            return FORWARD;
4863        }
4864    }
4865
4866    /**
4867     * Delivers post-ime input events to a native activity.
4868     */
4869    final class NativePostImeInputStage extends AsyncInputStage
4870            implements InputQueue.FinishedInputEventCallback {
4871        public NativePostImeInputStage(InputStage next, String traceCounter) {
4872            super(next, traceCounter);
4873        }
4874
4875        @Override
4876        protected int onProcess(QueuedInputEvent q) {
4877            if (mInputQueue != null) {
4878                mInputQueue.sendInputEvent(q.mEvent, q, false, this);
4879                return DEFER;
4880            }
4881            return FORWARD;
4882        }
4883
4884        @Override
4885        public void onFinishedInputEvent(Object token, boolean handled) {
4886            QueuedInputEvent q = (QueuedInputEvent)token;
4887            if (handled) {
4888                finish(q, true);
4889                return;
4890            }
4891            forward(q);
4892        }
4893    }
4894
4895    /**
4896     * Delivers post-ime input events to the view hierarchy.
4897     */
4898    final class ViewPostImeInputStage extends InputStage {
4899        public ViewPostImeInputStage(InputStage next) {
4900            super(next);
4901        }
4902
4903        @Override
4904        protected int onProcess(QueuedInputEvent q) {
4905            if (q.mEvent instanceof KeyEvent) {
4906                return processKeyEvent(q);
4907            } else {
4908                final int source = q.mEvent.getSource();
4909                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
4910                    return processPointerEvent(q);
4911                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
4912                    return processTrackballEvent(q);
4913                } else {
4914                    return processGenericMotionEvent(q);
4915                }
4916            }
4917        }
4918
4919        @Override
4920        protected void onDeliverToNext(QueuedInputEvent q) {
4921            if (mUnbufferedInputDispatch
4922                    && q.mEvent instanceof MotionEvent
4923                    && ((MotionEvent)q.mEvent).isTouchEvent()
4924                    && isTerminalInputEvent(q.mEvent)) {
4925                mUnbufferedInputDispatch = false;
4926                scheduleConsumeBatchedInput();
4927            }
4928            super.onDeliverToNext(q);
4929        }
4930
4931        private boolean performFocusNavigation(KeyEvent event) {
4932            int direction = 0;
4933            switch (event.getKeyCode()) {
4934                case KeyEvent.KEYCODE_DPAD_LEFT:
4935                    if (event.hasNoModifiers()) {
4936                        direction = View.FOCUS_LEFT;
4937                    }
4938                    break;
4939                case KeyEvent.KEYCODE_DPAD_RIGHT:
4940                    if (event.hasNoModifiers()) {
4941                        direction = View.FOCUS_RIGHT;
4942                    }
4943                    break;
4944                case KeyEvent.KEYCODE_DPAD_UP:
4945                    if (event.hasNoModifiers()) {
4946                        direction = View.FOCUS_UP;
4947                    }
4948                    break;
4949                case KeyEvent.KEYCODE_DPAD_DOWN:
4950                    if (event.hasNoModifiers()) {
4951                        direction = View.FOCUS_DOWN;
4952                    }
4953                    break;
4954                case KeyEvent.KEYCODE_TAB:
4955                    if (event.hasNoModifiers()) {
4956                        direction = View.FOCUS_FORWARD;
4957                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
4958                        direction = View.FOCUS_BACKWARD;
4959                    }
4960                    break;
4961            }
4962            if (direction != 0) {
4963                View focused = mView.findFocus();
4964                if (focused != null) {
4965                    View v = focused.focusSearch(direction);
4966                    if (v != null && v != focused) {
4967                        // do the math the get the interesting rect
4968                        // of previous focused into the coord system of
4969                        // newly focused view
4970                        focused.getFocusedRect(mTempRect);
4971                        if (mView instanceof ViewGroup) {
4972                            ((ViewGroup) mView).offsetDescendantRectToMyCoords(
4973                                    focused, mTempRect);
4974                            ((ViewGroup) mView).offsetRectIntoDescendantCoords(
4975                                    v, mTempRect);
4976                        }
4977                        if (v.requestFocus(direction, mTempRect)) {
4978                            playSoundEffect(SoundEffectConstants
4979                                    .getContantForFocusDirection(direction));
4980                            return true;
4981                        }
4982                    }
4983
4984                    // Give the focused view a last chance to handle the dpad key.
4985                    if (mView.dispatchUnhandledMove(focused, direction)) {
4986                        return true;
4987                    }
4988                } else {
4989                    if (mView.restoreDefaultFocus()) {
4990                        return true;
4991                    }
4992                }
4993            }
4994            return false;
4995        }
4996
4997        private boolean performKeyboardGroupNavigation(int direction) {
4998            final View focused = mView.findFocus();
4999            if (focused == null && mView.restoreDefaultFocus()) {
5000                return true;
5001            }
5002            View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction)
5003                    : focused.keyboardNavigationClusterSearch(null, direction);
5004
5005            // Since requestFocus only takes "real" focus directions (and therefore also
5006            // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN.
5007            int realDirection = direction;
5008            if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
5009                realDirection = View.FOCUS_DOWN;
5010            }
5011
5012            if (cluster != null && cluster.isRootNamespace()) {
5013                // the default cluster. Try to find a non-clustered view to focus.
5014                if (cluster.restoreFocusNotInCluster()) {
5015                    playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
5016                    return true;
5017                }
5018                // otherwise skip to next actual cluster
5019                cluster = keyboardNavigationClusterSearch(null, direction);
5020            }
5021
5022            if (cluster != null && cluster.restoreFocusInCluster(realDirection)) {
5023                playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
5024                return true;
5025            }
5026
5027            return false;
5028        }
5029
5030        private int processKeyEvent(QueuedInputEvent q) {
5031            final KeyEvent event = (KeyEvent)q.mEvent;
5032
5033            if (mUnhandledKeyManager.preViewDispatch(event)) {
5034                return FINISH_HANDLED;
5035            }
5036
5037            // Deliver the key to the view hierarchy.
5038            if (mView.dispatchKeyEvent(event)) {
5039                return FINISH_HANDLED;
5040            }
5041
5042            if (shouldDropInputEvent(q)) {
5043                return FINISH_NOT_HANDLED;
5044            }
5045
5046            // This dispatch is for windows that don't have a Window.Callback. Otherwise,
5047            // the Window.Callback usually will have already called this (see
5048            // DecorView.superDispatchKeyEvent) leaving this call a no-op.
5049            if (mUnhandledKeyManager.dispatch(mView, event)) {
5050                return FINISH_HANDLED;
5051            }
5052
5053            int groupNavigationDirection = 0;
5054
5055            if (event.getAction() == KeyEvent.ACTION_DOWN
5056                    && event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
5057                if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_META_ON)) {
5058                    groupNavigationDirection = View.FOCUS_FORWARD;
5059                } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),
5060                        KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON)) {
5061                    groupNavigationDirection = View.FOCUS_BACKWARD;
5062                }
5063            }
5064
5065            // If a modifier is held, try to interpret the key as a shortcut.
5066            if (event.getAction() == KeyEvent.ACTION_DOWN
5067                    && !KeyEvent.metaStateHasNoModifiers(event.getMetaState())
5068                    && event.getRepeatCount() == 0
5069                    && !KeyEvent.isModifierKey(event.getKeyCode())
5070                    && groupNavigationDirection == 0) {
5071                if (mView.dispatchKeyShortcutEvent(event)) {
5072                    return FINISH_HANDLED;
5073                }
5074                if (shouldDropInputEvent(q)) {
5075                    return FINISH_NOT_HANDLED;
5076                }
5077            }
5078
5079            // Apply the fallback event policy.
5080            if (mFallbackEventHandler.dispatchKeyEvent(event)) {
5081                return FINISH_HANDLED;
5082            }
5083            if (shouldDropInputEvent(q)) {
5084                return FINISH_NOT_HANDLED;
5085            }
5086
5087            // Handle automatic focus changes.
5088            if (event.getAction() == KeyEvent.ACTION_DOWN) {
5089                if (groupNavigationDirection != 0) {
5090                    if (performKeyboardGroupNavigation(groupNavigationDirection)) {
5091                        return FINISH_HANDLED;
5092                    }
5093                } else {
5094                    if (performFocusNavigation(event)) {
5095                        return FINISH_HANDLED;
5096                    }
5097                }
5098            }
5099            return FORWARD;
5100        }
5101
5102        private int processPointerEvent(QueuedInputEvent q) {
5103            final MotionEvent event = (MotionEvent)q.mEvent;
5104
5105            mAttachInfo.mUnbufferedDispatchRequested = false;
5106            mAttachInfo.mHandlingPointerEvent = true;
5107            boolean handled = mView.dispatchPointerEvent(event);
5108            maybeUpdatePointerIcon(event);
5109            maybeUpdateTooltip(event);
5110            mAttachInfo.mHandlingPointerEvent = false;
5111            if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
5112                mUnbufferedInputDispatch = true;
5113                if (mConsumeBatchedInputScheduled) {
5114                    scheduleConsumeBatchedInputImmediately();
5115                }
5116            }
5117            return handled ? FINISH_HANDLED : FORWARD;
5118        }
5119
5120        private void maybeUpdatePointerIcon(MotionEvent event) {
5121            if (event.getPointerCount() == 1 && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
5122                if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
5123                        || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
5124                    // Other apps or the window manager may change the icon type outside of
5125                    // this app, therefore the icon type has to be reset on enter/exit event.
5126                    mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
5127                }
5128
5129                if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
5130                    if (!updatePointerIcon(event) &&
5131                            event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
5132                        mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
5133                    }
5134                }
5135            }
5136        }
5137
5138        private int processTrackballEvent(QueuedInputEvent q) {
5139            final MotionEvent event = (MotionEvent)q.mEvent;
5140
5141            if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
5142                if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) {
5143                    return FINISH_HANDLED;
5144                }
5145            }
5146
5147            if (mView.dispatchTrackballEvent(event)) {
5148                return FINISH_HANDLED;
5149            }
5150            return FORWARD;
5151        }
5152
5153        private int processGenericMotionEvent(QueuedInputEvent q) {
5154            final MotionEvent event = (MotionEvent)q.mEvent;
5155
5156            // Deliver the event to the view.
5157            if (mView.dispatchGenericMotionEvent(event)) {
5158                return FINISH_HANDLED;
5159            }
5160            return FORWARD;
5161        }
5162    }
5163
5164    private void resetPointerIcon(MotionEvent event) {
5165        mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
5166        updatePointerIcon(event);
5167    }
5168
5169    private boolean updatePointerIcon(MotionEvent event) {
5170        final int pointerIndex = 0;
5171        final float x = event.getX(pointerIndex);
5172        final float y = event.getY(pointerIndex);
5173        if (mView == null) {
5174            // E.g. click outside a popup to dismiss it
5175            Slog.d(mTag, "updatePointerIcon called after view was removed");
5176            return false;
5177        }
5178        if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
5179            // E.g. when moving window divider with mouse
5180            Slog.d(mTag, "updatePointerIcon called with position out of bounds");
5181            return false;
5182        }
5183        final PointerIcon pointerIcon = mView.onResolvePointerIcon(event, pointerIndex);
5184        final int pointerType = (pointerIcon != null) ?
5185                pointerIcon.getType() : PointerIcon.TYPE_DEFAULT;
5186
5187        if (mPointerIconType != pointerType) {
5188            mPointerIconType = pointerType;
5189            mCustomPointerIcon = null;
5190            if (mPointerIconType != PointerIcon.TYPE_CUSTOM) {
5191                InputManager.getInstance().setPointerIconType(pointerType);
5192                return true;
5193            }
5194        }
5195        if (mPointerIconType == PointerIcon.TYPE_CUSTOM &&
5196                !pointerIcon.equals(mCustomPointerIcon)) {
5197            mCustomPointerIcon = pointerIcon;
5198            InputManager.getInstance().setCustomPointerIcon(mCustomPointerIcon);
5199        }
5200        return true;
5201    }
5202
5203    private void maybeUpdateTooltip(MotionEvent event) {
5204        if (event.getPointerCount() != 1) {
5205            return;
5206        }
5207        final int action = event.getActionMasked();
5208        if (action != MotionEvent.ACTION_HOVER_ENTER
5209                && action != MotionEvent.ACTION_HOVER_MOVE
5210                && action != MotionEvent.ACTION_HOVER_EXIT) {
5211            return;
5212        }
5213        AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
5214        if (manager.isEnabled() && manager.isTouchExplorationEnabled()) {
5215            return;
5216        }
5217        if (mView == null) {
5218            Slog.d(mTag, "maybeUpdateTooltip called after view was removed");
5219            return;
5220        }
5221        mView.dispatchTooltipHoverEvent(event);
5222    }
5223
5224    /**
5225     * Performs synthesis of new input events from unhandled input events.
5226     */
5227    final class SyntheticInputStage extends InputStage {
5228        private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
5229        private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
5230        private final SyntheticTouchNavigationHandler mTouchNavigation =
5231                new SyntheticTouchNavigationHandler();
5232        private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
5233
5234        public SyntheticInputStage() {
5235            super(null);
5236        }
5237
5238        @Override
5239        protected int onProcess(QueuedInputEvent q) {
5240            q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
5241            if (q.mEvent instanceof MotionEvent) {
5242                final MotionEvent event = (MotionEvent)q.mEvent;
5243                final int source = event.getSource();
5244                if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
5245                    mTrackball.process(event);
5246                    return FINISH_HANDLED;
5247                } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
5248                    mJoystick.process(event);
5249                    return FINISH_HANDLED;
5250                } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
5251                        == InputDevice.SOURCE_TOUCH_NAVIGATION) {
5252                    mTouchNavigation.process(event);
5253                    return FINISH_HANDLED;
5254                }
5255            } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
5256                mKeyboard.process((KeyEvent)q.mEvent);
5257                return FINISH_HANDLED;
5258            }
5259
5260            return FORWARD;
5261        }
5262
5263        @Override
5264        protected void onDeliverToNext(QueuedInputEvent q) {
5265            if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
5266                // Cancel related synthetic events if any prior stage has handled the event.
5267                if (q.mEvent instanceof MotionEvent) {
5268                    final MotionEvent event = (MotionEvent)q.mEvent;
5269                    final int source = event.getSource();
5270                    if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
5271                        mTrackball.cancel();
5272                    } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
5273                        mJoystick.cancel();
5274                    } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
5275                            == InputDevice.SOURCE_TOUCH_NAVIGATION) {
5276                        mTouchNavigation.cancel(event);
5277                    }
5278                }
5279            }
5280            super.onDeliverToNext(q);
5281        }
5282
5283        @Override
5284        protected void onWindowFocusChanged(boolean hasWindowFocus) {
5285            if (!hasWindowFocus) {
5286                mJoystick.cancel();
5287            }
5288        }
5289
5290        @Override
5291        protected void onDetachedFromWindow() {
5292            mJoystick.cancel();
5293        }
5294    }
5295
5296    /**
5297     * Creates dpad events from unhandled trackball movements.
5298     */
5299    final class SyntheticTrackballHandler {
5300        private final TrackballAxis mX = new TrackballAxis();
5301        private final TrackballAxis mY = new TrackballAxis();
5302        private long mLastTime;
5303
5304        public void process(MotionEvent event) {
5305            // Translate the trackball event into DPAD keys and try to deliver those.
5306            long curTime = SystemClock.uptimeMillis();
5307            if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
5308                // It has been too long since the last movement,
5309                // so restart at the beginning.
5310                mX.reset(0);
5311                mY.reset(0);
5312                mLastTime = curTime;
5313            }
5314
5315            final int action = event.getAction();
5316            final int metaState = event.getMetaState();
5317            switch (action) {
5318                case MotionEvent.ACTION_DOWN:
5319                    mX.reset(2);
5320                    mY.reset(2);
5321                    enqueueInputEvent(new KeyEvent(curTime, curTime,
5322                            KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
5323                            KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5324                            InputDevice.SOURCE_KEYBOARD));
5325                    break;
5326                case MotionEvent.ACTION_UP:
5327                    mX.reset(2);
5328                    mY.reset(2);
5329                    enqueueInputEvent(new KeyEvent(curTime, curTime,
5330                            KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
5331                            KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5332                            InputDevice.SOURCE_KEYBOARD));
5333                    break;
5334            }
5335
5336            if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
5337                    + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
5338                    + " move=" + event.getX()
5339                    + " / Y=" + mY.position + " step="
5340                    + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
5341                    + " move=" + event.getY());
5342            final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
5343            final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
5344
5345            // Generate DPAD events based on the trackball movement.
5346            // We pick the axis that has moved the most as the direction of
5347            // the DPAD.  When we generate DPAD events for one axis, then the
5348            // other axis is reset -- we don't want to perform DPAD jumps due
5349            // to slight movements in the trackball when making major movements
5350            // along the other axis.
5351            int keycode = 0;
5352            int movement = 0;
5353            float accel = 1;
5354            if (xOff > yOff) {
5355                movement = mX.generate();
5356                if (movement != 0) {
5357                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
5358                            : KeyEvent.KEYCODE_DPAD_LEFT;
5359                    accel = mX.acceleration;
5360                    mY.reset(2);
5361                }
5362            } else if (yOff > 0) {
5363                movement = mY.generate();
5364                if (movement != 0) {
5365                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
5366                            : KeyEvent.KEYCODE_DPAD_UP;
5367                    accel = mY.acceleration;
5368                    mX.reset(2);
5369                }
5370            }
5371
5372            if (keycode != 0) {
5373                if (movement < 0) movement = -movement;
5374                int accelMovement = (int)(movement * accel);
5375                if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
5376                        + " accelMovement=" + accelMovement
5377                        + " accel=" + accel);
5378                if (accelMovement > movement) {
5379                    if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
5380                            + keycode);
5381                    movement--;
5382                    int repeatCount = accelMovement - movement;
5383                    enqueueInputEvent(new KeyEvent(curTime, curTime,
5384                            KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
5385                            KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5386                            InputDevice.SOURCE_KEYBOARD));
5387                }
5388                while (movement > 0) {
5389                    if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
5390                            + keycode);
5391                    movement--;
5392                    curTime = SystemClock.uptimeMillis();
5393                    enqueueInputEvent(new KeyEvent(curTime, curTime,
5394                            KeyEvent.ACTION_DOWN, keycode, 0, metaState,
5395                            KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5396                            InputDevice.SOURCE_KEYBOARD));
5397                    enqueueInputEvent(new KeyEvent(curTime, curTime,
5398                            KeyEvent.ACTION_UP, keycode, 0, metaState,
5399                            KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5400                            InputDevice.SOURCE_KEYBOARD));
5401                }
5402                mLastTime = curTime;
5403            }
5404        }
5405
5406        public void cancel() {
5407            mLastTime = Integer.MIN_VALUE;
5408
5409            // If we reach this, we consumed a trackball event.
5410            // Because we will not translate the trackball event into a key event,
5411            // touch mode will not exit, so we exit touch mode here.
5412            if (mView != null && mAdded) {
5413                ensureTouchMode(false);
5414            }
5415        }
5416    }
5417
5418    /**
5419     * Maintains state information for a single trackball axis, generating
5420     * discrete (DPAD) movements based on raw trackball motion.
5421     */
5422    static final class TrackballAxis {
5423        /**
5424         * The maximum amount of acceleration we will apply.
5425         */
5426        static final float MAX_ACCELERATION = 20;
5427
5428        /**
5429         * The maximum amount of time (in milliseconds) between events in order
5430         * for us to consider the user to be doing fast trackball movements,
5431         * and thus apply an acceleration.
5432         */
5433        static final long FAST_MOVE_TIME = 150;
5434
5435        /**
5436         * Scaling factor to the time (in milliseconds) between events to how
5437         * much to multiple/divide the current acceleration.  When movement
5438         * is < FAST_MOVE_TIME this multiplies the acceleration; when >
5439         * FAST_MOVE_TIME it divides it.
5440         */
5441        static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
5442
5443        static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
5444        static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
5445        static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
5446
5447        float position;
5448        float acceleration = 1;
5449        long lastMoveTime = 0;
5450        int step;
5451        int dir;
5452        int nonAccelMovement;
5453
5454        void reset(int _step) {
5455            position = 0;
5456            acceleration = 1;
5457            lastMoveTime = 0;
5458            step = _step;
5459            dir = 0;
5460        }
5461
5462        /**
5463         * Add trackball movement into the state.  If the direction of movement
5464         * has been reversed, the state is reset before adding the
5465         * movement (so that you don't have to compensate for any previously
5466         * collected movement before see the result of the movement in the
5467         * new direction).
5468         *
5469         * @return Returns the absolute value of the amount of movement
5470         * collected so far.
5471         */
5472        float collect(float off, long time, String axis) {
5473            long normTime;
5474            if (off > 0) {
5475                normTime = (long)(off * FAST_MOVE_TIME);
5476                if (dir < 0) {
5477                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
5478                    position = 0;
5479                    step = 0;
5480                    acceleration = 1;
5481                    lastMoveTime = 0;
5482                }
5483                dir = 1;
5484            } else if (off < 0) {
5485                normTime = (long)((-off) * FAST_MOVE_TIME);
5486                if (dir > 0) {
5487                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
5488                    position = 0;
5489                    step = 0;
5490                    acceleration = 1;
5491                    lastMoveTime = 0;
5492                }
5493                dir = -1;
5494            } else {
5495                normTime = 0;
5496            }
5497
5498            // The number of milliseconds between each movement that is
5499            // considered "normal" and will not result in any acceleration
5500            // or deceleration, scaled by the offset we have here.
5501            if (normTime > 0) {
5502                long delta = time - lastMoveTime;
5503                lastMoveTime = time;
5504                float acc = acceleration;
5505                if (delta < normTime) {
5506                    // The user is scrolling rapidly, so increase acceleration.
5507                    float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
5508                    if (scale > 1) acc *= scale;
5509                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
5510                            + off + " normTime=" + normTime + " delta=" + delta
5511                            + " scale=" + scale + " acc=" + acc);
5512                    acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
5513                } else {
5514                    // The user is scrolling slowly, so decrease acceleration.
5515                    float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
5516                    if (scale > 1) acc /= scale;
5517                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
5518                            + off + " normTime=" + normTime + " delta=" + delta
5519                            + " scale=" + scale + " acc=" + acc);
5520                    acceleration = acc > 1 ? acc : 1;
5521                }
5522            }
5523            position += off;
5524            return Math.abs(position);
5525        }
5526
5527        /**
5528         * Generate the number of discrete movement events appropriate for
5529         * the currently collected trackball movement.
5530         *
5531         * @return Returns the number of discrete movements, either positive
5532         * or negative, or 0 if there is not enough trackball movement yet
5533         * for a discrete movement.
5534         */
5535        int generate() {
5536            int movement = 0;
5537            nonAccelMovement = 0;
5538            do {
5539                final int dir = position >= 0 ? 1 : -1;
5540                switch (step) {
5541                    // If we are going to execute the first step, then we want
5542                    // to do this as soon as possible instead of waiting for
5543                    // a full movement, in order to make things look responsive.
5544                    case 0:
5545                        if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
5546                            return movement;
5547                        }
5548                        movement += dir;
5549                        nonAccelMovement += dir;
5550                        step = 1;
5551                        break;
5552                    // If we have generated the first movement, then we need
5553                    // to wait for the second complete trackball motion before
5554                    // generating the second discrete movement.
5555                    case 1:
5556                        if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
5557                            return movement;
5558                        }
5559                        movement += dir;
5560                        nonAccelMovement += dir;
5561                        position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
5562                        step = 2;
5563                        break;
5564                    // After the first two, we generate discrete movements
5565                    // consistently with the trackball, applying an acceleration
5566                    // if the trackball is moving quickly.  This is a simple
5567                    // acceleration on top of what we already compute based
5568                    // on how quickly the wheel is being turned, to apply
5569                    // a longer increasing acceleration to continuous movement
5570                    // in one direction.
5571                    default:
5572                        if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
5573                            return movement;
5574                        }
5575                        movement += dir;
5576                        position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
5577                        float acc = acceleration;
5578                        acc *= 1.1f;
5579                        acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
5580                        break;
5581                }
5582            } while (true);
5583        }
5584    }
5585
5586    /**
5587     * Creates dpad events from unhandled joystick movements.
5588     */
5589    final class SyntheticJoystickHandler extends Handler {
5590        private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
5591        private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
5592
5593        private final JoystickAxesState mJoystickAxesState = new JoystickAxesState();
5594        private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>();
5595
5596        public SyntheticJoystickHandler() {
5597            super(true);
5598        }
5599
5600        @Override
5601        public void handleMessage(Message msg) {
5602            switch (msg.what) {
5603                case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
5604                case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
5605                    if (mAttachInfo.mHasWindowFocus) {
5606                        KeyEvent oldEvent = (KeyEvent) msg.obj;
5607                        KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
5608                                SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1);
5609                        enqueueInputEvent(e);
5610                        Message m = obtainMessage(msg.what, e);
5611                        m.setAsynchronous(true);
5612                        sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
5613                    }
5614                } break;
5615            }
5616        }
5617
5618        public void process(MotionEvent event) {
5619            switch(event.getActionMasked()) {
5620                case MotionEvent.ACTION_CANCEL:
5621                    cancel();
5622                    break;
5623                case MotionEvent.ACTION_MOVE:
5624                    update(event);
5625                    break;
5626                default:
5627                    Log.w(mTag, "Unexpected action: " + event.getActionMasked());
5628            }
5629        }
5630
5631        private void cancel() {
5632            removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
5633            removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
5634            for (int i = 0; i < mDeviceKeyEvents.size(); i++) {
5635                final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i);
5636                if (keyEvent != null) {
5637                    enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent,
5638                            SystemClock.uptimeMillis(), 0));
5639                }
5640            }
5641            mDeviceKeyEvents.clear();
5642            mJoystickAxesState.resetState();
5643        }
5644
5645        private void update(MotionEvent event) {
5646            final int historySize = event.getHistorySize();
5647            for (int h = 0; h < historySize; h++) {
5648                final long time = event.getHistoricalEventTime(h);
5649                mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
5650                        event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h));
5651                mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
5652                        event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h));
5653                mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
5654                        event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h));
5655                mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
5656                        event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h));
5657            }
5658            final long time = event.getEventTime();
5659            mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
5660                    event.getAxisValue(MotionEvent.AXIS_X));
5661            mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
5662                    event.getAxisValue(MotionEvent.AXIS_Y));
5663            mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
5664                    event.getAxisValue(MotionEvent.AXIS_HAT_X));
5665            mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
5666                    event.getAxisValue(MotionEvent.AXIS_HAT_Y));
5667        }
5668
5669        final class JoystickAxesState {
5670            // State machine: from neutral state (no button press) can go into
5671            // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event.
5672            // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state,
5673            // emitting an ACTION_UP event.
5674            private static final int STATE_UP_OR_LEFT = -1;
5675            private static final int STATE_NEUTRAL = 0;
5676            private static final int STATE_DOWN_OR_RIGHT = 1;
5677
5678            final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y}
5679            final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y}
5680
5681            void resetState() {
5682                mAxisStatesHat[0] = STATE_NEUTRAL;
5683                mAxisStatesHat[1] = STATE_NEUTRAL;
5684                mAxisStatesStick[0] = STATE_NEUTRAL;
5685                mAxisStatesStick[1] = STATE_NEUTRAL;
5686            }
5687
5688            void updateStateForAxis(MotionEvent event, long time, int axis, float value) {
5689                // Emit KeyEvent if necessary
5690                // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y
5691                final int axisStateIndex;
5692                final int repeatMessage;
5693                if (isXAxis(axis)) {
5694                    axisStateIndex = 0;
5695                    repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT;
5696                } else if (isYAxis(axis)) {
5697                    axisStateIndex = 1;
5698                    repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT;
5699                } else {
5700                    Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!");
5701                    return;
5702                }
5703                final int newState = joystickAxisValueToState(value);
5704
5705                final int currentState;
5706                if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
5707                    currentState = mAxisStatesStick[axisStateIndex];
5708                } else {
5709                    currentState = mAxisStatesHat[axisStateIndex];
5710                }
5711
5712                if (currentState == newState) {
5713                    return;
5714                }
5715
5716                final int metaState = event.getMetaState();
5717                final int deviceId = event.getDeviceId();
5718                final int source = event.getSource();
5719
5720                if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) {
5721                    // send a button release event
5722                    final int keyCode = joystickAxisAndStateToKeycode(axis, currentState);
5723                    if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
5724                        enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
5725                                0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
5726                        // remove the corresponding pending UP event if focus lost/view detached
5727                        mDeviceKeyEvents.put(deviceId, null);
5728                    }
5729                    removeMessages(repeatMessage);
5730                }
5731
5732                if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) {
5733                    // send a button down event
5734                    final int keyCode = joystickAxisAndStateToKeycode(axis, newState);
5735                    if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
5736                        KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode,
5737                                0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
5738                        enqueueInputEvent(keyEvent);
5739                        Message m = obtainMessage(repeatMessage, keyEvent);
5740                        m.setAsynchronous(true);
5741                        sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
5742                        // store the corresponding ACTION_UP event so that it can be sent
5743                        // if focus is lost or root view is removed
5744                        mDeviceKeyEvents.put(deviceId,
5745                                new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
5746                                        0, metaState, deviceId, 0,
5747                                        KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED,
5748                                        source));
5749                    }
5750                }
5751                if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
5752                    mAxisStatesStick[axisStateIndex] = newState;
5753                } else {
5754                    mAxisStatesHat[axisStateIndex] = newState;
5755                }
5756            }
5757
5758            private boolean isXAxis(int axis) {
5759                return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X;
5760            }
5761            private boolean isYAxis(int axis) {
5762                return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y;
5763            }
5764
5765            private int joystickAxisAndStateToKeycode(int axis, int state) {
5766                if (isXAxis(axis) && state == STATE_UP_OR_LEFT) {
5767                    return KeyEvent.KEYCODE_DPAD_LEFT;
5768                }
5769                if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
5770                    return KeyEvent.KEYCODE_DPAD_RIGHT;
5771                }
5772                if (isYAxis(axis) && state == STATE_UP_OR_LEFT) {
5773                    return KeyEvent.KEYCODE_DPAD_UP;
5774                }
5775                if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
5776                    return KeyEvent.KEYCODE_DPAD_DOWN;
5777                }
5778                Log.e(mTag, "Unknown axis " + axis + " or direction " + state);
5779                return KeyEvent.KEYCODE_UNKNOWN; // should never happen
5780            }
5781
5782            private int joystickAxisValueToState(float value) {
5783                if (value >= 0.5f) {
5784                    return STATE_DOWN_OR_RIGHT;
5785                } else if (value <= -0.5f) {
5786                    return STATE_UP_OR_LEFT;
5787                } else {
5788                    return STATE_NEUTRAL;
5789                }
5790            }
5791        }
5792    }
5793
5794    /**
5795     * Creates dpad events from unhandled touch navigation movements.
5796     */
5797    final class SyntheticTouchNavigationHandler extends Handler {
5798        private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
5799        private static final boolean LOCAL_DEBUG = false;
5800
5801        // Assumed nominal width and height in millimeters of a touch navigation pad,
5802        // if no resolution information is available from the input system.
5803        private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
5804        private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
5805
5806        /* TODO: These constants should eventually be moved to ViewConfiguration. */
5807
5808        // The nominal distance traveled to move by one unit.
5809        private static final int TICK_DISTANCE_MILLIMETERS = 12;
5810
5811        // Minimum and maximum fling velocity in ticks per second.
5812        // The minimum velocity should be set such that we perform enough ticks per
5813        // second that the fling appears to be fluid.  For example, if we set the minimum
5814        // to 2 ticks per second, then there may be up to half a second delay between the next
5815        // to last and last ticks which is noticeably discrete and jerky.  This value should
5816        // probably not be set to anything less than about 4.
5817        // If fling accuracy is a problem then consider tuning the tick distance instead.
5818        private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
5819        private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
5820
5821        // Fling velocity decay factor applied after each new key is emitted.
5822        // This parameter controls the deceleration and overall duration of the fling.
5823        // The fling stops automatically when its velocity drops below the minimum
5824        // fling velocity defined above.
5825        private static final float FLING_TICK_DECAY = 0.8f;
5826
5827        /* The input device that we are tracking. */
5828
5829        private int mCurrentDeviceId = -1;
5830        private int mCurrentSource;
5831        private boolean mCurrentDeviceSupported;
5832
5833        /* Configuration for the current input device. */
5834
5835        // The scaled tick distance.  A movement of this amount should generally translate
5836        // into a single dpad event in a given direction.
5837        private float mConfigTickDistance;
5838
5839        // The minimum and maximum scaled fling velocity.
5840        private float mConfigMinFlingVelocity;
5841        private float mConfigMaxFlingVelocity;
5842
5843        /* Tracking state. */
5844
5845        // The velocity tracker for detecting flings.
5846        private VelocityTracker mVelocityTracker;
5847
5848        // The active pointer id, or -1 if none.
5849        private int mActivePointerId = -1;
5850
5851        // Location where tracking started.
5852        private float mStartX;
5853        private float mStartY;
5854
5855        // Most recently observed position.
5856        private float mLastX;
5857        private float mLastY;
5858
5859        // Accumulated movement delta since the last direction key was sent.
5860        private float mAccumulatedX;
5861        private float mAccumulatedY;
5862
5863        // Set to true if any movement was delivered to the app.
5864        // Implies that tap slop was exceeded.
5865        private boolean mConsumedMovement;
5866
5867        // The most recently sent key down event.
5868        // The keycode remains set until the direction changes or a fling ends
5869        // so that repeated key events may be generated as required.
5870        private long mPendingKeyDownTime;
5871        private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
5872        private int mPendingKeyRepeatCount;
5873        private int mPendingKeyMetaState;
5874
5875        // The current fling velocity while a fling is in progress.
5876        private boolean mFlinging;
5877        private float mFlingVelocity;
5878
5879        public SyntheticTouchNavigationHandler() {
5880            super(true);
5881        }
5882
5883        public void process(MotionEvent event) {
5884            // Update the current device information.
5885            final long time = event.getEventTime();
5886            final int deviceId = event.getDeviceId();
5887            final int source = event.getSource();
5888            if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
5889                finishKeys(time);
5890                finishTracking(time);
5891                mCurrentDeviceId = deviceId;
5892                mCurrentSource = source;
5893                mCurrentDeviceSupported = false;
5894                InputDevice device = event.getDevice();
5895                if (device != null) {
5896                    // In order to support an input device, we must know certain
5897                    // characteristics about it, such as its size and resolution.
5898                    InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
5899                    InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
5900                    if (xRange != null && yRange != null) {
5901                        mCurrentDeviceSupported = true;
5902
5903                        // Infer the resolution if it not actually known.
5904                        float xRes = xRange.getResolution();
5905                        if (xRes <= 0) {
5906                            xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
5907                        }
5908                        float yRes = yRange.getResolution();
5909                        if (yRes <= 0) {
5910                            yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
5911                        }
5912                        float nominalRes = (xRes + yRes) * 0.5f;
5913
5914                        // Precompute all of the configuration thresholds we will need.
5915                        mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
5916                        mConfigMinFlingVelocity =
5917                                MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5918                        mConfigMaxFlingVelocity =
5919                                MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5920
5921                        if (LOCAL_DEBUG) {
5922                            Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
5923                                    + " (" + Integer.toHexString(mCurrentSource) + "): "
5924                                    + ", mConfigTickDistance=" + mConfigTickDistance
5925                                    + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
5926                                    + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
5927                        }
5928                    }
5929                }
5930            }
5931            if (!mCurrentDeviceSupported) {
5932                return;
5933            }
5934
5935            // Handle the event.
5936            final int action = event.getActionMasked();
5937            switch (action) {
5938                case MotionEvent.ACTION_DOWN: {
5939                    boolean caughtFling = mFlinging;
5940                    finishKeys(time);
5941                    finishTracking(time);
5942                    mActivePointerId = event.getPointerId(0);
5943                    mVelocityTracker = VelocityTracker.obtain();
5944                    mVelocityTracker.addMovement(event);
5945                    mStartX = event.getX();
5946                    mStartY = event.getY();
5947                    mLastX = mStartX;
5948                    mLastY = mStartY;
5949                    mAccumulatedX = 0;
5950                    mAccumulatedY = 0;
5951
5952                    // If we caught a fling, then pretend that the tap slop has already
5953                    // been exceeded to suppress taps whose only purpose is to stop the fling.
5954                    mConsumedMovement = caughtFling;
5955                    break;
5956                }
5957
5958                case MotionEvent.ACTION_MOVE:
5959                case MotionEvent.ACTION_UP: {
5960                    if (mActivePointerId < 0) {
5961                        break;
5962                    }
5963                    final int index = event.findPointerIndex(mActivePointerId);
5964                    if (index < 0) {
5965                        finishKeys(time);
5966                        finishTracking(time);
5967                        break;
5968                    }
5969
5970                    mVelocityTracker.addMovement(event);
5971                    final float x = event.getX(index);
5972                    final float y = event.getY(index);
5973                    mAccumulatedX += x - mLastX;
5974                    mAccumulatedY += y - mLastY;
5975                    mLastX = x;
5976                    mLastY = y;
5977
5978                    // Consume any accumulated movement so far.
5979                    final int metaState = event.getMetaState();
5980                    consumeAccumulatedMovement(time, metaState);
5981
5982                    // Detect taps and flings.
5983                    if (action == MotionEvent.ACTION_UP) {
5984                        if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
5985                            // It might be a fling.
5986                            mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
5987                            final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
5988                            final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
5989                            if (!startFling(time, vx, vy)) {
5990                                finishKeys(time);
5991                            }
5992                        }
5993                        finishTracking(time);
5994                    }
5995                    break;
5996                }
5997
5998                case MotionEvent.ACTION_CANCEL: {
5999                    finishKeys(time);
6000                    finishTracking(time);
6001                    break;
6002                }
6003            }
6004        }
6005
6006        public void cancel(MotionEvent event) {
6007            if (mCurrentDeviceId == event.getDeviceId()
6008                    && mCurrentSource == event.getSource()) {
6009                final long time = event.getEventTime();
6010                finishKeys(time);
6011                finishTracking(time);
6012            }
6013        }
6014
6015        private void finishKeys(long time) {
6016            cancelFling();
6017            sendKeyUp(time);
6018        }
6019
6020        private void finishTracking(long time) {
6021            if (mActivePointerId >= 0) {
6022                mActivePointerId = -1;
6023                mVelocityTracker.recycle();
6024                mVelocityTracker = null;
6025            }
6026        }
6027
6028        private void consumeAccumulatedMovement(long time, int metaState) {
6029            final float absX = Math.abs(mAccumulatedX);
6030            final float absY = Math.abs(mAccumulatedY);
6031            if (absX >= absY) {
6032                if (absX >= mConfigTickDistance) {
6033                    mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
6034                            KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
6035                    mAccumulatedY = 0;
6036                    mConsumedMovement = true;
6037                }
6038            } else {
6039                if (absY >= mConfigTickDistance) {
6040                    mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
6041                            KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
6042                    mAccumulatedX = 0;
6043                    mConsumedMovement = true;
6044                }
6045            }
6046        }
6047
6048        private float consumeAccumulatedMovement(long time, int metaState,
6049                float accumulator, int negativeKeyCode, int positiveKeyCode) {
6050            while (accumulator <= -mConfigTickDistance) {
6051                sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
6052                accumulator += mConfigTickDistance;
6053            }
6054            while (accumulator >= mConfigTickDistance) {
6055                sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
6056                accumulator -= mConfigTickDistance;
6057            }
6058            return accumulator;
6059        }
6060
6061        private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
6062            if (mPendingKeyCode != keyCode) {
6063                sendKeyUp(time);
6064                mPendingKeyDownTime = time;
6065                mPendingKeyCode = keyCode;
6066                mPendingKeyRepeatCount = 0;
6067            } else {
6068                mPendingKeyRepeatCount += 1;
6069            }
6070            mPendingKeyMetaState = metaState;
6071
6072            // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
6073            // but it doesn't quite make sense when simulating the events in this way.
6074            if (LOCAL_DEBUG) {
6075                Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
6076                        + ", repeatCount=" + mPendingKeyRepeatCount
6077                        + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
6078            }
6079            enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
6080                    KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
6081                    mPendingKeyMetaState, mCurrentDeviceId,
6082                    KeyEvent.FLAG_FALLBACK, mCurrentSource));
6083        }
6084
6085        private void sendKeyUp(long time) {
6086            if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
6087                if (LOCAL_DEBUG) {
6088                    Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
6089                            + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
6090                }
6091                enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
6092                        KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
6093                        mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
6094                        mCurrentSource));
6095                mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
6096            }
6097        }
6098
6099        private boolean startFling(long time, float vx, float vy) {
6100            if (LOCAL_DEBUG) {
6101                Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
6102                        + ", min=" + mConfigMinFlingVelocity);
6103            }
6104
6105            // Flings must be oriented in the same direction as the preceding movements.
6106            switch (mPendingKeyCode) {
6107                case KeyEvent.KEYCODE_DPAD_LEFT:
6108                    if (-vx >= mConfigMinFlingVelocity
6109                            && Math.abs(vy) < mConfigMinFlingVelocity) {
6110                        mFlingVelocity = -vx;
6111                        break;
6112                    }
6113                    return false;
6114
6115                case KeyEvent.KEYCODE_DPAD_RIGHT:
6116                    if (vx >= mConfigMinFlingVelocity
6117                            && Math.abs(vy) < mConfigMinFlingVelocity) {
6118                        mFlingVelocity = vx;
6119                        break;
6120                    }
6121                    return false;
6122
6123                case KeyEvent.KEYCODE_DPAD_UP:
6124                    if (-vy >= mConfigMinFlingVelocity
6125                            && Math.abs(vx) < mConfigMinFlingVelocity) {
6126                        mFlingVelocity = -vy;
6127                        break;
6128                    }
6129                    return false;
6130
6131                case KeyEvent.KEYCODE_DPAD_DOWN:
6132                    if (vy >= mConfigMinFlingVelocity
6133                            && Math.abs(vx) < mConfigMinFlingVelocity) {
6134                        mFlingVelocity = vy;
6135                        break;
6136                    }
6137                    return false;
6138            }
6139
6140            // Post the first fling event.
6141            mFlinging = postFling(time);
6142            return mFlinging;
6143        }
6144
6145        private boolean postFling(long time) {
6146            // The idea here is to estimate the time when the pointer would have
6147            // traveled one tick distance unit given the current fling velocity.
6148            // This effect creates continuity of motion.
6149            if (mFlingVelocity >= mConfigMinFlingVelocity) {
6150                long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
6151                postAtTime(mFlingRunnable, time + delay);
6152                if (LOCAL_DEBUG) {
6153                    Log.d(LOCAL_TAG, "Posted fling: velocity="
6154                            + mFlingVelocity + ", delay=" + delay
6155                            + ", keyCode=" + mPendingKeyCode);
6156                }
6157                return true;
6158            }
6159            return false;
6160        }
6161
6162        private void cancelFling() {
6163            if (mFlinging) {
6164                removeCallbacks(mFlingRunnable);
6165                mFlinging = false;
6166            }
6167        }
6168
6169        private final Runnable mFlingRunnable = new Runnable() {
6170            @Override
6171            public void run() {
6172                final long time = SystemClock.uptimeMillis();
6173                sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
6174                mFlingVelocity *= FLING_TICK_DECAY;
6175                if (!postFling(time)) {
6176                    mFlinging = false;
6177                    finishKeys(time);
6178                }
6179            }
6180        };
6181    }
6182
6183    final class SyntheticKeyboardHandler {
6184        public void process(KeyEvent event) {
6185            if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
6186                return;
6187            }
6188
6189            final KeyCharacterMap kcm = event.getKeyCharacterMap();
6190            final int keyCode = event.getKeyCode();
6191            final int metaState = event.getMetaState();
6192
6193            // Check for fallback actions specified by the key character map.
6194            KeyCharacterMap.FallbackAction fallbackAction =
6195                    kcm.getFallbackAction(keyCode, metaState);
6196            if (fallbackAction != null) {
6197                final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
6198                KeyEvent fallbackEvent = KeyEvent.obtain(
6199                        event.getDownTime(), event.getEventTime(),
6200                        event.getAction(), fallbackAction.keyCode,
6201                        event.getRepeatCount(), fallbackAction.metaState,
6202                        event.getDeviceId(), event.getScanCode(),
6203                        flags, event.getSource(), null);
6204                fallbackAction.recycle();
6205                enqueueInputEvent(fallbackEvent);
6206            }
6207        }
6208    }
6209
6210    /**
6211     * Returns true if the key is used for keyboard navigation.
6212     * @param keyEvent The key event.
6213     * @return True if the key is used for keyboard navigation.
6214     */
6215    private static boolean isNavigationKey(KeyEvent keyEvent) {
6216        switch (keyEvent.getKeyCode()) {
6217        case KeyEvent.KEYCODE_DPAD_LEFT:
6218        case KeyEvent.KEYCODE_DPAD_RIGHT:
6219        case KeyEvent.KEYCODE_DPAD_UP:
6220        case KeyEvent.KEYCODE_DPAD_DOWN:
6221        case KeyEvent.KEYCODE_DPAD_CENTER:
6222        case KeyEvent.KEYCODE_PAGE_UP:
6223        case KeyEvent.KEYCODE_PAGE_DOWN:
6224        case KeyEvent.KEYCODE_MOVE_HOME:
6225        case KeyEvent.KEYCODE_MOVE_END:
6226        case KeyEvent.KEYCODE_TAB:
6227        case KeyEvent.KEYCODE_SPACE:
6228        case KeyEvent.KEYCODE_ENTER:
6229            return true;
6230        }
6231        return false;
6232    }
6233
6234    /**
6235     * Returns true if the key is used for typing.
6236     * @param keyEvent The key event.
6237     * @return True if the key is used for typing.
6238     */
6239    private static boolean isTypingKey(KeyEvent keyEvent) {
6240        return keyEvent.getUnicodeChar() > 0;
6241    }
6242
6243    /**
6244     * See if the key event means we should leave touch mode (and leave touch mode if so).
6245     * @param event The key event.
6246     * @return Whether this key event should be consumed (meaning the act of
6247     *   leaving touch mode alone is considered the event).
6248     */
6249    private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
6250        // Only relevant in touch mode.
6251        if (!mAttachInfo.mInTouchMode) {
6252            return false;
6253        }
6254
6255        // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
6256        final int action = event.getAction();
6257        if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
6258            return false;
6259        }
6260
6261        // Don't leave touch mode if the IME told us not to.
6262        if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
6263            return false;
6264        }
6265
6266        // If the key can be used for keyboard navigation then leave touch mode
6267        // and select a focused view if needed (in ensureTouchMode).
6268        // When a new focused view is selected, we consume the navigation key because
6269        // navigation doesn't make much sense unless a view already has focus so
6270        // the key's purpose is to set focus.
6271        if (isNavigationKey(event)) {
6272            return ensureTouchMode(false);
6273        }
6274
6275        // If the key can be used for typing then leave touch mode
6276        // and select a focused view if needed (in ensureTouchMode).
6277        // Always allow the view to process the typing key.
6278        if (isTypingKey(event)) {
6279            ensureTouchMode(false);
6280            return false;
6281        }
6282
6283        return false;
6284    }
6285
6286    /* drag/drop */
6287    void setLocalDragState(Object obj) {
6288        mLocalDragState = obj;
6289    }
6290
6291    private void handleDragEvent(DragEvent event) {
6292        // From the root, only drag start/end/location are dispatched.  entered/exited
6293        // are determined and dispatched by the viewgroup hierarchy, who then report
6294        // that back here for ultimate reporting back to the framework.
6295        if (mView != null && mAdded) {
6296            final int what = event.mAction;
6297
6298            // Cache the drag description when the operation starts, then fill it in
6299            // on subsequent calls as a convenience
6300            if (what == DragEvent.ACTION_DRAG_STARTED) {
6301                mCurrentDragView = null;    // Start the current-recipient tracking
6302                mDragDescription = event.mClipDescription;
6303            } else {
6304                if (what == DragEvent.ACTION_DRAG_ENDED) {
6305                    mDragDescription = null;
6306                }
6307                event.mClipDescription = mDragDescription;
6308            }
6309
6310            if (what == DragEvent.ACTION_DRAG_EXITED) {
6311                // A direct EXITED event means that the window manager knows we've just crossed
6312                // a window boundary, so the current drag target within this one must have
6313                // just been exited. Send the EXITED notification to the current drag view, if any.
6314                if (View.sCascadedDragDrop) {
6315                    mView.dispatchDragEnterExitInPreN(event);
6316                }
6317                setDragFocus(null, event);
6318            } else {
6319                // For events with a [screen] location, translate into window coordinates
6320                if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
6321                    mDragPoint.set(event.mX, event.mY);
6322                    if (mTranslator != null) {
6323                        mTranslator.translatePointInScreenToAppWindow(mDragPoint);
6324                    }
6325
6326                    if (mCurScrollY != 0) {
6327                        mDragPoint.offset(0, mCurScrollY);
6328                    }
6329
6330                    event.mX = mDragPoint.x;
6331                    event.mY = mDragPoint.y;
6332                }
6333
6334                // Remember who the current drag target is pre-dispatch
6335                final View prevDragView = mCurrentDragView;
6336
6337                if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
6338                    event.mClipData.prepareToEnterProcess();
6339                }
6340
6341                // Now dispatch the drag/drop event
6342                boolean result = mView.dispatchDragEvent(event);
6343
6344                if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
6345                    // If the LOCATION event wasn't delivered to any handler, no view now has a drag
6346                    // focus.
6347                    setDragFocus(null, event);
6348                }
6349
6350                // If we changed apparent drag target, tell the OS about it
6351                if (prevDragView != mCurrentDragView) {
6352                    try {
6353                        if (prevDragView != null) {
6354                            mWindowSession.dragRecipientExited(mWindow);
6355                        }
6356                        if (mCurrentDragView != null) {
6357                            mWindowSession.dragRecipientEntered(mWindow);
6358                        }
6359                    } catch (RemoteException e) {
6360                        Slog.e(mTag, "Unable to note drag target change");
6361                    }
6362                }
6363
6364                // Report the drop result when we're done
6365                if (what == DragEvent.ACTION_DROP) {
6366                    try {
6367                        Log.i(mTag, "Reporting drop result: " + result);
6368                        mWindowSession.reportDropResult(mWindow, result);
6369                    } catch (RemoteException e) {
6370                        Log.e(mTag, "Unable to report drop result");
6371                    }
6372                }
6373
6374                // When the drag operation ends, reset drag-related state
6375                if (what == DragEvent.ACTION_DRAG_ENDED) {
6376                    mCurrentDragView = null;
6377                    setLocalDragState(null);
6378                    mAttachInfo.mDragToken = null;
6379                    if (mAttachInfo.mDragSurface != null) {
6380                        mAttachInfo.mDragSurface.release();
6381                        mAttachInfo.mDragSurface = null;
6382                    }
6383                }
6384            }
6385        }
6386        event.recycle();
6387    }
6388
6389    public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
6390        if (mSeq != args.seq) {
6391            // The sequence has changed, so we need to update our value and make
6392            // sure to do a traversal afterward so the window manager is given our
6393            // most recent data.
6394            mSeq = args.seq;
6395            mAttachInfo.mForceReportNewAttributes = true;
6396            scheduleTraversals();
6397        }
6398        if (mView == null) return;
6399        if (args.localChanges != 0) {
6400            mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
6401        }
6402
6403        int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
6404        if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
6405            mAttachInfo.mGlobalSystemUiVisibility = visibility;
6406            mView.dispatchSystemUiVisibilityChanged(visibility);
6407        }
6408    }
6409
6410    /**
6411     * Notify that the window title changed
6412     */
6413    public void onWindowTitleChanged() {
6414        mAttachInfo.mForceReportNewAttributes = true;
6415    }
6416
6417    public void handleDispatchWindowShown() {
6418        mAttachInfo.mTreeObserver.dispatchOnWindowShown();
6419    }
6420
6421    public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
6422        Bundle data = new Bundle();
6423        ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
6424        if (mView != null) {
6425            mView.requestKeyboardShortcuts(list, deviceId);
6426        }
6427        data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
6428        try {
6429            receiver.send(0, data);
6430        } catch (RemoteException e) {
6431        }
6432    }
6433
6434    public void getLastTouchPoint(Point outLocation) {
6435        outLocation.x = (int) mLastTouchPoint.x;
6436        outLocation.y = (int) mLastTouchPoint.y;
6437    }
6438
6439    public int getLastTouchSource() {
6440        return mLastTouchSource;
6441    }
6442
6443    public void setDragFocus(View newDragTarget, DragEvent event) {
6444        if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
6445            // Send EXITED and ENTERED notifications to the old and new drag focus views.
6446
6447            final float tx = event.mX;
6448            final float ty = event.mY;
6449            final int action = event.mAction;
6450            final ClipData td = event.mClipData;
6451            // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
6452            event.mX = 0;
6453            event.mY = 0;
6454            event.mClipData = null;
6455
6456            if (mCurrentDragView != null) {
6457                event.mAction = DragEvent.ACTION_DRAG_EXITED;
6458                mCurrentDragView.callDragEventHandler(event);
6459            }
6460
6461            if (newDragTarget != null) {
6462                event.mAction = DragEvent.ACTION_DRAG_ENTERED;
6463                newDragTarget.callDragEventHandler(event);
6464            }
6465
6466            event.mAction = action;
6467            event.mX = tx;
6468            event.mY = ty;
6469            event.mClipData = td;
6470        }
6471
6472        mCurrentDragView = newDragTarget;
6473    }
6474
6475    private AudioManager getAudioManager() {
6476        if (mView == null) {
6477            throw new IllegalStateException("getAudioManager called when there is no mView");
6478        }
6479        if (mAudioManager == null) {
6480            mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
6481        }
6482        return mAudioManager;
6483    }
6484
6485    private @Nullable AutofillManager getAutofillManager() {
6486        if (mView instanceof ViewGroup) {
6487            ViewGroup decorView = (ViewGroup) mView;
6488            if (decorView.getChildCount() > 0) {
6489                // We cannot use decorView's Context for querying AutofillManager: DecorView's
6490                // context is based on Application Context, it would allocate a different
6491                // AutofillManager instance.
6492                return decorView.getChildAt(0).getContext()
6493                        .getSystemService(AutofillManager.class);
6494            }
6495        }
6496        return null;
6497    }
6498
6499    private boolean isAutofillUiShowing() {
6500        AutofillManager afm = getAutofillManager();
6501        if (afm == null) {
6502            return false;
6503        }
6504        return afm.isAutofillUiShowing();
6505    }
6506
6507    public AccessibilityInteractionController getAccessibilityInteractionController() {
6508        if (mView == null) {
6509            throw new IllegalStateException("getAccessibilityInteractionController"
6510                    + " called when there is no mView");
6511        }
6512        if (mAccessibilityInteractionController == null) {
6513            mAccessibilityInteractionController = new AccessibilityInteractionController(this);
6514        }
6515        return mAccessibilityInteractionController;
6516    }
6517
6518    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
6519            boolean insetsPending) throws RemoteException {
6520
6521        float appScale = mAttachInfo.mApplicationScale;
6522        boolean restore = false;
6523        if (params != null && mTranslator != null) {
6524            restore = true;
6525            params.backup();
6526            mTranslator.translateWindowLayout(params);
6527        }
6528
6529        if (params != null) {
6530            if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
6531
6532            if (mOrigWindowType != params.type) {
6533                // For compatibility with old apps, don't crash here.
6534                if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
6535                    Slog.w(mTag, "Window type can not be changed after "
6536                            + "the window is added; ignoring change of " + mView);
6537                    params.type = mOrigWindowType;
6538                }
6539            }
6540        }
6541
6542        long frameNumber = -1;
6543        if (mSurface.isValid()) {
6544            frameNumber = mSurface.getNextFrameNumber();
6545        }
6546
6547        int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
6548                (int) (mView.getMeasuredWidth() * appScale + 0.5f),
6549                (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
6550                insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
6551                mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
6552                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
6553                mPendingMergedConfiguration, mSurface);
6554
6555        mPendingAlwaysConsumeNavBar =
6556                (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
6557
6558        if (restore) {
6559            params.restore();
6560        }
6561
6562        if (mTranslator != null) {
6563            mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
6564            mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
6565            mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
6566            mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
6567            mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
6568        }
6569        return relayoutResult;
6570    }
6571
6572    /**
6573     * {@inheritDoc}
6574     */
6575    @Override
6576    public void playSoundEffect(int effectId) {
6577        checkThread();
6578
6579        try {
6580            final AudioManager audioManager = getAudioManager();
6581
6582            switch (effectId) {
6583                case SoundEffectConstants.CLICK:
6584                    audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
6585                    return;
6586                case SoundEffectConstants.NAVIGATION_DOWN:
6587                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
6588                    return;
6589                case SoundEffectConstants.NAVIGATION_LEFT:
6590                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
6591                    return;
6592                case SoundEffectConstants.NAVIGATION_RIGHT:
6593                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
6594                    return;
6595                case SoundEffectConstants.NAVIGATION_UP:
6596                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
6597                    return;
6598                default:
6599                    throw new IllegalArgumentException("unknown effect id " + effectId +
6600                            " not defined in " + SoundEffectConstants.class.getCanonicalName());
6601            }
6602        } catch (IllegalStateException e) {
6603            // Exception thrown by getAudioManager() when mView is null
6604            Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
6605            e.printStackTrace();
6606        }
6607    }
6608
6609    /**
6610     * {@inheritDoc}
6611     */
6612    @Override
6613    public boolean performHapticFeedback(int effectId, boolean always) {
6614        try {
6615            return mWindowSession.performHapticFeedback(mWindow, effectId, always);
6616        } catch (RemoteException e) {
6617            return false;
6618        }
6619    }
6620
6621    /**
6622     * {@inheritDoc}
6623     */
6624    @Override
6625    public View focusSearch(View focused, int direction) {
6626        checkThread();
6627        if (!(mView instanceof ViewGroup)) {
6628            return null;
6629        }
6630        return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
6631    }
6632
6633    /**
6634     * {@inheritDoc}
6635     */
6636    @Override
6637    public View keyboardNavigationClusterSearch(View currentCluster,
6638            @FocusDirection int direction) {
6639        checkThread();
6640        return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
6641                mView, currentCluster, direction);
6642    }
6643
6644    public void debug() {
6645        mView.debug();
6646    }
6647
6648    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
6649        String innerPrefix = prefix + "  ";
6650        writer.print(prefix); writer.println("ViewRoot:");
6651        writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
6652                writer.print(" mRemoved="); writer.println(mRemoved);
6653        writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
6654                writer.println(mConsumeBatchedInputScheduled);
6655        writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
6656                writer.println(mConsumeBatchedInputImmediatelyScheduled);
6657        writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
6658                writer.println(mPendingInputEventCount);
6659        writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
6660                writer.println(mProcessInputEventsScheduled);
6661        writer.print(innerPrefix); writer.print("mTraversalScheduled=");
6662                writer.print(mTraversalScheduled);
6663        writer.print(innerPrefix); writer.print("mIsAmbientMode=");
6664                writer.print(mIsAmbientMode);
6665        if (mTraversalScheduled) {
6666            writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
6667        } else {
6668            writer.println();
6669        }
6670        mFirstInputStage.dump(innerPrefix, writer);
6671
6672        mChoreographer.dump(prefix, writer);
6673
6674        writer.print(prefix); writer.println("View Hierarchy:");
6675        dumpViewHierarchy(innerPrefix, writer, mView);
6676    }
6677
6678    private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
6679        writer.print(prefix);
6680        if (view == null) {
6681            writer.println("null");
6682            return;
6683        }
6684        writer.println(view.toString());
6685        if (!(view instanceof ViewGroup)) {
6686            return;
6687        }
6688        ViewGroup grp = (ViewGroup)view;
6689        final int N = grp.getChildCount();
6690        if (N <= 0) {
6691            return;
6692        }
6693        prefix = prefix + "  ";
6694        for (int i=0; i<N; i++) {
6695            dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
6696        }
6697    }
6698
6699    public void dumpGfxInfo(int[] info) {
6700        info[0] = info[1] = 0;
6701        if (mView != null) {
6702            getGfxInfo(mView, info);
6703        }
6704    }
6705
6706    private static void getGfxInfo(View view, int[] info) {
6707        RenderNode renderNode = view.mRenderNode;
6708        info[0]++;
6709        if (renderNode != null) {
6710            info[1] += renderNode.getDebugSize();
6711        }
6712
6713        if (view instanceof ViewGroup) {
6714            ViewGroup group = (ViewGroup) view;
6715
6716            int count = group.getChildCount();
6717            for (int i = 0; i < count; i++) {
6718                getGfxInfo(group.getChildAt(i), info);
6719            }
6720        }
6721    }
6722
6723    /**
6724     * @param immediate True, do now if not in traversal. False, put on queue and do later.
6725     * @return True, request has been queued. False, request has been completed.
6726     */
6727    boolean die(boolean immediate) {
6728        // Make sure we do execute immediately if we are in the middle of a traversal or the damage
6729        // done by dispatchDetachedFromWindow will cause havoc on return.
6730        if (immediate && !mIsInTraversal) {
6731            doDie();
6732            return false;
6733        }
6734
6735        if (!mIsDrawing) {
6736            destroyHardwareRenderer();
6737        } else {
6738            Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
6739                    "  window=" + this + ", title=" + mWindowAttributes.getTitle());
6740        }
6741        mHandler.sendEmptyMessage(MSG_DIE);
6742        return true;
6743    }
6744
6745    void doDie() {
6746        checkThread();
6747        if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
6748        synchronized (this) {
6749            if (mRemoved) {
6750                return;
6751            }
6752            mRemoved = true;
6753            if (mAdded) {
6754                dispatchDetachedFromWindow();
6755            }
6756
6757            if (mAdded && !mFirst) {
6758                destroyHardwareRenderer();
6759
6760                if (mView != null) {
6761                    int viewVisibility = mView.getVisibility();
6762                    boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
6763                    if (mWindowAttributesChanged || viewVisibilityChanged) {
6764                        // If layout params have been changed, first give them
6765                        // to the window manager to make sure it has the correct
6766                        // animation info.
6767                        try {
6768                            if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
6769                                    & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
6770                                mWindowSession.finishDrawing(mWindow);
6771                            }
6772                        } catch (RemoteException e) {
6773                        }
6774                    }
6775
6776                    mSurface.release();
6777                }
6778            }
6779
6780            mAdded = false;
6781        }
6782        WindowManagerGlobal.getInstance().doRemoveView(this);
6783    }
6784
6785    public void requestUpdateConfiguration(Configuration config) {
6786        Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
6787        mHandler.sendMessage(msg);
6788    }
6789
6790    public void loadSystemProperties() {
6791        mHandler.post(new Runnable() {
6792            @Override
6793            public void run() {
6794                // Profiling
6795                mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
6796                profileRendering(mAttachInfo.mHasWindowFocus);
6797
6798                // Hardware rendering
6799                if (mAttachInfo.mThreadedRenderer != null) {
6800                    if (mAttachInfo.mThreadedRenderer.loadSystemProperties()) {
6801                        invalidate();
6802                    }
6803                }
6804
6805                // Layout debugging
6806                boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
6807                if (layout != mAttachInfo.mDebugLayout) {
6808                    mAttachInfo.mDebugLayout = layout;
6809                    if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
6810                        mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
6811                    }
6812                }
6813            }
6814        });
6815    }
6816
6817    private void destroyHardwareRenderer() {
6818        ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
6819
6820        if (hardwareRenderer != null) {
6821            if (mView != null) {
6822                hardwareRenderer.destroyHardwareResources(mView);
6823            }
6824            hardwareRenderer.destroy();
6825            hardwareRenderer.setRequested(false);
6826
6827            mAttachInfo.mThreadedRenderer = null;
6828            mAttachInfo.mHardwareAccelerated = false;
6829        }
6830    }
6831
6832    private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
6833            Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
6834            MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
6835            boolean alwaysConsumeNavBar, int displayId,
6836            DisplayCutout.ParcelableWrapper displayCutout) {
6837        if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
6838                + " contentInsets=" + contentInsets.toShortString()
6839                + " visibleInsets=" + visibleInsets.toShortString()
6840                + " reportDraw=" + reportDraw
6841                + " backDropFrame=" + backDropFrame);
6842
6843        // Tell all listeners that we are resizing the window so that the chrome can get
6844        // updated as fast as possible on a separate thread,
6845        if (mDragResizing && mUseMTRenderer) {
6846            boolean fullscreen = frame.equals(backDropFrame);
6847            synchronized (mWindowCallbacks) {
6848                for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
6849                    mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen,
6850                            visibleInsets, stableInsets);
6851                }
6852            }
6853        }
6854
6855        Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
6856        if (mTranslator != null) {
6857            mTranslator.translateRectInScreenToAppWindow(frame);
6858            mTranslator.translateRectInScreenToAppWindow(overscanInsets);
6859            mTranslator.translateRectInScreenToAppWindow(contentInsets);
6860            mTranslator.translateRectInScreenToAppWindow(visibleInsets);
6861        }
6862        SomeArgs args = SomeArgs.obtain();
6863        final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
6864        args.arg1 = sameProcessCall ? new Rect(frame) : frame;
6865        args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
6866        args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
6867        args.arg4 = sameProcessCall && mergedConfiguration != null
6868                ? new MergedConfiguration(mergedConfiguration) : mergedConfiguration;
6869        args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
6870        args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
6871        args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
6872        args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
6873        args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
6874        args.argi1 = forceLayout ? 1 : 0;
6875        args.argi2 = alwaysConsumeNavBar ? 1 : 0;
6876        args.argi3 = displayId;
6877        msg.obj = args;
6878        mHandler.sendMessage(msg);
6879    }
6880
6881    public void dispatchMoved(int newX, int newY) {
6882        if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
6883        if (mTranslator != null) {
6884            PointF point = new PointF(newX, newY);
6885            mTranslator.translatePointInScreenToAppWindow(point);
6886            newX = (int) (point.x + 0.5);
6887            newY = (int) (point.y + 0.5);
6888        }
6889        Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
6890        mHandler.sendMessage(msg);
6891    }
6892
6893    /**
6894     * Represents a pending input event that is waiting in a queue.
6895     *
6896     * Input events are processed in serial order by the timestamp specified by
6897     * {@link InputEvent#getEventTimeNano()}.  In general, the input dispatcher delivers
6898     * one input event to the application at a time and waits for the application
6899     * to finish handling it before delivering the next one.
6900     *
6901     * However, because the application or IME can synthesize and inject multiple
6902     * key events at a time without going through the input dispatcher, we end up
6903     * needing a queue on the application's side.
6904     */
6905    private static final class QueuedInputEvent {
6906        public static final int FLAG_DELIVER_POST_IME = 1 << 0;
6907        public static final int FLAG_DEFERRED = 1 << 1;
6908        public static final int FLAG_FINISHED = 1 << 2;
6909        public static final int FLAG_FINISHED_HANDLED = 1 << 3;
6910        public static final int FLAG_RESYNTHESIZED = 1 << 4;
6911        public static final int FLAG_UNHANDLED = 1 << 5;
6912
6913        public QueuedInputEvent mNext;
6914
6915        public InputEvent mEvent;
6916        public InputEventReceiver mReceiver;
6917        public int mFlags;
6918
6919        public boolean shouldSkipIme() {
6920            if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
6921                return true;
6922            }
6923            return mEvent instanceof MotionEvent
6924                    && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
6925                        || mEvent.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER));
6926        }
6927
6928        public boolean shouldSendToSynthesizer() {
6929            if ((mFlags & FLAG_UNHANDLED) != 0) {
6930                return true;
6931            }
6932
6933            return false;
6934        }
6935
6936        @Override
6937        public String toString() {
6938            StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
6939            boolean hasPrevious = false;
6940            hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
6941            hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
6942            hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
6943            hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
6944            hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
6945            hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
6946            if (!hasPrevious) {
6947                sb.append("0");
6948            }
6949            sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
6950            sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
6951            sb.append(", mEvent=" + mEvent + "}");
6952            return sb.toString();
6953        }
6954
6955        private boolean flagToString(String name, int flag,
6956                boolean hasPrevious, StringBuilder sb) {
6957            if ((mFlags & flag) != 0) {
6958                if (hasPrevious) {
6959                    sb.append("|");
6960                }
6961                sb.append(name);
6962                return true;
6963            }
6964            return hasPrevious;
6965        }
6966    }
6967
6968    private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
6969            InputEventReceiver receiver, int flags) {
6970        QueuedInputEvent q = mQueuedInputEventPool;
6971        if (q != null) {
6972            mQueuedInputEventPoolSize -= 1;
6973            mQueuedInputEventPool = q.mNext;
6974            q.mNext = null;
6975        } else {
6976            q = new QueuedInputEvent();
6977        }
6978
6979        q.mEvent = event;
6980        q.mReceiver = receiver;
6981        q.mFlags = flags;
6982        return q;
6983    }
6984
6985    private void recycleQueuedInputEvent(QueuedInputEvent q) {
6986        q.mEvent = null;
6987        q.mReceiver = null;
6988
6989        if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
6990            mQueuedInputEventPoolSize += 1;
6991            q.mNext = mQueuedInputEventPool;
6992            mQueuedInputEventPool = q;
6993        }
6994    }
6995
6996    void enqueueInputEvent(InputEvent event) {
6997        enqueueInputEvent(event, null, 0, false);
6998    }
6999
7000    void enqueueInputEvent(InputEvent event,
7001            InputEventReceiver receiver, int flags, boolean processImmediately) {
7002        adjustInputEventForCompatibility(event);
7003        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
7004
7005        // Always enqueue the input event in order, regardless of its time stamp.
7006        // We do this because the application or the IME may inject key events
7007        // in response to touch events and we want to ensure that the injected keys
7008        // are processed in the order they were received and we cannot trust that
7009        // the time stamp of injected events are monotonic.
7010        QueuedInputEvent last = mPendingInputEventTail;
7011        if (last == null) {
7012            mPendingInputEventHead = q;
7013            mPendingInputEventTail = q;
7014        } else {
7015            last.mNext = q;
7016            mPendingInputEventTail = q;
7017        }
7018        mPendingInputEventCount += 1;
7019        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
7020                mPendingInputEventCount);
7021
7022        if (processImmediately) {
7023            doProcessInputEvents();
7024        } else {
7025            scheduleProcessInputEvents();
7026        }
7027    }
7028
7029    private void scheduleProcessInputEvents() {
7030        if (!mProcessInputEventsScheduled) {
7031            mProcessInputEventsScheduled = true;
7032            Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
7033            msg.setAsynchronous(true);
7034            mHandler.sendMessage(msg);
7035        }
7036    }
7037
7038    void doProcessInputEvents() {
7039        // Deliver all pending input events in the queue.
7040        while (mPendingInputEventHead != null) {
7041            QueuedInputEvent q = mPendingInputEventHead;
7042            mPendingInputEventHead = q.mNext;
7043            if (mPendingInputEventHead == null) {
7044                mPendingInputEventTail = null;
7045            }
7046            q.mNext = null;
7047
7048            mPendingInputEventCount -= 1;
7049            Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
7050                    mPendingInputEventCount);
7051
7052            long eventTime = q.mEvent.getEventTimeNano();
7053            long oldestEventTime = eventTime;
7054            if (q.mEvent instanceof MotionEvent) {
7055                MotionEvent me = (MotionEvent)q.mEvent;
7056                if (me.getHistorySize() > 0) {
7057                    oldestEventTime = me.getHistoricalEventTimeNano(0);
7058                }
7059            }
7060            mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
7061
7062            deliverInputEvent(q);
7063        }
7064
7065        // We are done processing all input events that we can process right now
7066        // so we can clear the pending flag immediately.
7067        if (mProcessInputEventsScheduled) {
7068            mProcessInputEventsScheduled = false;
7069            mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
7070        }
7071    }
7072
7073    private void deliverInputEvent(QueuedInputEvent q) {
7074        Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
7075                q.mEvent.getSequenceNumber());
7076        if (mInputEventConsistencyVerifier != null) {
7077            mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
7078        }
7079
7080        InputStage stage;
7081        if (q.shouldSendToSynthesizer()) {
7082            stage = mSyntheticInputStage;
7083        } else {
7084            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
7085        }
7086
7087        if (q.mEvent instanceof KeyEvent) {
7088            mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
7089        }
7090
7091        if (stage != null) {
7092            handleWindowFocusChanged();
7093            stage.deliver(q);
7094        } else {
7095            finishInputEvent(q);
7096        }
7097    }
7098
7099    private void finishInputEvent(QueuedInputEvent q) {
7100        Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
7101                q.mEvent.getSequenceNumber());
7102
7103        if (q.mReceiver != null) {
7104            boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
7105            q.mReceiver.finishInputEvent(q.mEvent, handled);
7106        } else {
7107            q.mEvent.recycleIfNeededAfterDispatch();
7108        }
7109
7110        recycleQueuedInputEvent(q);
7111    }
7112
7113    private void adjustInputEventForCompatibility(InputEvent e) {
7114        if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
7115            MotionEvent motion = (MotionEvent) e;
7116            final int mask =
7117                MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
7118            final int buttonState = motion.getButtonState();
7119            final int compatButtonState = (buttonState & mask) >> 4;
7120            if (compatButtonState != 0) {
7121                motion.setButtonState(buttonState | compatButtonState);
7122            }
7123        }
7124    }
7125
7126    static boolean isTerminalInputEvent(InputEvent event) {
7127        if (event instanceof KeyEvent) {
7128            final KeyEvent keyEvent = (KeyEvent)event;
7129            return keyEvent.getAction() == KeyEvent.ACTION_UP;
7130        } else {
7131            final MotionEvent motionEvent = (MotionEvent)event;
7132            final int action = motionEvent.getAction();
7133            return action == MotionEvent.ACTION_UP
7134                    || action == MotionEvent.ACTION_CANCEL
7135                    || action == MotionEvent.ACTION_HOVER_EXIT;
7136        }
7137    }
7138
7139    void scheduleConsumeBatchedInput() {
7140        if (!mConsumeBatchedInputScheduled) {
7141            mConsumeBatchedInputScheduled = true;
7142            mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
7143                    mConsumedBatchedInputRunnable, null);
7144        }
7145    }
7146
7147    void unscheduleConsumeBatchedInput() {
7148        if (mConsumeBatchedInputScheduled) {
7149            mConsumeBatchedInputScheduled = false;
7150            mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
7151                    mConsumedBatchedInputRunnable, null);
7152        }
7153    }
7154
7155    void scheduleConsumeBatchedInputImmediately() {
7156        if (!mConsumeBatchedInputImmediatelyScheduled) {
7157            unscheduleConsumeBatchedInput();
7158            mConsumeBatchedInputImmediatelyScheduled = true;
7159            mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
7160        }
7161    }
7162
7163    void doConsumeBatchedInput(long frameTimeNanos) {
7164        if (mConsumeBatchedInputScheduled) {
7165            mConsumeBatchedInputScheduled = false;
7166            if (mInputEventReceiver != null) {
7167                if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
7168                        && frameTimeNanos != -1) {
7169                    // If we consumed a batch here, we want to go ahead and schedule the
7170                    // consumption of batched input events on the next frame. Otherwise, we would
7171                    // wait until we have more input events pending and might get starved by other
7172                    // things occurring in the process. If the frame time is -1, however, then
7173                    // we're in a non-batching mode, so there's no need to schedule this.
7174                    scheduleConsumeBatchedInput();
7175                }
7176            }
7177            doProcessInputEvents();
7178        }
7179    }
7180
7181    final class TraversalRunnable implements Runnable {
7182        @Override
7183        public void run() {
7184            doTraversal();
7185        }
7186    }
7187    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
7188
7189    final class WindowInputEventReceiver extends InputEventReceiver {
7190        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
7191            super(inputChannel, looper);
7192        }
7193
7194        @Override
7195        public void onInputEvent(InputEvent event, int displayId) {
7196            enqueueInputEvent(event, this, 0, true);
7197        }
7198
7199        @Override
7200        public void onBatchedInputEventPending() {
7201            if (mUnbufferedInputDispatch) {
7202                super.onBatchedInputEventPending();
7203            } else {
7204                scheduleConsumeBatchedInput();
7205            }
7206        }
7207
7208        @Override
7209        public void dispose() {
7210            unscheduleConsumeBatchedInput();
7211            super.dispose();
7212        }
7213    }
7214    WindowInputEventReceiver mInputEventReceiver;
7215
7216    final class ConsumeBatchedInputRunnable implements Runnable {
7217        @Override
7218        public void run() {
7219            doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
7220        }
7221    }
7222    final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
7223            new ConsumeBatchedInputRunnable();
7224    boolean mConsumeBatchedInputScheduled;
7225
7226    final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
7227        @Override
7228        public void run() {
7229            doConsumeBatchedInput(-1);
7230        }
7231    }
7232    final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
7233            new ConsumeBatchedInputImmediatelyRunnable();
7234    boolean mConsumeBatchedInputImmediatelyScheduled;
7235
7236    final class InvalidateOnAnimationRunnable implements Runnable {
7237        private boolean mPosted;
7238        private final ArrayList<View> mViews = new ArrayList<View>();
7239        private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
7240                new ArrayList<AttachInfo.InvalidateInfo>();
7241        private View[] mTempViews;
7242        private AttachInfo.InvalidateInfo[] mTempViewRects;
7243
7244        public void addView(View view) {
7245            synchronized (this) {
7246                mViews.add(view);
7247                postIfNeededLocked();
7248            }
7249        }
7250
7251        public void addViewRect(AttachInfo.InvalidateInfo info) {
7252            synchronized (this) {
7253                mViewRects.add(info);
7254                postIfNeededLocked();
7255            }
7256        }
7257
7258        public void removeView(View view) {
7259            synchronized (this) {
7260                mViews.remove(view);
7261
7262                for (int i = mViewRects.size(); i-- > 0; ) {
7263                    AttachInfo.InvalidateInfo info = mViewRects.get(i);
7264                    if (info.target == view) {
7265                        mViewRects.remove(i);
7266                        info.recycle();
7267                    }
7268                }
7269
7270                if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
7271                    mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
7272                    mPosted = false;
7273                }
7274            }
7275        }
7276
7277        @Override
7278        public void run() {
7279            final int viewCount;
7280            final int viewRectCount;
7281            synchronized (this) {
7282                mPosted = false;
7283
7284                viewCount = mViews.size();
7285                if (viewCount != 0) {
7286                    mTempViews = mViews.toArray(mTempViews != null
7287                            ? mTempViews : new View[viewCount]);
7288                    mViews.clear();
7289                }
7290
7291                viewRectCount = mViewRects.size();
7292                if (viewRectCount != 0) {
7293                    mTempViewRects = mViewRects.toArray(mTempViewRects != null
7294                            ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
7295                    mViewRects.clear();
7296                }
7297            }
7298
7299            for (int i = 0; i < viewCount; i++) {
7300                mTempViews[i].invalidate();
7301                mTempViews[i] = null;
7302            }
7303
7304            for (int i = 0; i < viewRectCount; i++) {
7305                final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
7306                info.target.invalidate(info.left, info.top, info.right, info.bottom);
7307                info.recycle();
7308            }
7309        }
7310
7311        private void postIfNeededLocked() {
7312            if (!mPosted) {
7313                mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
7314                mPosted = true;
7315            }
7316        }
7317    }
7318    final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
7319            new InvalidateOnAnimationRunnable();
7320
7321    public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
7322        Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
7323        mHandler.sendMessageDelayed(msg, delayMilliseconds);
7324    }
7325
7326    public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
7327            long delayMilliseconds) {
7328        final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
7329        mHandler.sendMessageDelayed(msg, delayMilliseconds);
7330    }
7331
7332    public void dispatchInvalidateOnAnimation(View view) {
7333        mInvalidateOnAnimationRunnable.addView(view);
7334    }
7335
7336    public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
7337        mInvalidateOnAnimationRunnable.addViewRect(info);
7338    }
7339
7340    public void cancelInvalidate(View view) {
7341        mHandler.removeMessages(MSG_INVALIDATE, view);
7342        // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
7343        // them to the pool
7344        mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
7345        mInvalidateOnAnimationRunnable.removeView(view);
7346    }
7347
7348    public void dispatchInputEvent(InputEvent event) {
7349        dispatchInputEvent(event, null);
7350    }
7351
7352    public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
7353        SomeArgs args = SomeArgs.obtain();
7354        args.arg1 = event;
7355        args.arg2 = receiver;
7356        Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
7357        msg.setAsynchronous(true);
7358        mHandler.sendMessage(msg);
7359    }
7360
7361    public void synthesizeInputEvent(InputEvent event) {
7362        Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
7363        msg.setAsynchronous(true);
7364        mHandler.sendMessage(msg);
7365    }
7366
7367    public void dispatchKeyFromIme(KeyEvent event) {
7368        Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
7369        msg.setAsynchronous(true);
7370        mHandler.sendMessage(msg);
7371    }
7372
7373    public void dispatchKeyFromAutofill(KeyEvent event) {
7374        Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event);
7375        msg.setAsynchronous(true);
7376        mHandler.sendMessage(msg);
7377    }
7378
7379    /**
7380     * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
7381     *
7382     * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
7383     * passes in.
7384     */
7385    public void dispatchUnhandledInputEvent(InputEvent event) {
7386        if (event instanceof MotionEvent) {
7387            event = MotionEvent.obtain((MotionEvent) event);
7388        }
7389        synthesizeInputEvent(event);
7390    }
7391
7392    public void dispatchAppVisibility(boolean visible) {
7393        Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
7394        msg.arg1 = visible ? 1 : 0;
7395        mHandler.sendMessage(msg);
7396    }
7397
7398    public void dispatchGetNewSurface() {
7399        Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
7400        mHandler.sendMessage(msg);
7401    }
7402
7403    public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
7404        synchronized (this) {
7405            mWindowFocusChanged = true;
7406            mUpcomingWindowFocus = hasFocus;
7407            mUpcomingInTouchMode = inTouchMode;
7408        }
7409        Message msg = Message.obtain();
7410        msg.what = MSG_WINDOW_FOCUS_CHANGED;
7411        mHandler.sendMessage(msg);
7412    }
7413
7414    public void dispatchWindowShown() {
7415        mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
7416    }
7417
7418    public void dispatchCloseSystemDialogs(String reason) {
7419        Message msg = Message.obtain();
7420        msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
7421        msg.obj = reason;
7422        mHandler.sendMessage(msg);
7423    }
7424
7425    public void dispatchDragEvent(DragEvent event) {
7426        final int what;
7427        if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
7428            what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
7429            mHandler.removeMessages(what);
7430        } else {
7431            what = MSG_DISPATCH_DRAG_EVENT;
7432        }
7433        Message msg = mHandler.obtainMessage(what, event);
7434        mHandler.sendMessage(msg);
7435    }
7436
7437    public void updatePointerIcon(float x, float y) {
7438        final int what = MSG_UPDATE_POINTER_ICON;
7439        mHandler.removeMessages(what);
7440        final long now = SystemClock.uptimeMillis();
7441        final MotionEvent event = MotionEvent.obtain(
7442                0, now, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
7443        Message msg = mHandler.obtainMessage(what, event);
7444        mHandler.sendMessage(msg);
7445    }
7446
7447    public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
7448            int localValue, int localChanges) {
7449        SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
7450        args.seq = seq;
7451        args.globalVisibility = globalVisibility;
7452        args.localValue = localValue;
7453        args.localChanges = localChanges;
7454        mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
7455    }
7456
7457    public void dispatchCheckFocus() {
7458        if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
7459            // This will result in a call to checkFocus() below.
7460            mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
7461        }
7462    }
7463
7464    public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
7465        mHandler.obtainMessage(
7466                MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
7467    }
7468
7469    public void dispatchPointerCaptureChanged(boolean on) {
7470        final int what = MSG_POINTER_CAPTURE_CHANGED;
7471        mHandler.removeMessages(what);
7472        Message msg = mHandler.obtainMessage(what);
7473        msg.arg1 = on ? 1 : 0;
7474        mHandler.sendMessage(msg);
7475    }
7476
7477    /**
7478     * Post a callback to send a
7479     * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
7480     * This event is send at most once every
7481     * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
7482     */
7483    private void postSendWindowContentChangedCallback(View source, int changeType) {
7484        if (mSendWindowContentChangedAccessibilityEvent == null) {
7485            mSendWindowContentChangedAccessibilityEvent =
7486                new SendWindowContentChangedAccessibilityEvent();
7487        }
7488        mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
7489    }
7490
7491    /**
7492     * Remove a posted callback to send a
7493     * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
7494     */
7495    private void removeSendWindowContentChangedCallback() {
7496        if (mSendWindowContentChangedAccessibilityEvent != null) {
7497            mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
7498        }
7499    }
7500
7501    @Override
7502    public boolean showContextMenuForChild(View originalView) {
7503        return false;
7504    }
7505
7506    @Override
7507    public boolean showContextMenuForChild(View originalView, float x, float y) {
7508        return false;
7509    }
7510
7511    @Override
7512    public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
7513        return null;
7514    }
7515
7516    @Override
7517    public ActionMode startActionModeForChild(
7518            View originalView, ActionMode.Callback callback, int type) {
7519        return null;
7520    }
7521
7522    @Override
7523    public void createContextMenu(ContextMenu menu) {
7524    }
7525
7526    @Override
7527    public void childDrawableStateChanged(View child) {
7528    }
7529
7530    @Override
7531    public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
7532        if (mView == null || mStopped || mPausedForTransition) {
7533            return false;
7534        }
7535
7536        // Immediately flush pending content changed event (if any) to preserve event order
7537        if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
7538                && mSendWindowContentChangedAccessibilityEvent != null
7539                && mSendWindowContentChangedAccessibilityEvent.mSource != null) {
7540            mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun();
7541        }
7542
7543        // Intercept accessibility focus events fired by virtual nodes to keep
7544        // track of accessibility focus position in such nodes.
7545        final int eventType = event.getEventType();
7546        switch (eventType) {
7547            case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
7548                final long sourceNodeId = event.getSourceNodeId();
7549                final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
7550                        sourceNodeId);
7551                View source = mView.findViewByAccessibilityId(accessibilityViewId);
7552                if (source != null) {
7553                    AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
7554                    if (provider != null) {
7555                        final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
7556                                sourceNodeId);
7557                        final AccessibilityNodeInfo node;
7558                        node = provider.createAccessibilityNodeInfo(virtualNodeId);
7559                        setAccessibilityFocus(source, node);
7560                    }
7561                }
7562            } break;
7563            case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
7564                final long sourceNodeId = event.getSourceNodeId();
7565                final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
7566                        sourceNodeId);
7567                View source = mView.findViewByAccessibilityId(accessibilityViewId);
7568                if (source != null) {
7569                    AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
7570                    if (provider != null) {
7571                        setAccessibilityFocus(null, null);
7572                    }
7573                }
7574            } break;
7575
7576
7577            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
7578                handleWindowContentChangedEvent(event);
7579            } break;
7580        }
7581        mAccessibilityManager.sendAccessibilityEvent(event);
7582        return true;
7583    }
7584
7585    /**
7586     * Updates the focused virtual view, when necessary, in response to a
7587     * content changed event.
7588     * <p>
7589     * This is necessary to get updated bounds after a position change.
7590     *
7591     * @param event an accessibility event of type
7592     *              {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
7593     */
7594    private void handleWindowContentChangedEvent(AccessibilityEvent event) {
7595        final View focusedHost = mAccessibilityFocusedHost;
7596        if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
7597            // No virtual view focused, nothing to do here.
7598            return;
7599        }
7600
7601        final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
7602        if (provider == null) {
7603            // Error state: virtual view with no provider. Clear focus.
7604            mAccessibilityFocusedHost = null;
7605            mAccessibilityFocusedVirtualView = null;
7606            focusedHost.clearAccessibilityFocusNoCallbacks(0);
7607            return;
7608        }
7609
7610        // We only care about change types that may affect the bounds of the
7611        // focused virtual view.
7612        final int changes = event.getContentChangeTypes();
7613        if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
7614                && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
7615            return;
7616        }
7617
7618        final long eventSourceNodeId = event.getSourceNodeId();
7619        final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
7620
7621        // Search up the tree for subtree containment.
7622        boolean hostInSubtree = false;
7623        View root = mAccessibilityFocusedHost;
7624        while (root != null && !hostInSubtree) {
7625            if (changedViewId == root.getAccessibilityViewId()) {
7626                hostInSubtree = true;
7627            } else {
7628                final ViewParent parent = root.getParent();
7629                if (parent instanceof View) {
7630                    root = (View) parent;
7631                } else {
7632                    root = null;
7633                }
7634            }
7635        }
7636
7637        // We care only about changes in subtrees containing the host view.
7638        if (!hostInSubtree) {
7639            return;
7640        }
7641
7642        final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
7643        int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
7644
7645        // Refresh the node for the focused virtual view.
7646        final Rect oldBounds = mTempRect;
7647        mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
7648        mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
7649        if (mAccessibilityFocusedVirtualView == null) {
7650            // Error state: The node no longer exists. Clear focus.
7651            mAccessibilityFocusedHost = null;
7652            focusedHost.clearAccessibilityFocusNoCallbacks(0);
7653
7654            // This will probably fail, but try to keep the provider's internal
7655            // state consistent by clearing focus.
7656            provider.performAction(focusedChildId,
7657                    AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
7658            invalidateRectOnScreen(oldBounds);
7659        } else {
7660            // The node was refreshed, invalidate bounds if necessary.
7661            final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
7662            if (!oldBounds.equals(newBounds)) {
7663                oldBounds.union(newBounds);
7664                invalidateRectOnScreen(oldBounds);
7665            }
7666        }
7667    }
7668
7669    @Override
7670    public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
7671        postSendWindowContentChangedCallback(Preconditions.checkNotNull(source), changeType);
7672    }
7673
7674    @Override
7675    public boolean canResolveLayoutDirection() {
7676        return true;
7677    }
7678
7679    @Override
7680    public boolean isLayoutDirectionResolved() {
7681        return true;
7682    }
7683
7684    @Override
7685    public int getLayoutDirection() {
7686        return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
7687    }
7688
7689    @Override
7690    public boolean canResolveTextDirection() {
7691        return true;
7692    }
7693
7694    @Override
7695    public boolean isTextDirectionResolved() {
7696        return true;
7697    }
7698
7699    @Override
7700    public int getTextDirection() {
7701        return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
7702    }
7703
7704    @Override
7705    public boolean canResolveTextAlignment() {
7706        return true;
7707    }
7708
7709    @Override
7710    public boolean isTextAlignmentResolved() {
7711        return true;
7712    }
7713
7714    @Override
7715    public int getTextAlignment() {
7716        return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
7717    }
7718
7719    private View getCommonPredecessor(View first, View second) {
7720        if (mTempHashSet == null) {
7721            mTempHashSet = new HashSet<View>();
7722        }
7723        HashSet<View> seen = mTempHashSet;
7724        seen.clear();
7725        View firstCurrent = first;
7726        while (firstCurrent != null) {
7727            seen.add(firstCurrent);
7728            ViewParent firstCurrentParent = firstCurrent.mParent;
7729            if (firstCurrentParent instanceof View) {
7730                firstCurrent = (View) firstCurrentParent;
7731            } else {
7732                firstCurrent = null;
7733            }
7734        }
7735        View secondCurrent = second;
7736        while (secondCurrent != null) {
7737            if (seen.contains(secondCurrent)) {
7738                seen.clear();
7739                return secondCurrent;
7740            }
7741            ViewParent secondCurrentParent = secondCurrent.mParent;
7742            if (secondCurrentParent instanceof View) {
7743                secondCurrent = (View) secondCurrentParent;
7744            } else {
7745                secondCurrent = null;
7746            }
7747        }
7748        seen.clear();
7749        return null;
7750    }
7751
7752    void checkThread() {
7753        if (mThread != Thread.currentThread()) {
7754            throw new CalledFromWrongThreadException(
7755                    "Only the original thread that created a view hierarchy can touch its views.");
7756        }
7757    }
7758
7759    @Override
7760    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
7761        // ViewAncestor never intercepts touch event, so this can be a no-op
7762    }
7763
7764    @Override
7765    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
7766        if (rectangle == null) {
7767            return scrollToRectOrFocus(null, immediate);
7768        }
7769        rectangle.offset(child.getLeft() - child.getScrollX(),
7770                child.getTop() - child.getScrollY());
7771        final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
7772        mTempRect.set(rectangle);
7773        mTempRect.offset(0, -mCurScrollY);
7774        mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
7775        try {
7776            mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
7777        } catch (RemoteException re) {
7778            /* ignore */
7779        }
7780        return scrolled;
7781    }
7782
7783    @Override
7784    public void childHasTransientStateChanged(View child, boolean hasTransientState) {
7785        // Do nothing.
7786    }
7787
7788    @Override
7789    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
7790        return false;
7791    }
7792
7793    @Override
7794    public void onStopNestedScroll(View target) {
7795    }
7796
7797    @Override
7798    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
7799    }
7800
7801    @Override
7802    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
7803            int dxUnconsumed, int dyUnconsumed) {
7804    }
7805
7806    @Override
7807    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
7808    }
7809
7810    @Override
7811    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
7812        return false;
7813    }
7814
7815    @Override
7816    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
7817        return false;
7818    }
7819
7820    @Override
7821    public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
7822        return false;
7823    }
7824
7825
7826    private void reportNextDraw() {
7827        if (mReportNextDraw == false) {
7828            drawPending();
7829        }
7830        mReportNextDraw = true;
7831    }
7832
7833    /**
7834     * Force the window to report its next draw.
7835     * <p>
7836     * This method is only supposed to be used to speed up the interaction from SystemUI and window
7837     * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
7838     * unless you fully understand this interaction.
7839     * @hide
7840     */
7841    public void setReportNextDraw() {
7842        reportNextDraw();
7843        invalidate();
7844    }
7845
7846    void changeCanvasOpacity(boolean opaque) {
7847        Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
7848        if (mAttachInfo.mThreadedRenderer != null) {
7849            mAttachInfo.mThreadedRenderer.setOpaque(opaque);
7850        }
7851    }
7852
7853    /**
7854     * Dispatches a KeyEvent to all registered key fallback handlers.
7855     *
7856     * @param event
7857     * @return {@code true} if the event was handled, {@code false} otherwise.
7858     */
7859    public boolean dispatchUnhandledKeyEvent(KeyEvent event) {
7860        return mUnhandledKeyManager.dispatch(mView, event);
7861    }
7862
7863    class TakenSurfaceHolder extends BaseSurfaceHolder {
7864        @Override
7865        public boolean onAllowLockCanvas() {
7866            return mDrawingAllowed;
7867        }
7868
7869        @Override
7870        public void onRelayoutContainer() {
7871            // Not currently interesting -- from changing between fixed and layout size.
7872        }
7873
7874        @Override
7875        public void setFormat(int format) {
7876            ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
7877        }
7878
7879        @Override
7880        public void setType(int type) {
7881            ((RootViewSurfaceTaker)mView).setSurfaceType(type);
7882        }
7883
7884        @Override
7885        public void onUpdateSurface() {
7886            // We take care of format and type changes on our own.
7887            throw new IllegalStateException("Shouldn't be here");
7888        }
7889
7890        @Override
7891        public boolean isCreating() {
7892            return mIsCreating;
7893        }
7894
7895        @Override
7896        public void setFixedSize(int width, int height) {
7897            throw new UnsupportedOperationException(
7898                    "Currently only support sizing from layout");
7899        }
7900
7901        @Override
7902        public void setKeepScreenOn(boolean screenOn) {
7903            ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
7904        }
7905    }
7906
7907    static class W extends IWindow.Stub {
7908        private final WeakReference<ViewRootImpl> mViewAncestor;
7909        private final IWindowSession mWindowSession;
7910
7911        W(ViewRootImpl viewAncestor) {
7912            mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
7913            mWindowSession = viewAncestor.mWindowSession;
7914        }
7915
7916        @Override
7917        public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
7918                Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
7919                MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
7920                boolean alwaysConsumeNavBar, int displayId,
7921                DisplayCutout.ParcelableWrapper displayCutout) {
7922            final ViewRootImpl viewAncestor = mViewAncestor.get();
7923            if (viewAncestor != null) {
7924                viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
7925                        visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
7926                        backDropFrame, forceLayout, alwaysConsumeNavBar, displayId, displayCutout);
7927            }
7928        }
7929
7930        @Override
7931        public void moved(int newX, int newY) {
7932            final ViewRootImpl viewAncestor = mViewAncestor.get();
7933            if (viewAncestor != null) {
7934                viewAncestor.dispatchMoved(newX, newY);
7935            }
7936        }
7937
7938        @Override
7939        public void dispatchAppVisibility(boolean visible) {
7940            final ViewRootImpl viewAncestor = mViewAncestor.get();
7941            if (viewAncestor != null) {
7942                viewAncestor.dispatchAppVisibility(visible);
7943            }
7944        }
7945
7946        @Override
7947        public void dispatchGetNewSurface() {
7948            final ViewRootImpl viewAncestor = mViewAncestor.get();
7949            if (viewAncestor != null) {
7950                viewAncestor.dispatchGetNewSurface();
7951            }
7952        }
7953
7954        @Override
7955        public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
7956            final ViewRootImpl viewAncestor = mViewAncestor.get();
7957            if (viewAncestor != null) {
7958                viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
7959            }
7960        }
7961
7962        private static int checkCallingPermission(String permission) {
7963            try {
7964                return ActivityManager.getService().checkPermission(
7965                        permission, Binder.getCallingPid(), Binder.getCallingUid());
7966            } catch (RemoteException e) {
7967                return PackageManager.PERMISSION_DENIED;
7968            }
7969        }
7970
7971        @Override
7972        public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
7973            final ViewRootImpl viewAncestor = mViewAncestor.get();
7974            if (viewAncestor != null) {
7975                final View view = viewAncestor.mView;
7976                if (view != null) {
7977                    if (checkCallingPermission(Manifest.permission.DUMP) !=
7978                            PackageManager.PERMISSION_GRANTED) {
7979                        throw new SecurityException("Insufficient permissions to invoke"
7980                                + " executeCommand() from pid=" + Binder.getCallingPid()
7981                                + ", uid=" + Binder.getCallingUid());
7982                    }
7983
7984                    OutputStream clientStream = null;
7985                    try {
7986                        clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
7987                        ViewDebug.dispatchCommand(view, command, parameters, clientStream);
7988                    } catch (IOException e) {
7989                        e.printStackTrace();
7990                    } finally {
7991                        if (clientStream != null) {
7992                            try {
7993                                clientStream.close();
7994                            } catch (IOException e) {
7995                                e.printStackTrace();
7996                            }
7997                        }
7998                    }
7999                }
8000            }
8001        }
8002
8003        @Override
8004        public void closeSystemDialogs(String reason) {
8005            final ViewRootImpl viewAncestor = mViewAncestor.get();
8006            if (viewAncestor != null) {
8007                viewAncestor.dispatchCloseSystemDialogs(reason);
8008            }
8009        }
8010
8011        @Override
8012        public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
8013                boolean sync) {
8014            if (sync) {
8015                try {
8016                    mWindowSession.wallpaperOffsetsComplete(asBinder());
8017                } catch (RemoteException e) {
8018                }
8019            }
8020        }
8021
8022        @Override
8023        public void dispatchWallpaperCommand(String action, int x, int y,
8024                int z, Bundle extras, boolean sync) {
8025            if (sync) {
8026                try {
8027                    mWindowSession.wallpaperCommandComplete(asBinder(), null);
8028                } catch (RemoteException e) {
8029                }
8030            }
8031        }
8032
8033        /* Drag/drop */
8034        @Override
8035        public void dispatchDragEvent(DragEvent event) {
8036            final ViewRootImpl viewAncestor = mViewAncestor.get();
8037            if (viewAncestor != null) {
8038                viewAncestor.dispatchDragEvent(event);
8039            }
8040        }
8041
8042        @Override
8043        public void updatePointerIcon(float x, float y) {
8044            final ViewRootImpl viewAncestor = mViewAncestor.get();
8045            if (viewAncestor != null) {
8046                viewAncestor.updatePointerIcon(x, y);
8047            }
8048        }
8049
8050        @Override
8051        public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
8052                int localValue, int localChanges) {
8053            final ViewRootImpl viewAncestor = mViewAncestor.get();
8054            if (viewAncestor != null) {
8055                viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
8056                        localValue, localChanges);
8057            }
8058        }
8059
8060        @Override
8061        public void dispatchWindowShown() {
8062            final ViewRootImpl viewAncestor = mViewAncestor.get();
8063            if (viewAncestor != null) {
8064                viewAncestor.dispatchWindowShown();
8065            }
8066        }
8067
8068        @Override
8069        public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
8070            ViewRootImpl viewAncestor = mViewAncestor.get();
8071            if (viewAncestor != null) {
8072                viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
8073            }
8074        }
8075
8076        @Override
8077        public void dispatchPointerCaptureChanged(boolean hasCapture) {
8078            final ViewRootImpl viewAncestor = mViewAncestor.get();
8079            if (viewAncestor != null) {
8080                viewAncestor.dispatchPointerCaptureChanged(hasCapture);
8081            }
8082        }
8083
8084    }
8085
8086    public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
8087        public CalledFromWrongThreadException(String msg) {
8088            super(msg);
8089        }
8090    }
8091
8092    static HandlerActionQueue getRunQueue() {
8093        HandlerActionQueue rq = sRunQueues.get();
8094        if (rq != null) {
8095            return rq;
8096        }
8097        rq = new HandlerActionQueue();
8098        sRunQueues.set(rq);
8099        return rq;
8100    }
8101
8102    /**
8103     * Start a drag resizing which will inform all listeners that a window resize is taking place.
8104     */
8105    private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
8106            Rect stableInsets, int resizeMode) {
8107        if (!mDragResizing) {
8108            mDragResizing = true;
8109            if (mUseMTRenderer) {
8110                for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8111                    mWindowCallbacks.get(i).onWindowDragResizeStart(
8112                            initialBounds, fullscreen, systemInsets, stableInsets, resizeMode);
8113                }
8114            }
8115            mFullRedrawNeeded = true;
8116        }
8117    }
8118
8119    /**
8120     * End a drag resize which will inform all listeners that a window resize has ended.
8121     */
8122    private void endDragResizing() {
8123        if (mDragResizing) {
8124            mDragResizing = false;
8125            if (mUseMTRenderer) {
8126                for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8127                    mWindowCallbacks.get(i).onWindowDragResizeEnd();
8128                }
8129            }
8130            mFullRedrawNeeded = true;
8131        }
8132    }
8133
8134    private boolean updateContentDrawBounds() {
8135        boolean updated = false;
8136        if (mUseMTRenderer) {
8137            for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8138                updated |=
8139                        mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left,
8140                                mWindowAttributes.surfaceInsets.top, mWidth, mHeight);
8141            }
8142        }
8143        return updated | (mDragResizing && mReportNextDraw);
8144    }
8145
8146    private void requestDrawWindow() {
8147        if (!mUseMTRenderer) {
8148            return;
8149        }
8150        mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
8151        for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8152            mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
8153        }
8154    }
8155
8156    /**
8157     * Tells this instance that its corresponding activity has just relaunched. In this case, we
8158     * need to force a relayout of the window to make sure we get the correct bounds from window
8159     * manager.
8160     */
8161    public void reportActivityRelaunched() {
8162        mActivityRelaunched = true;
8163    }
8164
8165    /**
8166     * Class for managing the accessibility interaction connection
8167     * based on the global accessibility state.
8168     */
8169    final class AccessibilityInteractionConnectionManager
8170            implements AccessibilityStateChangeListener {
8171        @Override
8172        public void onAccessibilityStateChanged(boolean enabled) {
8173            if (enabled) {
8174                ensureConnection();
8175                if (mAttachInfo.mHasWindowFocus && (mView != null)) {
8176                    mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
8177                    View focusedView = mView.findFocus();
8178                    if (focusedView != null && focusedView != mView) {
8179                        focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
8180                    }
8181                }
8182            } else {
8183                ensureNoConnection();
8184                mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
8185            }
8186        }
8187
8188        public void ensureConnection() {
8189            final boolean registered = mAttachInfo.mAccessibilityWindowId
8190                    != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
8191            if (!registered) {
8192                mAttachInfo.mAccessibilityWindowId =
8193                        mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
8194                                mContext.getPackageName(),
8195                                new AccessibilityInteractionConnection(ViewRootImpl.this));
8196            }
8197        }
8198
8199        public void ensureNoConnection() {
8200            final boolean registered = mAttachInfo.mAccessibilityWindowId
8201                    != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
8202            if (registered) {
8203                mAttachInfo.mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
8204                mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
8205            }
8206        }
8207    }
8208
8209    final class HighContrastTextManager implements HighTextContrastChangeListener {
8210        HighContrastTextManager() {
8211            ThreadedRenderer.setHighContrastText(mAccessibilityManager.isHighTextContrastEnabled());
8212        }
8213        @Override
8214        public void onHighTextContrastStateChanged(boolean enabled) {
8215            ThreadedRenderer.setHighContrastText(enabled);
8216
8217            // Destroy Displaylists so they can be recreated with high contrast recordings
8218            destroyHardwareResources();
8219
8220            // Schedule redraw, which will rerecord + redraw all text
8221            invalidate();
8222        }
8223    }
8224
8225    /**
8226     * This class is an interface this ViewAncestor provides to the
8227     * AccessibilityManagerService to the latter can interact with
8228     * the view hierarchy in this ViewAncestor.
8229     */
8230    static final class AccessibilityInteractionConnection
8231            extends IAccessibilityInteractionConnection.Stub {
8232        private final WeakReference<ViewRootImpl> mViewRootImpl;
8233
8234        AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
8235            mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
8236        }
8237
8238        @Override
8239        public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
8240                Region interactiveRegion, int interactionId,
8241                IAccessibilityInteractionConnectionCallback callback, int flags,
8242                int interrogatingPid, long interrogatingTid, MagnificationSpec spec, Bundle args) {
8243            ViewRootImpl viewRootImpl = mViewRootImpl.get();
8244            if (viewRootImpl != null && viewRootImpl.mView != null) {
8245                viewRootImpl.getAccessibilityInteractionController()
8246                    .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
8247                            interactiveRegion, interactionId, callback, flags, interrogatingPid,
8248                            interrogatingTid, spec, args);
8249            } else {
8250                // We cannot make the call and notify the caller so it does not wait.
8251                try {
8252                    callback.setFindAccessibilityNodeInfosResult(null, interactionId);
8253                } catch (RemoteException re) {
8254                    /* best effort - ignore */
8255                }
8256            }
8257        }
8258
8259        @Override
8260        public void performAccessibilityAction(long accessibilityNodeId, int action,
8261                Bundle arguments, int interactionId,
8262                IAccessibilityInteractionConnectionCallback callback, int flags,
8263                int interrogatingPid, long interrogatingTid) {
8264            ViewRootImpl viewRootImpl = mViewRootImpl.get();
8265            if (viewRootImpl != null && viewRootImpl.mView != null) {
8266                viewRootImpl.getAccessibilityInteractionController()
8267                    .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
8268                            interactionId, callback, flags, interrogatingPid, interrogatingTid);
8269            } else {
8270                // We cannot make the call and notify the caller so it does not wait.
8271                try {
8272                    callback.setPerformAccessibilityActionResult(false, interactionId);
8273                } catch (RemoteException re) {
8274                    /* best effort - ignore */
8275                }
8276            }
8277        }
8278
8279        @Override
8280        public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
8281                String viewId, Region interactiveRegion, int interactionId,
8282                IAccessibilityInteractionConnectionCallback callback, int flags,
8283                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
8284            ViewRootImpl viewRootImpl = mViewRootImpl.get();
8285            if (viewRootImpl != null && viewRootImpl.mView != null) {
8286                viewRootImpl.getAccessibilityInteractionController()
8287                    .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
8288                            viewId, interactiveRegion, interactionId, callback, flags,
8289                            interrogatingPid, interrogatingTid, spec);
8290            } else {
8291                // We cannot make the call and notify the caller so it does not wait.
8292                try {
8293                    callback.setFindAccessibilityNodeInfoResult(null, interactionId);
8294                } catch (RemoteException re) {
8295                    /* best effort - ignore */
8296                }
8297            }
8298        }
8299
8300        @Override
8301        public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
8302                Region interactiveRegion, int interactionId,
8303                IAccessibilityInteractionConnectionCallback callback, int flags,
8304                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
8305            ViewRootImpl viewRootImpl = mViewRootImpl.get();
8306            if (viewRootImpl != null && viewRootImpl.mView != null) {
8307                viewRootImpl.getAccessibilityInteractionController()
8308                    .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
8309                            interactiveRegion, interactionId, callback, flags, interrogatingPid,
8310                            interrogatingTid, spec);
8311            } else {
8312                // We cannot make the call and notify the caller so it does not wait.
8313                try {
8314                    callback.setFindAccessibilityNodeInfosResult(null, interactionId);
8315                } catch (RemoteException re) {
8316                    /* best effort - ignore */
8317                }
8318            }
8319        }
8320
8321        @Override
8322        public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
8323                int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
8324                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
8325            ViewRootImpl viewRootImpl = mViewRootImpl.get();
8326            if (viewRootImpl != null && viewRootImpl.mView != null) {
8327                viewRootImpl.getAccessibilityInteractionController()
8328                    .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
8329                            interactionId, callback, flags, interrogatingPid, interrogatingTid,
8330                            spec);
8331            } else {
8332                // We cannot make the call and notify the caller so it does not wait.
8333                try {
8334                    callback.setFindAccessibilityNodeInfoResult(null, interactionId);
8335                } catch (RemoteException re) {
8336                    /* best effort - ignore */
8337                }
8338            }
8339        }
8340
8341        @Override
8342        public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
8343                int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
8344                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
8345            ViewRootImpl viewRootImpl = mViewRootImpl.get();
8346            if (viewRootImpl != null && viewRootImpl.mView != null) {
8347                viewRootImpl.getAccessibilityInteractionController()
8348                    .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
8349                            interactionId, callback, flags, interrogatingPid, interrogatingTid,
8350                            spec);
8351            } else {
8352                // We cannot make the call and notify the caller so it does not wait.
8353                try {
8354                    callback.setFindAccessibilityNodeInfoResult(null, interactionId);
8355                } catch (RemoteException re) {
8356                    /* best effort - ignore */
8357                }
8358            }
8359        }
8360    }
8361
8362    private class SendWindowContentChangedAccessibilityEvent implements Runnable {
8363        private int mChangeTypes = 0;
8364
8365        public View mSource;
8366        public long mLastEventTimeMillis;
8367        /**
8368         * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace
8369         * of the original {@link #runOrPost} call instead of one for sending the delayed event
8370         * from a looper.
8371         */
8372        public StackTraceElement[] mOrigin;
8373
8374        @Override
8375        public void run() {
8376            // Protect against re-entrant code and attempt to do the right thing in the case that
8377            // we're multithreaded.
8378            View source = mSource;
8379            mSource = null;
8380            if (source == null) {
8381                Log.e(TAG, "Accessibility content change has no source");
8382                return;
8383            }
8384            // The accessibility may be turned off while we were waiting so check again.
8385            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
8386                mLastEventTimeMillis = SystemClock.uptimeMillis();
8387                AccessibilityEvent event = AccessibilityEvent.obtain();
8388                event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
8389                event.setContentChangeTypes(mChangeTypes);
8390                if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin;
8391                source.sendAccessibilityEventUnchecked(event);
8392            } else {
8393                mLastEventTimeMillis = 0;
8394            }
8395            // In any case reset to initial state.
8396            source.resetSubtreeAccessibilityStateChanged();
8397            mChangeTypes = 0;
8398            if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null;
8399        }
8400
8401        public void runOrPost(View source, int changeType) {
8402            if (mHandler.getLooper() != Looper.myLooper()) {
8403                CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the "
8404                        + "original thread that created a view hierarchy can touch its views.");
8405                // TODO: Throw the exception
8406                Log.e(TAG, "Accessibility content change on non-UI thread. Future Android "
8407                        + "versions will throw an exception.", e);
8408                // Attempt to recover. This code does not eliminate the thread safety issue, but
8409                // it should force any issues to happen near the above log.
8410                mHandler.removeCallbacks(this);
8411                if (mSource != null) {
8412                    // Dispatch whatever was pending. It's still possible that the runnable started
8413                    // just before we removed the callbacks, and bad things will happen, but at
8414                    // least they should happen very close to the logged error.
8415                    run();
8416                }
8417            }
8418            if (mSource != null) {
8419                // If there is no common predecessor, then mSource points to
8420                // a removed view, hence in this case always prefer the source.
8421                View predecessor = getCommonPredecessor(mSource, source);
8422                if (predecessor != null) {
8423                    predecessor = predecessor.getSelfOrParentImportantForA11y();
8424                }
8425                mSource = (predecessor != null) ? predecessor : source;
8426                mChangeTypes |= changeType;
8427                return;
8428            }
8429            mSource = source;
8430            mChangeTypes = changeType;
8431            if (AccessibilityEvent.DEBUG_ORIGIN) {
8432                mOrigin = Thread.currentThread().getStackTrace();
8433            }
8434            final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
8435            final long minEventIntevalMillis =
8436                    ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
8437            if (timeSinceLastMillis >= minEventIntevalMillis) {
8438                removeCallbacksAndRun();
8439            } else {
8440                mHandler.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
8441            }
8442        }
8443
8444        public void removeCallbacksAndRun() {
8445            mHandler.removeCallbacks(this);
8446            run();
8447        }
8448    }
8449
8450    private static class UnhandledKeyManager {
8451        // This is used to ensure that unhandled events are only dispatched once. We attempt
8452        // to dispatch more than once in order to achieve a certain order. Specifically, if we
8453        // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should
8454        // be dispatched after the view hierarchy, but before the Callback. However, if we aren't
8455        // in an activity, we still want unhandled keys to be dispatched.
8456        private boolean mDispatched = true;
8457
8458        // Keeps track of which Views have unhandled key focus for which keys. This doesn't
8459        // include modifiers.
8460        private final SparseArray<WeakReference<View>> mCapturedKeys = new SparseArray<>();
8461
8462        // The current receiver. This value is transient and used between the pre-dispatch and
8463        // pre-view phase to ensure that other input-stages don't interfere with tracking.
8464        private WeakReference<View> mCurrentReceiver = null;
8465
8466        boolean dispatch(View root, KeyEvent event) {
8467            if (mDispatched) {
8468                return false;
8469            }
8470            View consumer;
8471            try {
8472                Trace.traceBegin(Trace.TRACE_TAG_VIEW, "UnhandledKeyEvent dispatch");
8473                mDispatched = true;
8474
8475                consumer = root.dispatchUnhandledKeyEvent(event);
8476
8477                // If an unhandled listener handles one, then keep track of it so that the
8478                // consuming view is first to receive its repeats and release as well.
8479                if (event.getAction() == KeyEvent.ACTION_DOWN) {
8480                    int keycode = event.getKeyCode();
8481                    if (consumer != null && !KeyEvent.isModifierKey(keycode)) {
8482                        mCapturedKeys.put(keycode, new WeakReference<>(consumer));
8483                    }
8484                }
8485            } finally {
8486                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
8487            }
8488            return consumer != null;
8489        }
8490
8491        /**
8492         * Called before the event gets dispatched to anything
8493         */
8494        void preDispatch(KeyEvent event) {
8495            // Always clean-up 'up' events since it's possible for earlier dispatch stages to
8496            // consume them without consuming the corresponding 'down' event.
8497            mCurrentReceiver = null;
8498            if (event.getAction() == KeyEvent.ACTION_UP) {
8499                int idx = mCapturedKeys.indexOfKey(event.getKeyCode());
8500                if (idx >= 0) {
8501                    mCurrentReceiver = mCapturedKeys.valueAt(idx);
8502                    mCapturedKeys.removeAt(idx);
8503                }
8504            }
8505        }
8506
8507        /**
8508         * Called before the event gets dispatched to the view hierarchy
8509         * @return {@code true} if an unhandled handler has focus and consumed the event
8510         */
8511        boolean preViewDispatch(KeyEvent event) {
8512            mDispatched = false;
8513            if (mCurrentReceiver == null) {
8514                mCurrentReceiver = mCapturedKeys.get(event.getKeyCode());
8515            }
8516            if (mCurrentReceiver != null) {
8517                View target = mCurrentReceiver.get();
8518                if (event.getAction() == KeyEvent.ACTION_UP) {
8519                    mCurrentReceiver = null;
8520                }
8521                if (target != null && target.isAttachedToWindow()) {
8522                    target.onUnhandledKeyEvent(event);
8523                }
8524                // consume anyways so that we don't feed uncaptured key events to other views
8525                return true;
8526            }
8527            return false;
8528        }
8529    }
8530}
8531