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