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