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