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