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