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