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