OSDN Git Service

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