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