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