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.media.AudioManager;
     39 import android.os.Binder;
     40 import android.os.Bundle;
     41 import android.os.Debug;
     42 import android.os.Handler;
     43 import android.os.LatencyTimer;
     44 import android.os.Looper;
     45 import android.os.Message;
     46 import android.os.ParcelFileDescriptor;
     47 import android.os.Process;
     48 import android.os.RemoteException;
     49 import android.os.SystemClock;
     50 import android.os.SystemProperties;
     51 import android.util.AndroidRuntimeException;
     52 import android.util.DisplayMetrics;
     53 import android.util.EventLog;
     54 import android.util.Log;
     55 import android.util.Pool;
     56 import android.util.Poolable;
     57 import android.util.PoolableManager;
     58 import android.util.Pools;
     59 import android.util.Slog;
     60 import android.util.SparseArray;
     61 import android.util.TypedValue;
     62 import android.view.View.MeasureSpec;
     63 import android.view.accessibility.AccessibilityEvent;
     64 import android.view.accessibility.AccessibilityInteractionClient;
     65 import android.view.accessibility.AccessibilityManager;
     66 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
     67 import android.view.accessibility.AccessibilityNodeInfo;
     68 import android.view.accessibility.IAccessibilityInteractionConnection;
     69 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
     70 import android.view.animation.AccelerateDecelerateInterpolator;
     71 import android.view.animation.Interpolator;
     72 import android.view.inputmethod.InputConnection;
     73 import android.view.inputmethod.InputMethodManager;
     74 import android.widget.Scroller;
     75 
     76 import com.android.internal.policy.PolicyManager;
     77 import com.android.internal.view.BaseSurfaceHolder;
     78 import com.android.internal.view.IInputMethodCallback;
     79 import com.android.internal.view.IInputMethodSession;
     80 import com.android.internal.view.RootViewSurfaceTaker;
     81 
     82 import java.io.IOException;
     83 import java.io.OutputStream;
     84 import java.io.PrintWriter;
     85 import java.lang.ref.WeakReference;
     86 import java.util.ArrayList;
     87 import java.util.List;
     88 
     89 /**
     90  * The top of a view hierarchy, implementing the needed protocol between View
     91  * and the WindowManager.  This is for the most part an internal implementation
     92  * detail of {@link WindowManagerImpl}.
     93  *
     94  * {@hide}
     95  */
     96 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
     97 public final class ViewRootImpl extends Handler implements ViewParent,
     98         View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
     99     private static final String TAG = "ViewRootImpl";
    100     private static final boolean DBG = false;
    101     private static final boolean LOCAL_LOGV = false;
    102     /** @noinspection PointlessBooleanExpression*/
    103     private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
    104     private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
    105     private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
    106     private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
    107     private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
    108     private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
    109     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
    110     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
    111     private static final boolean DEBUG_FPS = false;
    112     private static final boolean WATCH_POINTER = false;
    113 
    114     /**
    115      * Set this system property to true to force the view hierarchy to render
    116      * at 60 Hz. This can be used to measure the potential framerate.
    117      */
    118     private static final String PROPERTY_PROFILE_RENDERING = "viewancestor.profile_rendering";
    119 
    120     private static final boolean MEASURE_LATENCY = false;
    121     private static LatencyTimer lt;
    122 
    123     /**
    124      * Maximum time we allow the user to roll the trackball enough to generate
    125      * a key event, before resetting the counters.
    126      */
    127     static final int MAX_TRACKBALL_DELAY = 250;
    128 
    129     static IWindowSession sWindowSession;
    130 
    131     static final Object mStaticInit = new Object();
    132     static boolean mInitialized = false;
    133 
    134     static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
    135 
    136     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
    137     static boolean sFirstDrawComplete = false;
    138 
    139     static final ArrayList<ComponentCallbacks> sConfigCallbacks
    140             = new ArrayList<ComponentCallbacks>();
    141 
    142     long mLastTrackballTime = 0;
    143     final TrackballAxis mTrackballAxisX = new TrackballAxis();
    144     final TrackballAxis mTrackballAxisY = new TrackballAxis();
    145 
    146     int mLastJoystickXDirection;
    147     int mLastJoystickYDirection;
    148     int mLastJoystickXKeyCode;
    149     int mLastJoystickYKeyCode;
    150 
    151     final int[] mTmpLocation = new int[2];
    152 
    153     final TypedValue mTmpValue = new TypedValue();
    154 
    155     final InputMethodCallback mInputMethodCallback;
    156     final SparseArray<Object> mPendingEvents = new SparseArray<Object>();
    157     int mPendingEventSeq = 0;
    158 
    159     final Thread mThread;
    160 
    161     final WindowLeaked mLocation;
    162 
    163     final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
    164 
    165     final W mWindow;
    166 
    167     final int mTargetSdkVersion;
    168 
    169     int mSeq;
    170 
    171     View mView;
    172     View mFocusedView;
    173     View mRealFocusedView;  // this is not set to null in touch mode
    174     int mViewVisibility;
    175     boolean mAppVisible = true;
    176     int mOrigWindowType = -1;
    177 
    178     // Set to true if the owner of this window is in the stopped state,
    179     // so the window should no longer be active.
    180     boolean mStopped = false;
    181 
    182     boolean mLastInCompatMode = false;
    183 
    184     SurfaceHolder.Callback2 mSurfaceHolderCallback;
    185     BaseSurfaceHolder mSurfaceHolder;
    186     boolean mIsCreating;
    187     boolean mDrawingAllowed;
    188 
    189     final Region mTransparentRegion;
    190     final Region mPreviousTransparentRegion;
    191 
    192     int mWidth;
    193     int mHeight;
    194     Rect mDirty;
    195     final Rect mCurrentDirty = new Rect();
    196     final Rect mPreviousDirty = new Rect();
    197     boolean mIsAnimating;
    198 
    199     CompatibilityInfo.Translator mTranslator;
    200 
    201     final View.AttachInfo mAttachInfo;
    202     InputChannel mInputChannel;
    203     InputQueue.Callback mInputQueueCallback;
    204     InputQueue mInputQueue;
    205     FallbackEventHandler mFallbackEventHandler;
    206 
    207     final Rect mTempRect; // used in the transaction to not thrash the heap.
    208     final Rect mVisRect; // used to retrieve visible rect of focused view.
    209 
    210     boolean mTraversalScheduled;
    211     long mLastTraversalFinishedTimeNanos;
    212     long mLastDrawDurationNanos;
    213     boolean mWillDrawSoon;
    214     boolean mLayoutRequested;
    215     boolean mFirst;
    216     boolean mReportNextDraw;
    217     boolean mFullRedrawNeeded;
    218     boolean mNewSurfaceNeeded;
    219     boolean mHasHadWindowFocus;
    220     boolean mLastWasImTarget;
    221 
    222     boolean mWindowAttributesChanged = false;
    223     int mWindowAttributesChangesFlag = 0;
    224 
    225     // These can be accessed by any thread, must be protected with a lock.
    226     // Surface can never be reassigned or cleared (use Surface.clear()).
    227     private final Surface mSurface = new Surface();
    228 
    229     boolean mAdded;
    230     boolean mAddedTouchMode;
    231 
    232     CompatibilityInfoHolder mCompatibilityInfo;
    233 
    234     /*package*/ int mAddNesting;
    235 
    236     // These are accessed by multiple threads.
    237     final Rect mWinFrame; // frame given by window manager.
    238 
    239     final Rect mPendingVisibleInsets = new Rect();
    240     final Rect mPendingContentInsets = new Rect();
    241     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
    242             = new ViewTreeObserver.InternalInsetsInfo();
    243 
    244     final Configuration mLastConfiguration = new Configuration();
    245     final Configuration mPendingConfiguration = new Configuration();
    246 
    247     class ResizedInfo {
    248         Rect coveredInsets;
    249         Rect visibleInsets;
    250         Configuration newConfig;
    251     }
    252 
    253     boolean mScrollMayChange;
    254     int mSoftInputMode;
    255     View mLastScrolledFocus;
    256     int mScrollY;
    257     int mCurScrollY;
    258     Scroller mScroller;
    259     HardwareLayer mResizeBuffer;
    260     long mResizeBufferStartTime;
    261     int mResizeBufferDuration;
    262     static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
    263     private ArrayList<LayoutTransition> mPendingTransitions;
    264 
    265     final ViewConfiguration mViewConfiguration;
    266 
    267     /* Drag/drop */
    268     ClipDescription mDragDescription;
    269     View mCurrentDragView;
    270     volatile Object mLocalDragState;
    271     final PointF mDragPoint = new PointF();
    272     final PointF mLastTouchPoint = new PointF();
    273 
    274     private boolean mProfileRendering;
    275     private Thread mRenderProfiler;
    276     private volatile boolean mRenderProfilingEnabled;
    277 
    278     // Variables to track frames per second, enabled via DEBUG_FPS flag
    279     private long mFpsStartTime = -1;
    280     private long mFpsPrevTime = -1;
    281     private int mFpsNumFrames;
    282 
    283     /**
    284      * see {@link #playSoundEffect(int)}
    285      */
    286     AudioManager mAudioManager;
    287 
    288     final AccessibilityManager mAccessibilityManager;
    289 
    290     AccessibilityInteractionController mAccessibilityInteractionContrtoller;
    291 
    292     AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
    293 
    294     SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
    295 
    296     private final int mDensity;
    297 
    298     /**
    299      * Consistency verifier for debugging purposes.
    300      */
    301     protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
    302             InputEventConsistencyVerifier.isInstrumentationEnabled() ?
    303                     new InputEventConsistencyVerifier(this, 0) : null;
    304 
    305     public static IWindowSession getWindowSession(Looper mainLooper) {
    306         synchronized (mStaticInit) {
    307             if (!mInitialized) {
    308                 try {
    309                     InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
    310                     sWindowSession = Display.getWindowManager().openSession(
    311                             imm.getClient(), imm.getInputContext());
    312                     mInitialized = true;
    313                 } catch (RemoteException e) {
    314                 }
    315             }
    316             return sWindowSession;
    317         }
    318     }
    319 
    320     static final class SystemUiVisibilityInfo {
    321         int seq;
    322         int globalVisibility;
    323         int localValue;
    324         int localChanges;
    325     }
    326 
    327     public ViewRootImpl(Context context) {
    328         super();
    329 
    330         if (MEASURE_LATENCY) {
    331             if (lt == null) {
    332                 lt = new LatencyTimer(100, 1000);
    333             }
    334         }
    335 
    336         // Initialize the statics when this class is first instantiated. This is
    337         // done here instead of in the static block because Zygote does not
    338         // allow the spawning of threads.
    339         getWindowSession(context.getMainLooper());
    340 
    341         mThread = Thread.currentThread();
    342         mLocation = new WindowLeaked(null);
    343         mLocation.fillInStackTrace();
    344         mWidth = -1;
    345         mHeight = -1;
    346         mDirty = new Rect();
    347         mTempRect = new Rect();
    348         mVisRect = new Rect();
    349         mWinFrame = new Rect();
    350         mWindow = new W(this);
    351         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
    352         mInputMethodCallback = new InputMethodCallback(this);
    353         mViewVisibility = View.GONE;
    354         mTransparentRegion = new Region();
    355         mPreviousTransparentRegion = new Region();
    356         mFirst = true; // true for the first time the view is added
    357         mAdded = false;
    358         mAccessibilityManager = AccessibilityManager.getInstance(context);
    359         mAccessibilityInteractionConnectionManager =
    360             new AccessibilityInteractionConnectionManager();
    361         mAccessibilityManager.addAccessibilityStateChangeListener(
    362                 mAccessibilityInteractionConnectionManager);
    363         mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
    364         mViewConfiguration = ViewConfiguration.get(context);
    365         mDensity = context.getResources().getDisplayMetrics().densityDpi;
    366         mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
    367         mProfileRendering = Boolean.parseBoolean(
    368                 SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false"));
    369     }
    370 
    371     public static void addFirstDrawHandler(Runnable callback) {
    372         synchronized (sFirstDrawHandlers) {
    373             if (!sFirstDrawComplete) {
    374                 sFirstDrawHandlers.add(callback);
    375             }
    376         }
    377     }
    378 
    379     public static void addConfigCallback(ComponentCallbacks callback) {
    380         synchronized (sConfigCallbacks) {
    381             sConfigCallbacks.add(callback);
    382         }
    383     }
    384 
    385     // FIXME for perf testing only
    386     private boolean mProfile = false;
    387 
    388     /**
    389      * Call this to profile the next traversal call.
    390      * FIXME for perf testing only. Remove eventually
    391      */
    392     public void profile() {
    393         mProfile = true;
    394     }
    395 
    396     /**
    397      * Indicates whether we are in touch mode. Calling this method triggers an IPC
    398      * call and should be avoided whenever possible.
    399      *
    400      * @return True, if the device is in touch mode, false otherwise.
    401      *
    402      * @hide
    403      */
    404     static boolean isInTouchMode() {
    405         if (mInitialized) {
    406             try {
    407                 return sWindowSession.getInTouchMode();
    408             } catch (RemoteException e) {
    409             }
    410         }
    411         return false;
    412     }
    413 
    414     /**
    415      * We have one child
    416      */
    417     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    418         synchronized (this) {
    419             if (mView == null) {
    420                 mView = view;
    421                 mFallbackEventHandler.setView(view);
    422                 mWindowAttributes.copyFrom(attrs);
    423                 attrs = mWindowAttributes;
    424 
    425                 if (view instanceof RootViewSurfaceTaker) {
    426                     mSurfaceHolderCallback =
    427                             ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
    428                     if (mSurfaceHolderCallback != null) {
    429                         mSurfaceHolder = new TakenSurfaceHolder();
    430                         mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
    431                     }
    432                 }
    433 
    434                 // If the application owns the surface, don't enable hardware acceleration
    435                 if (mSurfaceHolder == null) {
    436                     enableHardwareAcceleration(attrs);
    437                 }
    438 
    439                 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
    440                 mTranslator = compatibilityInfo.getTranslator();
    441 
    442                 if (mTranslator != null) {
    443                     mSurface.setCompatibilityTranslator(mTranslator);
    444                 }
    445 
    446                 boolean restore = false;
    447                 if (mTranslator != null) {
    448                     restore = true;
    449                     attrs.backup();
    450                     mTranslator.translateWindowLayout(attrs);
    451                 }
    452                 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
    453 
    454                 if (!compatibilityInfo.supportsScreen()) {
    455                     attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
    456                     mLastInCompatMode = true;
    457                 }
    458 
    459                 mSoftInputMode = attrs.softInputMode;
    460                 mWindowAttributesChanged = true;
    461                 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
    462                 mAttachInfo.mRootView = view;
    463                 mAttachInfo.mScalingRequired = mTranslator != null;
    464                 mAttachInfo.mApplicationScale =
    465                         mTranslator == null ? 1.0f : mTranslator.applicationScale;
    466                 if (panelParentView != null) {
    467                     mAttachInfo.mPanelParentWindowToken
    468                             = panelParentView.getApplicationWindowToken();
    469                 }
    470                 mAdded = true;
    471                 int res; /* = WindowManagerImpl.ADD_OKAY; */
    472 
    473                 // Schedule the first layout -before- adding to the window
    474                 // manager, to make sure we do the relayout before receiving
    475                 // any other events from the system.
    476                 requestLayout();
    477                 if ((mWindowAttributes.inputFeatures
    478                         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
    479                     mInputChannel = new InputChannel();
    480                 }
    481                 try {
    482                     mOrigWindowType = mWindowAttributes.type;
    483                     res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
    484                             getHostVisibility(), mAttachInfo.mContentInsets,
    485                             mInputChannel);
    486                 } catch (RemoteException e) {
    487                     mAdded = false;
    488                     mView = null;
    489                     mAttachInfo.mRootView = null;
    490                     mInputChannel = null;
    491                     mFallbackEventHandler.setView(null);
    492                     unscheduleTraversals();
    493                     throw new RuntimeException("Adding window failed", e);
    494                 } finally {
    495                     if (restore) {
    496                         attrs.restore();
    497                     }
    498                 }
    499 
    500                 if (mTranslator != null) {
    501                     mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
    502                 }
    503                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
    504                 mPendingVisibleInsets.set(0, 0, 0, 0);
    505                 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
    506                 if (res < WindowManagerImpl.ADD_OKAY) {
    507                     mView = null;
    508                     mAttachInfo.mRootView = null;
    509                     mAdded = false;
    510                     mFallbackEventHandler.setView(null);
    511                     unscheduleTraversals();
    512                     switch (res) {
    513                         case WindowManagerImpl.ADD_BAD_APP_TOKEN:
    514                         case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
    515                             throw new WindowManagerImpl.BadTokenException(
    516                                 "Unable to add window -- token " + attrs.token
    517                                 + " is not valid; is your activity running?");
    518                         case WindowManagerImpl.ADD_NOT_APP_TOKEN:
    519                             throw new WindowManagerImpl.BadTokenException(
    520                                 "Unable to add window -- token " + attrs.token
    521                                 + " is not for an application");
    522                         case WindowManagerImpl.ADD_APP_EXITING:
    523                             throw new WindowManagerImpl.BadTokenException(
    524                                 "Unable to add window -- app for token " + attrs.token
    525                                 + " is exiting");
    526                         case WindowManagerImpl.ADD_DUPLICATE_ADD:
    527                             throw new WindowManagerImpl.BadTokenException(
    528                                 "Unable to add window -- window " + mWindow
    529                                 + " has already been added");
    530                         case WindowManagerImpl.ADD_STARTING_NOT_NEEDED:
    531                             // Silently ignore -- we would have just removed it
    532                             // right away, anyway.
    533                             return;
    534                         case WindowManagerImpl.ADD_MULTIPLE_SINGLETON:
    535                             throw new WindowManagerImpl.BadTokenException(
    536                                 "Unable to add window " + mWindow +
    537                                 " -- another window of this type already exists");
    538                         case WindowManagerImpl.ADD_PERMISSION_DENIED:
    539                             throw new WindowManagerImpl.BadTokenException(
    540                                 "Unable to add window " + mWindow +
    541                                 " -- permission denied for this window type");
    542                     }
    543                     throw new RuntimeException(
    544                         "Unable to add window -- unknown error code " + res);
    545                 }
    546 
    547                 if (view instanceof RootViewSurfaceTaker) {
    548                     mInputQueueCallback =
    549                         ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
    550                 }
    551                 if (mInputChannel != null) {
    552                     if (mInputQueueCallback != null) {
    553                         mInputQueue = new InputQueue(mInputChannel);
    554                         mInputQueueCallback.onInputQueueCreated(mInputQueue);
    555                     } else {
    556                         InputQueue.registerInputChannel(mInputChannel, mInputHandler,
    557                                 Looper.myQueue());
    558                     }
    559                 }
    560 
    561                 view.assignParent(this);
    562                 mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0;
    563                 mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0;
    564 
    565                 if (mAccessibilityManager.isEnabled()) {
    566                     mAccessibilityInteractionConnectionManager.ensureConnection();
    567                 }
    568             }
    569         }
    570     }
    571 
    572     private void destroyHardwareResources() {
    573         if (mAttachInfo.mHardwareRenderer != null) {
    574             if (mAttachInfo.mHardwareRenderer.isEnabled()) {
    575                 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
    576             }
    577             mAttachInfo.mHardwareRenderer.destroy(false);
    578         }
    579     }
    580 
    581     void destroyHardwareLayers() {
    582         if (mThread != Thread.currentThread()) {
    583             if (mAttachInfo.mHardwareRenderer != null &&
    584                     mAttachInfo.mHardwareRenderer.isEnabled()) {
    585                 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
    586             }
    587         } else {
    588             if (mAttachInfo.mHardwareRenderer != null &&
    589                     mAttachInfo.mHardwareRenderer.isEnabled()) {
    590                 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
    591             }
    592         }
    593     }
    594 
    595     private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
    596         mAttachInfo.mHardwareAccelerated = false;
    597         mAttachInfo.mHardwareAccelerationRequested = false;
    598 
    599         // Try to enable hardware acceleration if requested
    600         final boolean hardwareAccelerated =
    601                 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
    602 
    603         if (hardwareAccelerated) {
    604             if (!HardwareRenderer.isAvailable()) {
    605                 return;
    606             }
    607 
    608             // Persistent processes (including the system) should not do
    609             // accelerated rendering on low-end devices.  In that case,
    610             // sRendererDisabled will be set.  In addition, the system process
    611             // itself should never do accelerated rendering.  In that case, both
    612             // sRendererDisabled and sSystemRendererDisabled are set.  When
    613             // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
    614             // can be used by code on the system process to escape that and enable
    615             // HW accelerated drawing.  (This is basically for the lock screen.)
    616 
    617             final boolean fakeHwAccelerated = (attrs.privateFlags &
    618                     WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
    619             final boolean forceHwAccelerated = (attrs.privateFlags &
    620                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
    621 
    622             if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
    623                     && forceHwAccelerated)) {
    624                 // Don't enable hardware acceleration when we're not on the main thread
    625                 if (!HardwareRenderer.sSystemRendererDisabled
    626                         && Looper.getMainLooper() != Looper.myLooper()) {
    627                     Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
    628                             + "acceleration outside of the main thread, aborting");
    629                     return;
    630                 }
    631 
    632                 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
    633                 if (mAttachInfo.mHardwareRenderer != null) {
    634                     mAttachInfo.mHardwareRenderer.destroy(true);
    635                 }
    636                 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
    637                 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
    638                         = mAttachInfo.mHardwareRenderer != null;
    639             } else if (fakeHwAccelerated) {
    640                 // The window had wanted to use hardware acceleration, but this
    641                 // is not allowed in its process.  By setting this flag, it can
    642                 // still render as if it was accelerated.  This is basically for
    643                 // the preview windows the window manager shows for launching
    644                 // applications, so they will look more like the app being launched.
    645                 mAttachInfo.mHardwareAccelerationRequested = true;
    646             }
    647         }
    648     }
    649 
    650     public View getView() {
    651         return mView;
    652     }
    653 
    654     final WindowLeaked getLocation() {
    655         return mLocation;
    656     }
    657 
    658     void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
    659         synchronized (this) {
    660             int oldSoftInputMode = mWindowAttributes.softInputMode;
    661             // preserve compatible window flag if exists.
    662             int compatibleWindowFlag =
    663                 mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
    664             mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
    665             mWindowAttributes.flags |= compatibleWindowFlag;
    666 
    667             if (newView) {
    668                 mSoftInputMode = attrs.softInputMode;
    669                 requestLayout();
    670             }
    671             // Don't lose the mode we last auto-computed.
    672             if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
    673                     == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
    674                 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
    675                         & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
    676                         | (oldSoftInputMode
    677                                 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
    678             }
    679             mWindowAttributesChanged = true;
    680             scheduleTraversals();
    681         }
    682     }
    683 
    684     void handleAppVisibility(boolean visible) {
    685         if (mAppVisible != visible) {
    686             mAppVisible = visible;
    687             scheduleTraversals();
    688         }
    689     }
    690 
    691     void handleGetNewSurface() {
    692         mNewSurfaceNeeded = true;
    693         mFullRedrawNeeded = true;
    694         scheduleTraversals();
    695     }
    696 
    697     /**
    698      * {@inheritDoc}
    699      */
    700     public void requestLayout() {
    701         checkThread();
    702         mLayoutRequested = true;
    703         scheduleTraversals();
    704     }
    705 
    706     /**
    707      * {@inheritDoc}
    708      */
    709     public boolean isLayoutRequested() {
    710         return mLayoutRequested;
    711     }
    712 
    713     public void invalidateChild(View child, Rect dirty) {
    714         checkThread();
    715         if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
    716         if (dirty == null) {
    717             // Fast invalidation for GL-enabled applications; GL must redraw everything
    718             invalidate();
    719             return;
    720         }
    721         if (mCurScrollY != 0 || mTranslator != null) {
    722             mTempRect.set(dirty);
    723             dirty = mTempRect;
    724             if (mCurScrollY != 0) {
    725                dirty.offset(0, -mCurScrollY);
    726             }
    727             if (mTranslator != null) {
    728                 mTranslator.translateRectInAppWindowToScreen(dirty);
    729             }
    730             if (mAttachInfo.mScalingRequired) {
    731                 dirty.inset(-1, -1);
    732             }
    733         }
    734         if (!mDirty.isEmpty() && !mDirty.contains(dirty)) {
    735             mAttachInfo.mSetIgnoreDirtyState = true;
    736             mAttachInfo.mIgnoreDirtyState = true;
    737         }
    738         mDirty.union(dirty);
    739         if (!mWillDrawSoon) {
    740             scheduleTraversals();
    741         }
    742     }
    743 
    744     void invalidate() {
    745         mDirty.set(0, 0, mWidth, mHeight);
    746         scheduleTraversals();
    747     }
    748 
    749     void setStopped(boolean stopped) {
    750         if (mStopped != stopped) {
    751             mStopped = stopped;
    752             if (!stopped) {
    753                 scheduleTraversals();
    754             }
    755         }
    756     }
    757 
    758     public ViewParent getParent() {
    759         return null;
    760     }
    761 
    762     public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
    763         invalidateChild(null, dirty);
    764         return null;
    765     }
    766 
    767     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
    768         if (child != mView) {
    769             throw new RuntimeException("child is not mine, honest!");
    770         }
    771         // Note: don't apply scroll offset, because we want to know its
    772         // visibility in the virtual canvas being given to the view hierarchy.
    773         return r.intersect(0, 0, mWidth, mHeight);
    774     }
    775 
    776     public void bringChildToFront(View child) {
    777     }
    778 
    779     public void scheduleTraversals() {
    780         if (!mTraversalScheduled) {
    781             mTraversalScheduled = true;
    782 
    783             //noinspection ConstantConditions
    784             if (ViewDebug.DEBUG_LATENCY && mLastTraversalFinishedTimeNanos != 0) {
    785                 final long now = System.nanoTime();
    786                 Log.d(TAG, "Latency: Scheduled traversal, it has been "
    787                         + ((now - mLastTraversalFinishedTimeNanos) * 0.000001f)
    788                         + "ms since the last traversal finished.");
    789             }
    790 
    791             sendEmptyMessage(DO_TRAVERSAL);
    792         }
    793     }
    794 
    795     public void unscheduleTraversals() {
    796         if (mTraversalScheduled) {
    797             mTraversalScheduled = false;
    798             removeMessages(DO_TRAVERSAL);
    799         }
    800     }
    801 
    802     int getHostVisibility() {
    803         return mAppVisible ? mView.getVisibility() : View.GONE;
    804     }
    805 
    806     void disposeResizeBuffer() {
    807         if (mResizeBuffer != null) {
    808             mResizeBuffer.destroy();
    809             mResizeBuffer = null;
    810         }
    811     }
    812 
    813     /**
    814      * Add LayoutTransition to the list of transitions to be started in the next traversal.
    815      * This list will be cleared after the transitions on the list are start()'ed. These
    816      * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
    817      * happens during the layout phase of traversal, which we want to complete before any of the
    818      * animations are started (because those animations may side-effect properties that layout
    819      * depends upon, like the bounding rectangles of the affected views). So we add the transition
    820      * to the list and it is started just prior to starting the drawing phase of traversal.
    821      *
    822      * @param transition The LayoutTransition to be started on the next traversal.
    823      *
    824      * @hide
    825      */
    826     public void requestTransitionStart(LayoutTransition transition) {
    827         if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
    828             if (mPendingTransitions == null) {
    829                  mPendingTransitions = new ArrayList<LayoutTransition>();
    830             }
    831             mPendingTransitions.add(transition);
    832         }
    833     }
    834 
    835     private void performTraversals() {
    836         // cache mView since it is used so much below...
    837         final View host = mView;
    838 
    839         if (DBG) {
    840             System.out.println("======================================");
    841             System.out.println("performTraversals");
    842             host.debug();
    843         }
    844 
    845         if (host == null || !mAdded)
    846             return;
    847 
    848         mTraversalScheduled = false;
    849         mWillDrawSoon = true;
    850         boolean windowSizeMayChange = false;
    851         boolean fullRedrawNeeded = mFullRedrawNeeded;
    852         boolean newSurface = false;
    853         boolean surfaceChanged = false;
    854         WindowManager.LayoutParams lp = mWindowAttributes;
    855 
    856         int desiredWindowWidth;
    857         int desiredWindowHeight;
    858         int childWidthMeasureSpec;
    859         int childHeightMeasureSpec;
    860 
    861         final View.AttachInfo attachInfo = mAttachInfo;
    862 
    863         final int viewVisibility = getHostVisibility();
    864         boolean viewVisibilityChanged = mViewVisibility != viewVisibility
    865                 || mNewSurfaceNeeded;
    866 
    867         WindowManager.LayoutParams params = null;
    868         int windowAttributesChanges = 0;
    869         if (mWindowAttributesChanged) {
    870             mWindowAttributesChanged = false;
    871             surfaceChanged = true;
    872             params = lp;
    873             windowAttributesChanges = mWindowAttributesChangesFlag;
    874         }
    875         CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
    876         if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
    877             params = lp;
    878             fullRedrawNeeded = true;
    879             mLayoutRequested = true;
    880             if (mLastInCompatMode) {
    881                 params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
    882                 mLastInCompatMode = false;
    883             } else {
    884                 params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
    885                 mLastInCompatMode = true;
    886             }
    887         }
    888 
    889         mWindowAttributesChangesFlag = 0;
    890 
    891         Rect frame = mWinFrame;
    892         if (mFirst) {
    893             fullRedrawNeeded = true;
    894             mLayoutRequested = true;
    895 
    896             if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
    897                 // NOTE -- system code, won't try to do compat mode.
    898                 Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
    899                 Point size = new Point();
    900                 disp.getRealSize(size);
    901                 desiredWindowWidth = size.x;
    902                 desiredWindowHeight = size.y;
    903             } else {
    904                 DisplayMetrics packageMetrics =
    905                     mView.getContext().getResources().getDisplayMetrics();
    906                 desiredWindowWidth = packageMetrics.widthPixels;
    907                 desiredWindowHeight = packageMetrics.heightPixels;
    908             }
    909 
    910             // For the very first time, tell the view hierarchy that it
    911             // is attached to the window.  Note that at this point the surface
    912             // object is not initialized to its backing store, but soon it
    913             // will be (assuming the window is visible).
    914             attachInfo.mSurface = mSurface;
    915             // We used to use the following condition to choose 32 bits drawing caches:
    916             // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
    917             // However, windows are now always 32 bits by default, so choose 32 bits
    918             attachInfo.mUse32BitDrawingCache = true;
    919             attachInfo.mHasWindowFocus = false;
    920             attachInfo.mWindowVisibility = viewVisibility;
    921             attachInfo.mRecomputeGlobalAttributes = false;
    922             attachInfo.mKeepScreenOn = false;
    923             attachInfo.mSystemUiVisibility = 0;
    924             viewVisibilityChanged = false;
    925             mLastConfiguration.setTo(host.getResources().getConfiguration());
    926             host.dispatchAttachedToWindow(attachInfo, 0);
    927             //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
    928 
    929             host.fitSystemWindows(mAttachInfo.mContentInsets);
    930 
    931         } else {
    932             desiredWindowWidth = frame.width();
    933             desiredWindowHeight = frame.height();
    934             if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
    935                 if (DEBUG_ORIENTATION) Log.v(TAG,
    936                         "View " + host + " resized to: " + frame);
    937                 fullRedrawNeeded = true;
    938                 mLayoutRequested = true;
    939                 windowSizeMayChange = true;
    940             }
    941         }
    942 
    943         if (viewVisibilityChanged) {
    944             attachInfo.mWindowVisibility = viewVisibility;
    945             host.dispatchWindowVisibilityChanged(viewVisibility);
    946             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
    947                 destroyHardwareResources();
    948             }
    949             if (viewVisibility == View.GONE) {
    950                 // After making a window gone, we will count it as being
    951                 // shown for the first time the next time it gets focus.
    952                 mHasHadWindowFocus = false;
    953             }
    954         }
    955 
    956         boolean insetsChanged = false;
    957 
    958         if (mLayoutRequested && !mStopped) {
    959             // Execute enqueued actions on every layout in case a view that was detached
    960             // enqueued an action after being detached
    961             getRunQueue().executeActions(attachInfo.mHandler);
    962 
    963             final Resources res = mView.getContext().getResources();
    964 
    965             if (mFirst) {
    966                 // make sure touch mode code executes by setting cached value
    967                 // to opposite of the added touch mode.
    968                 mAttachInfo.mInTouchMode = !mAddedTouchMode;
    969                 ensureTouchModeLocally(mAddedTouchMode);
    970             } else {
    971                 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
    972                     insetsChanged = true;
    973                 }
    974                 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
    975                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
    976                     if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
    977                             + mAttachInfo.mVisibleInsets);
    978                 }
    979                 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
    980                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
    981                     windowSizeMayChange = true;
    982 
    983                     if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
    984                         // NOTE -- system code, won't try to do compat mode.
    985                         Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
    986                         Point size = new Point();
    987                         disp.getRealSize(size);
    988                         desiredWindowWidth = size.x;
    989                         desiredWindowHeight = size.y;
    990                     } else {
    991                         DisplayMetrics packageMetrics = res.getDisplayMetrics();
    992                         desiredWindowWidth = packageMetrics.widthPixels;
    993                         desiredWindowHeight = packageMetrics.heightPixels;
    994                     }
    995                 }
    996             }
    997 
    998             // Ask host how big it wants to be
    999             if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
   1000                     "Measuring " + host + " in display " + desiredWindowWidth
   1001                     + "x" + desiredWindowHeight + "...");
   1002 
   1003             boolean goodMeasure = false;
   1004             if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
   1005                 // On large screens, we don't want to allow dialogs to just
   1006                 // stretch to fill the entire width of the screen to display
   1007                 // one line of text.  First try doing the layout at a smaller
   1008                 // size to see if it will fit.
   1009                 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
   1010                 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
   1011                 int baseSize = 0;
   1012                 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
   1013                     baseSize = (int)mTmpValue.getDimension(packageMetrics);
   1014                 }
   1015                 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
   1016                 if (baseSize != 0 && desiredWindowWidth > baseSize) {
   1017                     childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
   1018                     childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
   1019                     host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   1020                     if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
   1021                             + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
   1022                     if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
   1023                         goodMeasure = true;
   1024                     } else {
   1025                         // Didn't fit in that size... try expanding a bit.
   1026                         baseSize = (baseSize+desiredWindowWidth)/2;
   1027                         if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
   1028                                 + baseSize);
   1029                         childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
   1030                         host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   1031                         if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
   1032                                 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
   1033                         if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
   1034                             if (DEBUG_DIALOG) Log.v(TAG, "Good!");
   1035                             goodMeasure = true;
   1036                         }
   1037                     }
   1038                 }
   1039             }
   1040 
   1041             if (!goodMeasure) {
   1042                 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
   1043                 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
   1044                 host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   1045                 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
   1046                     windowSizeMayChange = true;
   1047                 }
   1048             }
   1049 
   1050             if (DBG) {
   1051                 System.out.println("======================================");
   1052                 System.out.println("performTraversals -- after measure");
   1053                 host.debug();
   1054             }
   1055         }
   1056 
   1057         if (attachInfo.mRecomputeGlobalAttributes && host.mAttachInfo != null) {
   1058             //Log.i(TAG, "Computing view hierarchy attributes!");
   1059             attachInfo.mRecomputeGlobalAttributes = false;
   1060             boolean oldScreenOn = attachInfo.mKeepScreenOn;
   1061             int oldVis = attachInfo.mSystemUiVisibility;
   1062             boolean oldHasSystemUiListeners = attachInfo.mHasSystemUiListeners;
   1063             attachInfo.mKeepScreenOn = false;
   1064             attachInfo.mSystemUiVisibility = 0;
   1065             attachInfo.mHasSystemUiListeners = false;
   1066             host.dispatchCollectViewAttributes(0);
   1067             if (attachInfo.mKeepScreenOn != oldScreenOn
   1068                     || attachInfo.mSystemUiVisibility != oldVis
   1069                     || attachInfo.mHasSystemUiListeners != oldHasSystemUiListeners) {
   1070                 params = lp;
   1071             }
   1072         }
   1073         if (attachInfo.mForceReportNewAttributes) {
   1074             attachInfo.mForceReportNewAttributes = false;
   1075             params = lp;
   1076         }
   1077 
   1078         if (mFirst || attachInfo.mViewVisibilityChanged) {
   1079             attachInfo.mViewVisibilityChanged = false;
   1080             int resizeMode = mSoftInputMode &
   1081                     WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
   1082             // If we are in auto resize mode, then we need to determine
   1083             // what mode to use now.
   1084             if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
   1085                 final int N = attachInfo.mScrollContainers.size();
   1086                 for (int i=0; i<N; i++) {
   1087                     if (attachInfo.mScrollContainers.get(i).isShown()) {
   1088                         resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
   1089                     }
   1090                 }
   1091                 if (resizeMode == 0) {
   1092                     resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
   1093                 }
   1094                 if ((lp.softInputMode &
   1095                         WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
   1096                     lp.softInputMode = (lp.softInputMode &
   1097                             ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
   1098                             resizeMode;
   1099                     params = lp;
   1100                 }
   1101             }
   1102         }
   1103 
   1104         if (params != null && (host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
   1105             if (!PixelFormat.formatHasAlpha(params.format)) {
   1106                 params.format = PixelFormat.TRANSLUCENT;
   1107             }
   1108         }
   1109 
   1110         boolean windowShouldResize = mLayoutRequested && windowSizeMayChange
   1111             && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
   1112                 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
   1113                         frame.width() < desiredWindowWidth && frame.width() != mWidth)
   1114                 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
   1115                         frame.height() < desiredWindowHeight && frame.height() != mHeight));
   1116 
   1117         final boolean computesInternalInsets =
   1118                 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
   1119 
   1120         boolean insetsPending = false;
   1121         int relayoutResult = 0;
   1122 
   1123         if (mFirst || windowShouldResize || insetsChanged ||
   1124                 viewVisibilityChanged || params != null) {
   1125 
   1126             if (viewVisibility == View.VISIBLE) {
   1127                 // If this window is giving internal insets to the window
   1128                 // manager, and it is being added or changing its visibility,
   1129                 // then we want to first give the window manager "fake"
   1130                 // insets to cause it to effectively ignore the content of
   1131                 // the window during layout.  This avoids it briefly causing
   1132                 // other windows to resize/move based on the raw frame of the
   1133                 // window, waiting until we can finish laying out this window
   1134                 // and get back to the window manager with the ultimately
   1135                 // computed insets.
   1136                 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
   1137             }
   1138 
   1139             if (mSurfaceHolder != null) {
   1140                 mSurfaceHolder.mSurfaceLock.lock();
   1141                 mDrawingAllowed = true;
   1142             }
   1143 
   1144             boolean hwInitialized = false;
   1145             boolean contentInsetsChanged = false;
   1146             boolean visibleInsetsChanged;
   1147             boolean hadSurface = mSurface.isValid();
   1148 
   1149             try {
   1150                 int fl = 0;
   1151                 if (params != null) {
   1152                     fl = params.flags;
   1153                     if (attachInfo.mKeepScreenOn) {
   1154                         params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
   1155                     }
   1156                     params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
   1157                     params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
   1158                 }
   1159                 if (DEBUG_LAYOUT) {
   1160                     Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
   1161                             host.getMeasuredHeight() + ", params=" + params);
   1162                 }
   1163 
   1164                 final int surfaceGenerationId = mSurface.getGenerationId();
   1165                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
   1166 
   1167                 if (params != null) {
   1168                     params.flags = fl;
   1169                 }
   1170 
   1171                 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
   1172                         + " content=" + mPendingContentInsets.toShortString()
   1173                         + " visible=" + mPendingVisibleInsets.toShortString()
   1174                         + " surface=" + mSurface);
   1175 
   1176                 if (mPendingConfiguration.seq != 0) {
   1177                     if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
   1178                             + mPendingConfiguration);
   1179                     updateConfiguration(mPendingConfiguration, !mFirst);
   1180                     mPendingConfiguration.seq = 0;
   1181                 }
   1182 
   1183                 contentInsetsChanged = !mPendingContentInsets.equals(
   1184                         mAttachInfo.mContentInsets);
   1185                 visibleInsetsChanged = !mPendingVisibleInsets.equals(
   1186                         mAttachInfo.mVisibleInsets);
   1187                 if (contentInsetsChanged) {
   1188                     if (mWidth > 0 && mHeight > 0 &&
   1189                             mSurface != null && mSurface.isValid() &&
   1190                             !mAttachInfo.mTurnOffWindowResizeAnim &&
   1191                             mAttachInfo.mHardwareRenderer != null &&
   1192                             mAttachInfo.mHardwareRenderer.isEnabled() &&
   1193                             mAttachInfo.mHardwareRenderer.validate() &&
   1194                             lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
   1195 
   1196                         disposeResizeBuffer();
   1197 
   1198                         boolean completed = false;
   1199                         HardwareCanvas canvas = null;
   1200                         try {
   1201                             if (mResizeBuffer == null) {
   1202                                 mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
   1203                                         mWidth, mHeight, false);
   1204                             } else if (mResizeBuffer.getWidth() != mWidth ||
   1205                                     mResizeBuffer.getHeight() != mHeight) {
   1206                                 mResizeBuffer.resize(mWidth, mHeight);
   1207                             }
   1208                             canvas = mResizeBuffer.start(mAttachInfo.mHardwareCanvas);
   1209                             canvas.setViewport(mWidth, mHeight);
   1210                             canvas.onPreDraw(null);
   1211                             final int restoreCount = canvas.save();
   1212 
   1213                             canvas.drawColor(0xff000000, PorterDuff.Mode.SRC);
   1214 
   1215                             int yoff;
   1216                             final boolean scrolling = mScroller != null
   1217                                     && mScroller.computeScrollOffset();
   1218                             if (scrolling) {
   1219                                 yoff = mScroller.getCurrY();
   1220                                 mScroller.abortAnimation();
   1221                             } else {
   1222                                 yoff = mScrollY;
   1223                             }
   1224 
   1225                             canvas.translate(0, -yoff);
   1226                             if (mTranslator != null) {
   1227                                 mTranslator.translateCanvas(canvas);
   1228                             }
   1229 
   1230                             mView.draw(canvas);
   1231 
   1232                             mResizeBufferStartTime = SystemClock.uptimeMillis();
   1233                             mResizeBufferDuration = mView.getResources().getInteger(
   1234                                     com.android.internal.R.integer.config_mediumAnimTime);
   1235                             completed = true;
   1236 
   1237                             canvas.restoreToCount(restoreCount);
   1238                         } catch (OutOfMemoryError e) {
   1239                             Log.w(TAG, "Not enough memory for content change anim buffer", e);
   1240                         } finally {
   1241                             if (canvas != null) {
   1242                                 canvas.onPostDraw();
   1243                             }
   1244                             if (mResizeBuffer != null) {
   1245                                 mResizeBuffer.end(mAttachInfo.mHardwareCanvas);
   1246                                 if (!completed) {
   1247                                     mResizeBuffer.destroy();
   1248                                     mResizeBuffer = null;
   1249                                 }
   1250                             }
   1251                         }
   1252                     }
   1253                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
   1254                     host.fitSystemWindows(mAttachInfo.mContentInsets);
   1255                     if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
   1256                             + mAttachInfo.mContentInsets);
   1257                 }
   1258                 if (visibleInsetsChanged) {
   1259                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
   1260                     if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
   1261                             + mAttachInfo.mVisibleInsets);
   1262                 }
   1263 
   1264                 if (!hadSurface) {
   1265                     if (mSurface.isValid()) {
   1266                         // If we are creating a new surface, then we need to
   1267                         // completely redraw it.  Also, when we get to the
   1268                         // point of drawing it we will hold off and schedule
   1269                         // a new traversal instead.  This is so we can tell the
   1270                         // window manager about all of the windows being displayed
   1271                         // before actually drawing them, so it can display then
   1272                         // all at once.
   1273                         newSurface = true;
   1274                         fullRedrawNeeded = true;
   1275                         mPreviousTransparentRegion.setEmpty();
   1276 
   1277                         if (mAttachInfo.mHardwareRenderer != null) {
   1278                             try {
   1279                                 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(mHolder);
   1280                             } catch (Surface.OutOfResourcesException e) {
   1281                                 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
   1282                                 try {
   1283                                     if (!sWindowSession.outOfMemory(mWindow)) {
   1284                                         Slog.w(TAG, "No processes killed for memory; killing self");
   1285                                         Process.killProcess(Process.myPid());
   1286                                     }
   1287                                 } catch (RemoteException ex) {
   1288                                 }
   1289                                 mLayoutRequested = true;    // ask wm for a new surface next time.
   1290                                 return;
   1291                             }
   1292                         }
   1293                     }
   1294                 } else if (!mSurface.isValid()) {
   1295                     // If the surface has been removed, then reset the scroll
   1296                     // positions.
   1297                     mLastScrolledFocus = null;
   1298                     mScrollY = mCurScrollY = 0;
   1299                     if (mScroller != null) {
   1300                         mScroller.abortAnimation();
   1301                     }
   1302                     disposeResizeBuffer();
   1303                     // Our surface is gone
   1304                     if (mAttachInfo.mHardwareRenderer != null &&
   1305                             mAttachInfo.mHardwareRenderer.isEnabled()) {
   1306                         mAttachInfo.mHardwareRenderer.destroy(true);
   1307                     }
   1308                 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
   1309                         mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
   1310                     fullRedrawNeeded = true;
   1311                     try {
   1312                         mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
   1313                     } catch (Surface.OutOfResourcesException e) {
   1314                         Log.e(TAG, "OutOfResourcesException updating HW surface", e);
   1315                         try {
   1316                             if (!sWindowSession.outOfMemory(mWindow)) {
   1317                                 Slog.w(TAG, "No processes killed for memory; killing self");
   1318                                 Process.killProcess(Process.myPid());
   1319                             }
   1320                         } catch (RemoteException ex) {
   1321                         }
   1322                         mLayoutRequested = true;    // ask wm for a new surface next time.
   1323                         return;
   1324                     }
   1325                 }
   1326             } catch (RemoteException e) {
   1327             }
   1328 
   1329             if (DEBUG_ORIENTATION) Log.v(
   1330                     TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
   1331 
   1332             attachInfo.mWindowLeft = frame.left;
   1333             attachInfo.mWindowTop = frame.top;
   1334 
   1335             // !!FIXME!! This next section handles the case where we did not get the
   1336             // window size we asked for. We should avoid this by getting a maximum size from
   1337             // the window session beforehand.
   1338             mWidth = frame.width();
   1339             mHeight = frame.height();
   1340 
   1341             if (mSurfaceHolder != null) {
   1342                 // The app owns the surface; tell it about what is going on.
   1343                 if (mSurface.isValid()) {
   1344                     // XXX .copyFrom() doesn't work!
   1345                     //mSurfaceHolder.mSurface.copyFrom(mSurface);
   1346                     mSurfaceHolder.mSurface = mSurface;
   1347                 }
   1348                 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
   1349                 mSurfaceHolder.mSurfaceLock.unlock();
   1350                 if (mSurface.isValid()) {
   1351                     if (!hadSurface) {
   1352                         mSurfaceHolder.ungetCallbacks();
   1353 
   1354                         mIsCreating = true;
   1355                         mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
   1356                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   1357                         if (callbacks != null) {
   1358                             for (SurfaceHolder.Callback c : callbacks) {
   1359                                 c.surfaceCreated(mSurfaceHolder);
   1360                             }
   1361                         }
   1362                         surfaceChanged = true;
   1363                     }
   1364                     if (surfaceChanged) {
   1365                         mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
   1366                                 lp.format, mWidth, mHeight);
   1367                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   1368                         if (callbacks != null) {
   1369                             for (SurfaceHolder.Callback c : callbacks) {
   1370                                 c.surfaceChanged(mSurfaceHolder, lp.format,
   1371                                         mWidth, mHeight);
   1372                             }
   1373                         }
   1374                     }
   1375                     mIsCreating = false;
   1376                 } else if (hadSurface) {
   1377                     mSurfaceHolder.ungetCallbacks();
   1378                     SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   1379                     mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
   1380                     if (callbacks != null) {
   1381                         for (SurfaceHolder.Callback c : callbacks) {
   1382                             c.surfaceDestroyed(mSurfaceHolder);
   1383                         }
   1384                     }
   1385                     mSurfaceHolder.mSurfaceLock.lock();
   1386                     try {
   1387                         mSurfaceHolder.mSurface = new Surface();
   1388                     } finally {
   1389                         mSurfaceHolder.mSurfaceLock.unlock();
   1390                     }
   1391                 }
   1392             }
   1393 
   1394             if (mAttachInfo.mHardwareRenderer != null &&
   1395                     mAttachInfo.mHardwareRenderer.isEnabled()) {
   1396                 if (hwInitialized || windowShouldResize ||
   1397                         mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
   1398                         mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
   1399                     mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
   1400                     if (!hwInitialized) {
   1401                         mAttachInfo.mHardwareRenderer.invalidate(mHolder);
   1402                     }
   1403                 }
   1404             }
   1405 
   1406             if (!mStopped) {
   1407                 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
   1408                         (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
   1409                 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
   1410                         || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
   1411                     childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
   1412                     childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
   1413 
   1414                     if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
   1415                             + mWidth + " measuredWidth=" + host.getMeasuredWidth()
   1416                             + " mHeight=" + mHeight
   1417                             + " measuredHeight=" + host.getMeasuredHeight()
   1418                             + " coveredInsetsChanged=" + contentInsetsChanged);
   1419 
   1420                      // Ask host how big it wants to be
   1421                     host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   1422 
   1423                     // Implementation of weights from WindowManager.LayoutParams
   1424                     // We just grow the dimensions as needed and re-measure if
   1425                     // needs be
   1426                     int width = host.getMeasuredWidth();
   1427                     int height = host.getMeasuredHeight();
   1428                     boolean measureAgain = false;
   1429 
   1430                     if (lp.horizontalWeight > 0.0f) {
   1431                         width += (int) ((mWidth - width) * lp.horizontalWeight);
   1432                         childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
   1433                                 MeasureSpec.EXACTLY);
   1434                         measureAgain = true;
   1435                     }
   1436                     if (lp.verticalWeight > 0.0f) {
   1437                         height += (int) ((mHeight - height) * lp.verticalWeight);
   1438                         childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
   1439                                 MeasureSpec.EXACTLY);
   1440                         measureAgain = true;
   1441                     }
   1442 
   1443                     if (measureAgain) {
   1444                         if (DEBUG_LAYOUT) Log.v(TAG,
   1445                                 "And hey let's measure once more: width=" + width
   1446                                 + " height=" + height);
   1447                         host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   1448                     }
   1449 
   1450                     mLayoutRequested = true;
   1451                 }
   1452             }
   1453         }
   1454 
   1455         final boolean didLayout = mLayoutRequested && !mStopped;
   1456         boolean triggerGlobalLayoutListener = didLayout
   1457                 || attachInfo.mRecomputeGlobalAttributes;
   1458         if (didLayout) {
   1459             mLayoutRequested = false;
   1460             mScrollMayChange = true;
   1461             if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
   1462                 TAG, "Laying out " + host + " to (" +
   1463                 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
   1464             long startTime = 0L;
   1465             if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
   1466                 startTime = SystemClock.elapsedRealtime();
   1467             }
   1468             host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
   1469 
   1470             if (false && ViewDebug.consistencyCheckEnabled) {
   1471                 if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
   1472                     throw new IllegalStateException("The view hierarchy is an inconsistent state,"
   1473                             + "please refer to the logs with the tag "
   1474                             + ViewDebug.CONSISTENCY_LOG_TAG + " for more infomation.");
   1475                 }
   1476             }
   1477 
   1478             if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
   1479                 EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
   1480             }
   1481 
   1482             // By this point all views have been sized and positionned
   1483             // We can compute the transparent area
   1484 
   1485             if ((host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
   1486                 // start out transparent
   1487                 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
   1488                 host.getLocationInWindow(mTmpLocation);
   1489                 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
   1490                         mTmpLocation[0] + host.mRight - host.mLeft,
   1491                         mTmpLocation[1] + host.mBottom - host.mTop);
   1492 
   1493                 host.gatherTransparentRegion(mTransparentRegion);
   1494                 if (mTranslator != null) {
   1495                     mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
   1496                 }
   1497 
   1498                 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
   1499                     mPreviousTransparentRegion.set(mTransparentRegion);
   1500                     // reconfigure window manager
   1501                     try {
   1502                         sWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
   1503                     } catch (RemoteException e) {
   1504                     }
   1505                 }
   1506             }
   1507 
   1508             if (DBG) {
   1509                 System.out.println("======================================");
   1510                 System.out.println("performTraversals -- after setFrame");
   1511                 host.debug();
   1512             }
   1513         }
   1514 
   1515         if (triggerGlobalLayoutListener) {
   1516             attachInfo.mRecomputeGlobalAttributes = false;
   1517             attachInfo.mTreeObserver.dispatchOnGlobalLayout();
   1518 
   1519             if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
   1520                 postSendWindowContentChangedCallback();
   1521             }
   1522         }
   1523 
   1524         if (computesInternalInsets) {
   1525             // Clear the original insets.
   1526             final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
   1527             insets.reset();
   1528 
   1529             // Compute new insets in place.
   1530             attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
   1531 
   1532             // Tell the window manager.
   1533             if (insetsPending || !mLastGivenInsets.equals(insets)) {
   1534                 mLastGivenInsets.set(insets);
   1535 
   1536                 // Translate insets to screen coordinates if needed.
   1537                 final Rect contentInsets;
   1538                 final Rect visibleInsets;
   1539                 final Region touchableRegion;
   1540                 if (mTranslator != null) {
   1541                     contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
   1542                     visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
   1543                     touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
   1544                 } else {
   1545                     contentInsets = insets.contentInsets;
   1546                     visibleInsets = insets.visibleInsets;
   1547                     touchableRegion = insets.touchableRegion;
   1548                 }
   1549 
   1550                 try {
   1551                     sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
   1552                             contentInsets, visibleInsets, touchableRegion);
   1553                 } catch (RemoteException e) {
   1554                 }
   1555             }
   1556         }
   1557 
   1558         if (mFirst) {
   1559             // handle first focus request
   1560             if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
   1561                     + mView.hasFocus());
   1562             if (mView != null) {
   1563                 if (!mView.hasFocus()) {
   1564                     mView.requestFocus(View.FOCUS_FORWARD);
   1565                     mFocusedView = mRealFocusedView = mView.findFocus();
   1566                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
   1567                             + mFocusedView);
   1568                 } else {
   1569                     mRealFocusedView = mView.findFocus();
   1570                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
   1571                             + mRealFocusedView);
   1572                 }
   1573             }
   1574         }
   1575 
   1576         mFirst = false;
   1577         mWillDrawSoon = false;
   1578         mNewSurfaceNeeded = false;
   1579         mViewVisibility = viewVisibility;
   1580 
   1581         if (mAttachInfo.mHasWindowFocus) {
   1582             final boolean imTarget = WindowManager.LayoutParams
   1583                     .mayUseInputMethod(mWindowAttributes.flags);
   1584             if (imTarget != mLastWasImTarget) {
   1585                 mLastWasImTarget = imTarget;
   1586                 InputMethodManager imm = InputMethodManager.peekInstance();
   1587                 if (imm != null && imTarget) {
   1588                     imm.startGettingWindowFocus(mView);
   1589                     imm.onWindowFocus(mView, mView.findFocus(),
   1590                             mWindowAttributes.softInputMode,
   1591                             !mHasHadWindowFocus, mWindowAttributes.flags);
   1592                 }
   1593             }
   1594         }
   1595 
   1596         boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
   1597                 viewVisibility != View.VISIBLE;
   1598 
   1599         if (!cancelDraw && !newSurface) {
   1600             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
   1601                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
   1602                     mPendingTransitions.get(i).startChangingAnimations();
   1603                 }
   1604                 mPendingTransitions.clear();
   1605             }
   1606             mFullRedrawNeeded = false;
   1607 
   1608             final long drawStartTime;
   1609             if (ViewDebug.DEBUG_LATENCY) {
   1610                 drawStartTime = System.nanoTime();
   1611             }
   1612 
   1613             draw(fullRedrawNeeded);
   1614 
   1615             if (ViewDebug.DEBUG_LATENCY) {
   1616                 mLastDrawDurationNanos = System.nanoTime() - drawStartTime;
   1617             }
   1618 
   1619             if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0
   1620                     || mReportNextDraw) {
   1621                 if (LOCAL_LOGV) {
   1622                     Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
   1623                 }
   1624                 mReportNextDraw = false;
   1625                 if (mSurfaceHolder != null && mSurface.isValid()) {
   1626                     mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
   1627                     SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   1628                     if (callbacks != null) {
   1629                         for (SurfaceHolder.Callback c : callbacks) {
   1630                             if (c instanceof SurfaceHolder.Callback2) {
   1631                                 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
   1632                                         mSurfaceHolder);
   1633                             }
   1634                         }
   1635                     }
   1636                 }
   1637                 try {
   1638                     sWindowSession.finishDrawing(mWindow);
   1639                 } catch (RemoteException e) {
   1640                 }
   1641             }
   1642         } else {
   1643             // End any pending transitions on this non-visible window
   1644             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
   1645                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
   1646                     mPendingTransitions.get(i).endChangingAnimations();
   1647                 }
   1648                 mPendingTransitions.clear();
   1649             }
   1650             // We were supposed to report when we are done drawing. Since we canceled the
   1651             // draw, remember it here.
   1652             if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
   1653                 mReportNextDraw = true;
   1654             }
   1655             if (fullRedrawNeeded) {
   1656                 mFullRedrawNeeded = true;
   1657             }
   1658 
   1659             if (viewVisibility == View.VISIBLE) {
   1660                 // Try again
   1661                 scheduleTraversals();
   1662             }
   1663         }
   1664     }
   1665 
   1666     public void requestTransparentRegion(View child) {
   1667         // the test below should not fail unless someone is messing with us
   1668         checkThread();
   1669         if (mView == child) {
   1670             mView.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
   1671             // Need to make sure we re-evaluate the window attributes next
   1672             // time around, to ensure the window has the correct format.
   1673             mWindowAttributesChanged = true;
   1674             mWindowAttributesChangesFlag = 0;
   1675             requestLayout();
   1676         }
   1677     }
   1678 
   1679     /**
   1680      * Figures out the measure spec for the root view in a window based on it's
   1681      * layout params.
   1682      *
   1683      * @param windowSize
   1684      *            The available width or height of the window
   1685      *
   1686      * @param rootDimension
   1687      *            The layout params for one dimension (width or height) of the
   1688      *            window.
   1689      *
   1690      * @return The measure spec to use to measure the root view.
   1691      */
   1692     private int getRootMeasureSpec(int windowSize, int rootDimension) {
   1693         int measureSpec;
   1694         switch (rootDimension) {
   1695 
   1696         case ViewGroup.LayoutParams.MATCH_PARENT:
   1697             // Window can't resize. Force root view to be windowSize.
   1698             measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
   1699             break;
   1700         case ViewGroup.LayoutParams.WRAP_CONTENT:
   1701             // Window can resize. Set max size for root view.
   1702             measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
   1703             break;
   1704         default:
   1705             // Window wants to be an exact size. Force root view to be that size.
   1706             measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
   1707             break;
   1708         }
   1709         return measureSpec;
   1710     }
   1711 
   1712     int mHardwareYOffset;
   1713     int mResizeAlpha;
   1714     final Paint mResizePaint = new Paint();
   1715 
   1716     public void onHardwarePreDraw(HardwareCanvas canvas) {
   1717         canvas.translate(0, -mHardwareYOffset);
   1718     }
   1719 
   1720     public void onHardwarePostDraw(HardwareCanvas canvas) {
   1721         if (mResizeBuffer != null) {
   1722             mResizePaint.setAlpha(mResizeAlpha);
   1723             canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
   1724         }
   1725     }
   1726 
   1727     /**
   1728      * @hide
   1729      */
   1730     void outputDisplayList(View view) {
   1731         if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
   1732             DisplayList displayList = view.getDisplayList();
   1733             if (displayList != null) {
   1734                 mAttachInfo.mHardwareCanvas.outputDisplayList(displayList);
   1735             }
   1736         }
   1737     }
   1738 
   1739     /**
   1740      * @see #PROPERTY_PROFILE_RENDERING
   1741      */
   1742     private void profileRendering(boolean enabled) {
   1743         if (mProfileRendering) {
   1744             mRenderProfilingEnabled = enabled;
   1745             if (mRenderProfiler == null) {
   1746                 mRenderProfiler = new Thread(new Runnable() {
   1747                     @Override
   1748                     public void run() {
   1749                         Log.d(TAG, "Starting profiling thread");
   1750                         while (mRenderProfilingEnabled) {
   1751                             mAttachInfo.mHandler.post(new Runnable() {
   1752                                 @Override
   1753                                 public void run() {
   1754                                     mDirty.set(0, 0, mWidth, mHeight);
   1755                                     scheduleTraversals();
   1756                                 }
   1757                             });
   1758                             try {
   1759                                 // TODO: This should use vsync when we get an API
   1760                                 Thread.sleep(15);
   1761                             } catch (InterruptedException e) {
   1762                                 Log.d(TAG, "Exiting profiling thread");
   1763                             }
   1764                         }
   1765                     }
   1766                 }, "Rendering Profiler");
   1767                 mRenderProfiler.start();
   1768             } else {
   1769                 mRenderProfiler.interrupt();
   1770                 mRenderProfiler = null;
   1771             }
   1772         }
   1773     }
   1774 
   1775     /**
   1776      * Called from draw() when DEBUG_FPS is enabled
   1777      */
   1778     private void trackFPS() {
   1779         // Tracks frames per second drawn. First value in a series of draws may be bogus
   1780         // because it down not account for the intervening idle time
   1781         long nowTime = System.currentTimeMillis();
   1782         if (mFpsStartTime < 0) {
   1783             mFpsStartTime = mFpsPrevTime = nowTime;
   1784             mFpsNumFrames = 0;
   1785         } else {
   1786             ++mFpsNumFrames;
   1787             String thisHash = Integer.toHexString(System.identityHashCode(this));
   1788             long frameTime = nowTime - mFpsPrevTime;
   1789             long totalTime = nowTime - mFpsStartTime;
   1790             Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
   1791             mFpsPrevTime = nowTime;
   1792             if (totalTime > 1000) {
   1793                 float fps = (float) mFpsNumFrames * 1000 / totalTime;
   1794                 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
   1795                 mFpsStartTime = nowTime;
   1796                 mFpsNumFrames = 0;
   1797             }
   1798         }
   1799     }
   1800 
   1801     private void draw(boolean fullRedrawNeeded) {
   1802         Surface surface = mSurface;
   1803         if (surface == null || !surface.isValid()) {
   1804             return;
   1805         }
   1806 
   1807         if (DEBUG_FPS) {
   1808             trackFPS();
   1809         }
   1810 
   1811         if (!sFirstDrawComplete) {
   1812             synchronized (sFirstDrawHandlers) {
   1813                 sFirstDrawComplete = true;
   1814                 final int count = sFirstDrawHandlers.size();
   1815                 for (int i = 0; i< count; i++) {
   1816                     post(sFirstDrawHandlers.get(i));
   1817                 }
   1818             }
   1819         }
   1820 
   1821         scrollToRectOrFocus(null, false);
   1822 
   1823         if (mAttachInfo.mViewScrollChanged) {
   1824             mAttachInfo.mViewScrollChanged = false;
   1825             mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
   1826         }
   1827 
   1828         int yoff;
   1829         boolean animating = mScroller != null && mScroller.computeScrollOffset();
   1830         if (animating) {
   1831             yoff = mScroller.getCurrY();
   1832         } else {
   1833             yoff = mScrollY;
   1834         }
   1835         if (mCurScrollY != yoff) {
   1836             mCurScrollY = yoff;
   1837             fullRedrawNeeded = true;
   1838         }
   1839         float appScale = mAttachInfo.mApplicationScale;
   1840         boolean scalingRequired = mAttachInfo.mScalingRequired;
   1841 
   1842         int resizeAlpha = 0;
   1843         if (mResizeBuffer != null) {
   1844             long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
   1845             if (deltaTime < mResizeBufferDuration) {
   1846                 float amt = deltaTime/(float) mResizeBufferDuration;
   1847                 amt = mResizeInterpolator.getInterpolation(amt);
   1848                 animating = true;
   1849                 resizeAlpha = 255 - (int)(amt*255);
   1850             } else {
   1851                 disposeResizeBuffer();
   1852             }
   1853         }
   1854 
   1855         Rect dirty = mDirty;
   1856         if (mSurfaceHolder != null) {
   1857             // The app owns the surface, we won't draw.
   1858             dirty.setEmpty();
   1859             if (animating) {
   1860                 if (mScroller != null) {
   1861                     mScroller.abortAnimation();
   1862                 }
   1863                 disposeResizeBuffer();
   1864             }
   1865             return;
   1866         }
   1867 
   1868         if (fullRedrawNeeded) {
   1869             mAttachInfo.mIgnoreDirtyState = true;
   1870             dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
   1871         }
   1872 
   1873         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
   1874             if (!dirty.isEmpty() || mIsAnimating) {
   1875                 mIsAnimating = false;
   1876                 mHardwareYOffset = yoff;
   1877                 mResizeAlpha = resizeAlpha;
   1878 
   1879                 mCurrentDirty.set(dirty);
   1880                 mCurrentDirty.union(mPreviousDirty);
   1881                 mPreviousDirty.set(dirty);
   1882                 dirty.setEmpty();
   1883 
   1884                 Rect currentDirty = mCurrentDirty;
   1885                 if (animating) {
   1886                     currentDirty = null;
   1887                 }
   1888 
   1889                 if (mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this, currentDirty)) {
   1890                     mPreviousDirty.set(0, 0, mWidth, mHeight);
   1891                 }
   1892             }
   1893 
   1894             if (animating) {
   1895                 mFullRedrawNeeded = true;
   1896                 scheduleTraversals();
   1897             }
   1898 
   1899             return;
   1900         }
   1901 
   1902         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
   1903             Log.v(TAG, "Draw " + mView + "/"
   1904                     + mWindowAttributes.getTitle()
   1905                     + ": dirty={" + dirty.left + "," + dirty.top
   1906                     + "," + dirty.right + "," + dirty.bottom + "} surface="
   1907                     + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
   1908                     appScale + ", width=" + mWidth + ", height=" + mHeight);
   1909         }
   1910 
   1911         if (!dirty.isEmpty() || mIsAnimating) {
   1912             Canvas canvas;
   1913             try {
   1914                 int left = dirty.left;
   1915                 int top = dirty.top;
   1916                 int right = dirty.right;
   1917                 int bottom = dirty.bottom;
   1918 
   1919                 final long lockCanvasStartTime;
   1920                 if (ViewDebug.DEBUG_LATENCY) {
   1921                     lockCanvasStartTime = System.nanoTime();
   1922                 }
   1923 
   1924                 canvas = surface.lockCanvas(dirty);
   1925 
   1926                 if (ViewDebug.DEBUG_LATENCY) {
   1927                     long now = System.nanoTime();
   1928                     Log.d(TAG, "Latency: Spent "
   1929                             + ((now - lockCanvasStartTime) * 0.000001f)
   1930                             + "ms waiting for surface.lockCanvas()");
   1931                 }
   1932 
   1933                 if (left != dirty.left || top != dirty.top || right != dirty.right ||
   1934                         bottom != dirty.bottom) {
   1935                     mAttachInfo.mIgnoreDirtyState = true;
   1936                 }
   1937 
   1938                 // TODO: Do this in native
   1939                 canvas.setDensity(mDensity);
   1940             } catch (Surface.OutOfResourcesException e) {
   1941                 Log.e(TAG, "OutOfResourcesException locking surface", e);
   1942                 try {
   1943                     if (!sWindowSession.outOfMemory(mWindow)) {
   1944                         Slog.w(TAG, "No processes killed for memory; killing self");
   1945                         Process.killProcess(Process.myPid());
   1946                     }
   1947                 } catch (RemoteException ex) {
   1948                 }
   1949                 mLayoutRequested = true;    // ask wm for a new surface next time.
   1950                 return;
   1951             } catch (IllegalArgumentException e) {
   1952                 Log.e(TAG, "IllegalArgumentException locking surface", e);
   1953                 // Don't assume this is due to out of memory, it could be
   1954                 // something else, and if it is something else then we could
   1955                 // kill stuff (or ourself) for no reason.
   1956                 mLayoutRequested = true;    // ask wm for a new surface next time.
   1957                 return;
   1958             }
   1959 
   1960             try {
   1961                 if (!dirty.isEmpty() || mIsAnimating) {
   1962                     long startTime = 0L;
   1963 
   1964                     if (DEBUG_ORIENTATION || DEBUG_DRAW) {
   1965                         Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
   1966                                 + canvas.getWidth() + ", h=" + canvas.getHeight());
   1967                         //canvas.drawARGB(255, 255, 0, 0);
   1968                     }
   1969 
   1970                     if (ViewDebug.DEBUG_PROFILE_DRAWING) {
   1971                         startTime = SystemClock.elapsedRealtime();
   1972                     }
   1973 
   1974                     // If this bitmap's format includes an alpha channel, we
   1975                     // need to clear it before drawing so that the child will
   1976                     // properly re-composite its drawing on a transparent
   1977                     // background. This automatically respects the clip/dirty region
   1978                     // or
   1979                     // If we are applying an offset, we need to clear the area
   1980                     // where the offset doesn't appear to avoid having garbage
   1981                     // left in the blank areas.
   1982                     if (!canvas.isOpaque() || yoff != 0) {
   1983                         canvas.drawColor(0, PorterDuff.Mode.CLEAR);
   1984                     }
   1985 
   1986                     dirty.setEmpty();
   1987                     mIsAnimating = false;
   1988                     mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
   1989                     mView.mPrivateFlags |= View.DRAWN;
   1990 
   1991                     if (DEBUG_DRAW) {
   1992                         Context cxt = mView.getContext();
   1993                         Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
   1994                                 ", metrics=" + cxt.getResources().getDisplayMetrics() +
   1995                                 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
   1996                     }
   1997                     try {
   1998                         canvas.translate(0, -yoff);
   1999                         if (mTranslator != null) {
   2000                             mTranslator.translateCanvas(canvas);
   2001                         }
   2002                         canvas.setScreenDensity(scalingRequired
   2003                                 ? DisplayMetrics.DENSITY_DEVICE : 0);
   2004                         mAttachInfo.mSetIgnoreDirtyState = false;
   2005                         mView.draw(canvas);
   2006                     } finally {
   2007                         if (!mAttachInfo.mSetIgnoreDirtyState) {
   2008                             // Only clear the flag if it was not set during the mView.draw() call
   2009                             mAttachInfo.mIgnoreDirtyState = false;
   2010                         }
   2011                     }
   2012 
   2013                     if (false && ViewDebug.consistencyCheckEnabled) {
   2014                         mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
   2015                     }
   2016 
   2017                     if (ViewDebug.DEBUG_PROFILE_DRAWING) {
   2018                         EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
   2019                     }
   2020                 }
   2021 
   2022             } finally {
   2023                 surface.unlockCanvasAndPost(canvas);
   2024             }
   2025         }
   2026 
   2027         if (LOCAL_LOGV) {
   2028             Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
   2029         }
   2030 
   2031         if (animating) {
   2032             mFullRedrawNeeded = true;
   2033             scheduleTraversals();
   2034         }
   2035     }
   2036 
   2037     boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
   2038         final View.AttachInfo attachInfo = mAttachInfo;
   2039         final Rect ci = attachInfo.mContentInsets;
   2040         final Rect vi = attachInfo.mVisibleInsets;
   2041         int scrollY = 0;
   2042         boolean handled = false;
   2043 
   2044         if (vi.left > ci.left || vi.top > ci.top
   2045                 || vi.right > ci.right || vi.bottom > ci.bottom) {
   2046             // We'll assume that we aren't going to change the scroll
   2047             // offset, since we want to avoid that unless it is actually
   2048             // going to make the focus visible...  otherwise we scroll
   2049             // all over the place.
   2050             scrollY = mScrollY;
   2051             // We can be called for two different situations: during a draw,
   2052             // to update the scroll position if the focus has changed (in which
   2053             // case 'rectangle' is null), or in response to a
   2054             // requestChildRectangleOnScreen() call (in which case 'rectangle'
   2055             // is non-null and we just want to scroll to whatever that
   2056             // rectangle is).
   2057             View focus = mRealFocusedView;
   2058 
   2059             // When in touch mode, focus points to the previously focused view,
   2060             // which may have been removed from the view hierarchy. The following
   2061             // line checks whether the view is still in our hierarchy.
   2062             if (focus == null || focus.mAttachInfo != mAttachInfo) {
   2063                 mRealFocusedView = null;
   2064                 return false;
   2065             }
   2066 
   2067             if (focus != mLastScrolledFocus) {
   2068                 // If the focus has changed, then ignore any requests to scroll
   2069                 // to a rectangle; first we want to make sure the entire focus
   2070                 // view is visible.
   2071                 rectangle = null;
   2072             }
   2073             if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
   2074                     + " rectangle=" + rectangle + " ci=" + ci
   2075                     + " vi=" + vi);
   2076             if (focus == mLastScrolledFocus && !mScrollMayChange
   2077                     && rectangle == null) {
   2078                 // Optimization: if the focus hasn't changed since last
   2079                 // time, and no layout has happened, then just leave things
   2080                 // as they are.
   2081                 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
   2082                         + mScrollY + " vi=" + vi.toShortString());
   2083             } else if (focus != null) {
   2084                 // We need to determine if the currently focused view is
   2085                 // within the visible part of the window and, if not, apply
   2086                 // a pan so it can be seen.
   2087                 mLastScrolledFocus = focus;
   2088                 mScrollMayChange = false;
   2089                 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
   2090                 // Try to find the rectangle from the focus view.
   2091                 if (focus.getGlobalVisibleRect(mVisRect, null)) {
   2092                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
   2093                             + mView.getWidth() + " h=" + mView.getHeight()
   2094                             + " ci=" + ci.toShortString()
   2095                             + " vi=" + vi.toShortString());
   2096                     if (rectangle == null) {
   2097                         focus.getFocusedRect(mTempRect);
   2098                         if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
   2099                                 + ": focusRect=" + mTempRect.toShortString());
   2100                         if (mView instanceof ViewGroup) {
   2101                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
   2102                                     focus, mTempRect);
   2103                         }
   2104                         if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2105                                 "Focus in window: focusRect="
   2106                                 + mTempRect.toShortString()
   2107                                 + " visRect=" + mVisRect.toShortString());
   2108                     } else {
   2109                         mTempRect.set(rectangle);
   2110                         if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2111                                 "Request scroll to rect: "
   2112                                 + mTempRect.toShortString()
   2113                                 + " visRect=" + mVisRect.toShortString());
   2114                     }
   2115                     if (mTempRect.intersect(mVisRect)) {
   2116                         if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2117                                 "Focus window visible rect: "
   2118                                 + mTempRect.toShortString());
   2119                         if (mTempRect.height() >
   2120                                 (mView.getHeight()-vi.top-vi.bottom)) {
   2121                             // If the focus simply is not going to fit, then
   2122                             // best is probably just to leave things as-is.
   2123                             if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2124                                     "Too tall; leaving scrollY=" + scrollY);
   2125                         } else if ((mTempRect.top-scrollY) < vi.top) {
   2126                             scrollY -= vi.top - (mTempRect.top-scrollY);
   2127                             if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2128                                     "Top covered; scrollY=" + scrollY);
   2129                         } else if ((mTempRect.bottom-scrollY)
   2130                                 > (mView.getHeight()-vi.bottom)) {
   2131                             scrollY += (mTempRect.bottom-scrollY)
   2132                                     - (mView.getHeight()-vi.bottom);
   2133                             if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2134                                     "Bottom covered; scrollY=" + scrollY);
   2135                         }
   2136                         handled = true;
   2137                     }
   2138                 }
   2139             }
   2140         }
   2141 
   2142         if (scrollY != mScrollY) {
   2143             if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
   2144                     + mScrollY + " , new=" + scrollY);
   2145             if (!immediate && mResizeBuffer == null) {
   2146                 if (mScroller == null) {
   2147                     mScroller = new Scroller(mView.getContext());
   2148                 }
   2149                 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
   2150             } else if (mScroller != null) {
   2151                 mScroller.abortAnimation();
   2152             }
   2153             mScrollY = scrollY;
   2154         }
   2155 
   2156         return handled;
   2157     }
   2158 
   2159     public void requestChildFocus(View child, View focused) {
   2160         checkThread();
   2161         if (mFocusedView != focused) {
   2162             mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
   2163             scheduleTraversals();
   2164         }
   2165         mFocusedView = mRealFocusedView = focused;
   2166         if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now "
   2167                 + mFocusedView);
   2168     }
   2169 
   2170     public void clearChildFocus(View child) {
   2171         checkThread();
   2172 
   2173         View oldFocus = mFocusedView;
   2174 
   2175         if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus");
   2176         mFocusedView = mRealFocusedView = null;
   2177         if (mView != null && !mView.hasFocus()) {
   2178             // If a view gets the focus, the listener will be invoked from requestChildFocus()
   2179             if (!mView.requestFocus(View.FOCUS_FORWARD)) {
   2180                 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
   2181             }
   2182         } else if (oldFocus != null) {
   2183             mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
   2184         }
   2185     }
   2186 
   2187 
   2188     public void focusableViewAvailable(View v) {
   2189         checkThread();
   2190 
   2191         if (mView != null) {
   2192             if (!mView.hasFocus()) {
   2193                 v.requestFocus();
   2194             } else {
   2195                 // the one case where will transfer focus away from the current one
   2196                 // is if the current view is a view group that prefers to give focus
   2197                 // to its children first AND the view is a descendant of it.
   2198                 mFocusedView = mView.findFocus();
   2199                 boolean descendantsHaveDibsOnFocus =
   2200                         (mFocusedView instanceof ViewGroup) &&
   2201                             (((ViewGroup) mFocusedView).getDescendantFocusability() ==
   2202                                     ViewGroup.FOCUS_AFTER_DESCENDANTS);
   2203                 if (descendantsHaveDibsOnFocus && isViewDescendantOf(v, mFocusedView)) {
   2204                     // If a view gets the focus, the listener will be invoked from requestChildFocus()
   2205                     v.requestFocus();
   2206                 }
   2207             }
   2208         }
   2209     }
   2210 
   2211     public void recomputeViewAttributes(View child) {
   2212         checkThread();
   2213         if (mView == child) {
   2214             mAttachInfo.mRecomputeGlobalAttributes = true;
   2215             if (!mWillDrawSoon) {
   2216                 scheduleTraversals();
   2217             }
   2218         }
   2219     }
   2220 
   2221     void dispatchDetachedFromWindow() {
   2222         if (mView != null && mView.mAttachInfo != null) {
   2223             if (mAttachInfo.mHardwareRenderer != null &&
   2224                     mAttachInfo.mHardwareRenderer.isEnabled()) {
   2225                 mAttachInfo.mHardwareRenderer.validate();
   2226             }
   2227             mView.dispatchDetachedFromWindow();
   2228         }
   2229 
   2230         mAccessibilityInteractionConnectionManager.ensureNoConnection();
   2231         mAccessibilityManager.removeAccessibilityStateChangeListener(
   2232                 mAccessibilityInteractionConnectionManager);
   2233         removeSendWindowContentChangedCallback();
   2234 
   2235         mView = null;
   2236         mAttachInfo.mRootView = null;
   2237         mAttachInfo.mSurface = null;
   2238 
   2239         destroyHardwareRenderer();
   2240 
   2241         mSurface.release();
   2242 
   2243         if (mInputQueueCallback != null && mInputQueue != null) {
   2244             mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
   2245             mInputQueueCallback = null;
   2246             mInputQueue = null;
   2247         } else if (mInputChannel != null) {
   2248             InputQueue.unregisterInputChannel(mInputChannel);
   2249         }
   2250         try {
   2251             sWindowSession.remove(mWindow);
   2252         } catch (RemoteException e) {
   2253         }
   2254 
   2255         // Dispose the input channel after removing the window so the Window Manager
   2256         // doesn't interpret the input channel being closed as an abnormal termination.
   2257         if (mInputChannel != null) {
   2258             mInputChannel.dispose();
   2259             mInputChannel = null;
   2260         }
   2261     }
   2262 
   2263     void updateConfiguration(Configuration config, boolean force) {
   2264         if (DEBUG_CONFIGURATION) Log.v(TAG,
   2265                 "Applying new config to window "
   2266                 + mWindowAttributes.getTitle()
   2267                 + ": " + config);
   2268 
   2269         CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
   2270         if (ci != null) {
   2271             config = new Configuration(config);
   2272             ci.applyToConfiguration(config);
   2273         }
   2274 
   2275         synchronized (sConfigCallbacks) {
   2276             for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
   2277                 sConfigCallbacks.get(i).onConfigurationChanged(config);
   2278             }
   2279         }
   2280         if (mView != null) {
   2281             // At this point the resources have been updated to
   2282             // have the most recent config, whatever that is.  Use
   2283             // the on in them which may be newer.
   2284             config = mView.getResources().getConfiguration();
   2285             if (force || mLastConfiguration.diff(config) != 0) {
   2286                 mLastConfiguration.setTo(config);
   2287                 mView.dispatchConfigurationChanged(config);
   2288             }
   2289         }
   2290     }
   2291 
   2292     /**
   2293      * Return true if child is an ancestor of parent, (or equal to the parent).
   2294      */
   2295     private static boolean isViewDescendantOf(View child, View parent) {
   2296         if (child == parent) {
   2297             return true;
   2298         }
   2299 
   2300         final ViewParent theParent = child.getParent();
   2301         return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
   2302     }
   2303 
   2304     private static void forceLayout(View view) {
   2305         view.forceLayout();
   2306         if (view instanceof ViewGroup) {
   2307             ViewGroup group = (ViewGroup) view;
   2308             final int count = group.getChildCount();
   2309             for (int i = 0; i < count; i++) {
   2310                 forceLayout(group.getChildAt(i));
   2311             }
   2312         }
   2313     }
   2314 
   2315     public final static int DO_TRAVERSAL = 1000;
   2316     public final static int DIE = 1001;
   2317     public final static int RESIZED = 1002;
   2318     public final static int RESIZED_REPORT = 1003;
   2319     public final static int WINDOW_FOCUS_CHANGED = 1004;
   2320     public final static int DISPATCH_KEY = 1005;
   2321     public final static int DISPATCH_POINTER = 1006;
   2322     public final static int DISPATCH_TRACKBALL = 1007;
   2323     public final static int DISPATCH_APP_VISIBILITY = 1008;
   2324     public final static int DISPATCH_GET_NEW_SURFACE = 1009;
   2325     public final static int FINISHED_EVENT = 1010;
   2326     public final static int DISPATCH_KEY_FROM_IME = 1011;
   2327     public final static int FINISH_INPUT_CONNECTION = 1012;
   2328     public final static int CHECK_FOCUS = 1013;
   2329     public final static int CLOSE_SYSTEM_DIALOGS = 1014;
   2330     public final static int DISPATCH_DRAG_EVENT = 1015;
   2331     public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016;
   2332     public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017;
   2333     public final static int DISPATCH_GENERIC_MOTION = 1018;
   2334     public final static int UPDATE_CONFIGURATION = 1019;
   2335     public final static int DO_PERFORM_ACCESSIBILITY_ACTION = 1020;
   2336     public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 1021;
   2337     public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 1022;
   2338     public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT = 1023;
   2339 
   2340     @Override
   2341     public String getMessageName(Message message) {
   2342         switch (message.what) {
   2343             case DO_TRAVERSAL:
   2344                 return "DO_TRAVERSAL";
   2345             case DIE:
   2346                 return "DIE";
   2347             case RESIZED:
   2348                 return "RESIZED";
   2349             case RESIZED_REPORT:
   2350                 return "RESIZED_REPORT";
   2351             case WINDOW_FOCUS_CHANGED:
   2352                 return "WINDOW_FOCUS_CHANGED";
   2353             case DISPATCH_KEY:
   2354                 return "DISPATCH_KEY";
   2355             case DISPATCH_POINTER:
   2356                 return "DISPATCH_POINTER";
   2357             case DISPATCH_TRACKBALL:
   2358                 return "DISPATCH_TRACKBALL";
   2359             case DISPATCH_APP_VISIBILITY:
   2360                 return "DISPATCH_APP_VISIBILITY";
   2361             case DISPATCH_GET_NEW_SURFACE:
   2362                 return "DISPATCH_GET_NEW_SURFACE";
   2363             case FINISHED_EVENT:
   2364                 return "FINISHED_EVENT";
   2365             case DISPATCH_KEY_FROM_IME:
   2366                 return "DISPATCH_KEY_FROM_IME";
   2367             case FINISH_INPUT_CONNECTION:
   2368                 return "FINISH_INPUT_CONNECTION";
   2369             case CHECK_FOCUS:
   2370                 return "CHECK_FOCUS";
   2371             case CLOSE_SYSTEM_DIALOGS:
   2372                 return "CLOSE_SYSTEM_DIALOGS";
   2373             case DISPATCH_DRAG_EVENT:
   2374                 return "DISPATCH_DRAG_EVENT";
   2375             case DISPATCH_DRAG_LOCATION_EVENT:
   2376                 return "DISPATCH_DRAG_LOCATION_EVENT";
   2377             case DISPATCH_SYSTEM_UI_VISIBILITY:
   2378                 return "DISPATCH_SYSTEM_UI_VISIBILITY";
   2379             case DISPATCH_GENERIC_MOTION:
   2380                 return "DISPATCH_GENERIC_MOTION";
   2381             case UPDATE_CONFIGURATION:
   2382                 return "UPDATE_CONFIGURATION";
   2383             case DO_PERFORM_ACCESSIBILITY_ACTION:
   2384                 return "DO_PERFORM_ACCESSIBILITY_ACTION";
   2385             case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
   2386                 return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
   2387             case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID:
   2388                 return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
   2389             case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT:
   2390                 return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT";
   2391 
   2392         }
   2393         return super.getMessageName(message);
   2394     }
   2395 
   2396     @Override
   2397     public void handleMessage(Message msg) {
   2398         switch (msg.what) {
   2399         case View.AttachInfo.INVALIDATE_MSG:
   2400             ((View) msg.obj).invalidate();
   2401             break;
   2402         case View.AttachInfo.INVALIDATE_RECT_MSG:
   2403             final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
   2404             info.target.invalidate(info.left, info.top, info.right, info.bottom);
   2405             info.release();
   2406             break;
   2407         case DO_TRAVERSAL:
   2408             if (mProfile) {
   2409                 Debug.startMethodTracing("ViewAncestor");
   2410             }
   2411 
   2412             final long traversalStartTime;
   2413             if (ViewDebug.DEBUG_LATENCY) {
   2414                 traversalStartTime = System.nanoTime();
   2415                 mLastDrawDurationNanos = 0;
   2416             }
   2417 
   2418             performTraversals();
   2419 
   2420             if (ViewDebug.DEBUG_LATENCY) {
   2421                 long now = System.nanoTime();
   2422                 Log.d(TAG, "Latency: Spent "
   2423                         + ((now - traversalStartTime) * 0.000001f)
   2424                         + "ms in performTraversals(), with "
   2425                         + (mLastDrawDurationNanos * 0.000001f)
   2426                         + "ms of that time in draw()");
   2427                 mLastTraversalFinishedTimeNanos = now;
   2428             }
   2429 
   2430             if (mProfile) {
   2431                 Debug.stopMethodTracing();
   2432                 mProfile = false;
   2433             }
   2434             break;
   2435         case FINISHED_EVENT:
   2436             handleFinishedEvent(msg.arg1, msg.arg2 != 0);
   2437             break;
   2438         case DISPATCH_KEY:
   2439             deliverKeyEvent((KeyEvent)msg.obj, msg.arg1 != 0);
   2440             break;
   2441         case DISPATCH_POINTER:
   2442             deliverPointerEvent((MotionEvent) msg.obj, msg.arg1 != 0);
   2443             break;
   2444         case DISPATCH_TRACKBALL:
   2445             deliverTrackballEvent((MotionEvent) msg.obj, msg.arg1 != 0);
   2446             break;
   2447         case DISPATCH_GENERIC_MOTION:
   2448             deliverGenericMotionEvent((MotionEvent) msg.obj, msg.arg1 != 0);
   2449             break;
   2450         case DISPATCH_APP_VISIBILITY:
   2451             handleAppVisibility(msg.arg1 != 0);
   2452             break;
   2453         case DISPATCH_GET_NEW_SURFACE:
   2454             handleGetNewSurface();
   2455             break;
   2456         case RESIZED:
   2457             ResizedInfo ri = (ResizedInfo)msg.obj;
   2458 
   2459             if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
   2460                     && mPendingContentInsets.equals(ri.coveredInsets)
   2461                     && mPendingVisibleInsets.equals(ri.visibleInsets)
   2462                     && ((ResizedInfo)msg.obj).newConfig == null) {
   2463                 break;
   2464             }
   2465             // fall through...
   2466         case RESIZED_REPORT:
   2467             if (mAdded) {
   2468                 Configuration config = ((ResizedInfo)msg.obj).newConfig;
   2469                 if (config != null) {
   2470                     updateConfiguration(config, false);
   2471                 }
   2472                 mWinFrame.left = 0;
   2473                 mWinFrame.right = msg.arg1;
   2474                 mWinFrame.top = 0;
   2475                 mWinFrame.bottom = msg.arg2;
   2476                 mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
   2477                 mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
   2478                 if (msg.what == RESIZED_REPORT) {
   2479                     mReportNextDraw = true;
   2480                 }
   2481 
   2482                 if (mView != null) {
   2483                     forceLayout(mView);
   2484                 }
   2485                 requestLayout();
   2486             }
   2487             break;
   2488         case WINDOW_FOCUS_CHANGED: {
   2489             if (mAdded) {
   2490                 boolean hasWindowFocus = msg.arg1 != 0;
   2491                 mAttachInfo.mHasWindowFocus = hasWindowFocus;
   2492 
   2493                 profileRendering(hasWindowFocus);
   2494 
   2495                 if (hasWindowFocus) {
   2496                     boolean inTouchMode = msg.arg2 != 0;
   2497                     ensureTouchModeLocally(inTouchMode);
   2498 
   2499                     if (mAttachInfo.mHardwareRenderer != null &&
   2500                             mSurface != null && mSurface.isValid()) {
   2501                         mFullRedrawNeeded = true;
   2502                         try {
   2503                             mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
   2504                                     mAttachInfo, mHolder);
   2505                         } catch (Surface.OutOfResourcesException e) {
   2506                             Log.e(TAG, "OutOfResourcesException locking surface", e);
   2507                             try {
   2508                                 if (!sWindowSession.outOfMemory(mWindow)) {
   2509                                     Slog.w(TAG, "No processes killed for memory; killing self");
   2510                                     Process.killProcess(Process.myPid());
   2511                                 }
   2512                             } catch (RemoteException ex) {
   2513                             }
   2514                             // Retry in a bit.
   2515                             sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
   2516                             return;
   2517                         }
   2518                     }
   2519                 }
   2520 
   2521                 mLastWasImTarget = WindowManager.LayoutParams
   2522                         .mayUseInputMethod(mWindowAttributes.flags);
   2523 
   2524                 InputMethodManager imm = InputMethodManager.peekInstance();
   2525                 if (mView != null) {
   2526                     if (hasWindowFocus && imm != null && mLastWasImTarget) {
   2527                         imm.startGettingWindowFocus(mView);
   2528                     }
   2529                     mAttachInfo.mKeyDispatchState.reset();
   2530                     mView.dispatchWindowFocusChanged(hasWindowFocus);
   2531                 }
   2532 
   2533                 // Note: must be done after the focus change callbacks,
   2534                 // so all of the view state is set up correctly.
   2535                 if (hasWindowFocus) {
   2536                     if (imm != null && mLastWasImTarget) {
   2537                         imm.onWindowFocus(mView, mView.findFocus(),
   2538                                 mWindowAttributes.softInputMode,
   2539                                 !mHasHadWindowFocus, mWindowAttributes.flags);
   2540                     }
   2541                     // Clear the forward bit.  We can just do this directly, since
   2542                     // the window manager doesn't care about it.
   2543                     mWindowAttributes.softInputMode &=
   2544                             ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
   2545                     ((WindowManager.LayoutParams)mView.getLayoutParams())
   2546                             .softInputMode &=
   2547                                 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
   2548                     mHasHadWindowFocus = true;
   2549                 }
   2550 
   2551                 if (hasWindowFocus && mView != null) {
   2552                     sendAccessibilityEvents();
   2553                 }
   2554             }
   2555         } break;
   2556         case DIE:
   2557             doDie();
   2558             break;
   2559         case DISPATCH_KEY_FROM_IME: {
   2560             if (LOCAL_LOGV) Log.v(
   2561                 TAG, "Dispatching key "
   2562                 + msg.obj + " from IME to " + mView);
   2563             KeyEvent event = (KeyEvent)msg.obj;
   2564             if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
   2565                 // The IME is trying to say this event is from the
   2566                 // system!  Bad bad bad!
   2567                 //noinspection UnusedAssignment
   2568                 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
   2569             }
   2570             deliverKeyEventPostIme((KeyEvent)msg.obj, false);
   2571         } break;
   2572         case FINISH_INPUT_CONNECTION: {
   2573             InputMethodManager imm = InputMethodManager.peekInstance();
   2574             if (imm != null) {
   2575                 imm.reportFinishInputConnection((InputConnection)msg.obj);
   2576             }
   2577         } break;
   2578         case CHECK_FOCUS: {
   2579             InputMethodManager imm = InputMethodManager.peekInstance();
   2580             if (imm != null) {
   2581                 imm.checkFocus();
   2582             }
   2583         } break;
   2584         case CLOSE_SYSTEM_DIALOGS: {
   2585             if (mView != null) {
   2586                 mView.onCloseSystemDialogs((String)msg.obj);
   2587             }
   2588         } break;
   2589         case DISPATCH_DRAG_EVENT:
   2590         case DISPATCH_DRAG_LOCATION_EVENT: {
   2591             DragEvent event = (DragEvent)msg.obj;
   2592             event.mLocalState = mLocalDragState;    // only present when this app called startDrag()
   2593             handleDragEvent(event);
   2594         } break;
   2595         case DISPATCH_SYSTEM_UI_VISIBILITY: {
   2596             handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj);
   2597         } break;
   2598         case UPDATE_CONFIGURATION: {
   2599             Configuration config = (Configuration)msg.obj;
   2600             if (config.isOtherSeqNewer(mLastConfiguration)) {
   2601                 config = mLastConfiguration;
   2602             }
   2603             updateConfiguration(config, false);
   2604         } break;
   2605         case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
   2606             if (mView != null) {
   2607                 getAccessibilityInteractionController()
   2608                     .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg);
   2609             }
   2610         } break;
   2611         case DO_PERFORM_ACCESSIBILITY_ACTION: {
   2612             if (mView != null) {
   2613                 getAccessibilityInteractionController()
   2614                     .perfromAccessibilityActionUiThread(msg);
   2615             }
   2616         } break;
   2617         case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: {
   2618             if (mView != null) {
   2619                 getAccessibilityInteractionController()
   2620                     .findAccessibilityNodeInfoByViewIdUiThread(msg);
   2621             }
   2622         } break;
   2623         case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT: {
   2624             if (mView != null) {
   2625                 getAccessibilityInteractionController()
   2626                     .findAccessibilityNodeInfosByViewTextUiThread(msg);
   2627             }
   2628         } break;
   2629         }
   2630     }
   2631 
   2632     private void startInputEvent(InputQueue.FinishedCallback finishedCallback) {
   2633         if (mFinishedCallback != null) {
   2634             Slog.w(TAG, "Received a new input event from the input queue but there is "
   2635                     + "already an unfinished input event in progress.");
   2636         }
   2637 
   2638         if (ViewDebug.DEBUG_LATENCY) {
   2639             mInputEventReceiveTimeNanos = System.nanoTime();
   2640             mInputEventDeliverTimeNanos = 0;
   2641             mInputEventDeliverPostImeTimeNanos = 0;
   2642         }
   2643 
   2644         mFinishedCallback = finishedCallback;
   2645     }
   2646 
   2647     private void finishInputEvent(InputEvent event, boolean handled) {
   2648         if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished");
   2649 
   2650         if (mFinishedCallback == null) {
   2651             Slog.w(TAG, "Attempted to tell the input queue that the current input event "
   2652                     + "is finished but there is no input event actually in progress.");
   2653             return;
   2654         }
   2655 
   2656         if (ViewDebug.DEBUG_LATENCY) {
   2657             final long now = System.nanoTime();
   2658             final long eventTime = event.getEventTimeNano();
   2659             final StringBuilder msg = new StringBuilder();
   2660             msg.append("Latency: Spent ");
   2661             msg.append((now - mInputEventReceiveTimeNanos) * 0.000001f);
   2662             msg.append("ms processing ");
   2663             if (event instanceof KeyEvent) {
   2664                 final KeyEvent  keyEvent = (KeyEvent)event;
   2665                 msg.append("key event, action=");
   2666                 msg.append(KeyEvent.actionToString(keyEvent.getAction()));
   2667             } else {
   2668                 final MotionEvent motionEvent = (MotionEvent)event;
   2669                 msg.append("motion event, action=");
   2670                 msg.append(MotionEvent.actionToString(motionEvent.getAction()));
   2671                 msg.append(", historySize=");
   2672                 msg.append(motionEvent.getHistorySize());
   2673             }
   2674             msg.append(", handled=");
   2675             msg.append(handled);
   2676             msg.append(", received at +");
   2677             msg.append((mInputEventReceiveTimeNanos - eventTime) * 0.000001f);
   2678             if (mInputEventDeliverTimeNanos != 0) {
   2679                 msg.append("ms, delivered at +");
   2680                 msg.append((mInputEventDeliverTimeNanos - eventTime) * 0.000001f);
   2681             }
   2682             if (mInputEventDeliverPostImeTimeNanos != 0) {
   2683                 msg.append("ms, delivered post IME at +");
   2684                 msg.append((mInputEventDeliverPostImeTimeNanos - eventTime) * 0.000001f);
   2685             }
   2686             msg.append("ms, finished at +");
   2687             msg.append((now - eventTime) * 0.000001f);
   2688             msg.append("ms.");
   2689             Log.d(TAG, msg.toString());
   2690         }
   2691 
   2692         mFinishedCallback.finished(handled);
   2693         mFinishedCallback = null;
   2694     }
   2695 
   2696     /**
   2697      * Something in the current window tells us we need to change the touch mode.  For
   2698      * example, we are not in touch mode, and the user touches the screen.
   2699      *
   2700      * If the touch mode has changed, tell the window manager, and handle it locally.
   2701      *
   2702      * @param inTouchMode Whether we want to be in touch mode.
   2703      * @return True if the touch mode changed and focus changed was changed as a result
   2704      */
   2705     boolean ensureTouchMode(boolean inTouchMode) {
   2706         if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
   2707                 + "touch mode is " + mAttachInfo.mInTouchMode);
   2708         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
   2709 
   2710         // tell the window manager
   2711         try {
   2712             sWindowSession.setInTouchMode(inTouchMode);
   2713         } catch (RemoteException e) {
   2714             throw new RuntimeException(e);
   2715         }
   2716 
   2717         // handle the change
   2718         return ensureTouchModeLocally(inTouchMode);
   2719     }
   2720 
   2721     /**
   2722      * Ensure that the touch mode for this window is set, and if it is changing,
   2723      * take the appropriate action.
   2724      * @param inTouchMode Whether we want to be in touch mode.
   2725      * @return True if the touch mode changed and focus changed was changed as a result
   2726      */
   2727     private boolean ensureTouchModeLocally(boolean inTouchMode) {
   2728         if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
   2729                 + "touch mode is " + mAttachInfo.mInTouchMode);
   2730 
   2731         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
   2732 
   2733         mAttachInfo.mInTouchMode = inTouchMode;
   2734         mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
   2735 
   2736         return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
   2737     }
   2738 
   2739     private boolean enterTouchMode() {
   2740         if (mView != null) {
   2741             if (mView.hasFocus()) {
   2742                 // note: not relying on mFocusedView here because this could
   2743                 // be when the window is first being added, and mFocused isn't
   2744                 // set yet.
   2745                 final View focused = mView.findFocus();
   2746                 if (focused != null && !focused.isFocusableInTouchMode()) {
   2747 
   2748                     final ViewGroup ancestorToTakeFocus =
   2749                             findAncestorToTakeFocusInTouchMode(focused);
   2750                     if (ancestorToTakeFocus != null) {
   2751                         // there is an ancestor that wants focus after its descendants that
   2752                         // is focusable in touch mode.. give it focus
   2753                         return ancestorToTakeFocus.requestFocus();
   2754                     } else {
   2755                         // nothing appropriate to have focus in touch mode, clear it out
   2756                         mView.unFocus();
   2757                         mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
   2758                         mFocusedView = null;
   2759                         return true;
   2760                     }
   2761                 }
   2762             }
   2763         }
   2764         return false;
   2765     }
   2766 
   2767 
   2768     /**
   2769      * Find an ancestor of focused that wants focus after its descendants and is
   2770      * focusable in touch mode.
   2771      * @param focused The currently focused view.
   2772      * @return An appropriate view, or null if no such view exists.
   2773      */
   2774     private ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
   2775         ViewParent parent = focused.getParent();
   2776         while (parent instanceof ViewGroup) {
   2777             final ViewGroup vgParent = (ViewGroup) parent;
   2778             if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
   2779                     && vgParent.isFocusableInTouchMode()) {
   2780                 return vgParent;
   2781             }
   2782             if (vgParent.isRootNamespace()) {
   2783                 return null;
   2784             } else {
   2785                 parent = vgParent.getParent();
   2786             }
   2787         }
   2788         return null;
   2789     }
   2790 
   2791     private boolean leaveTouchMode() {
   2792         if (mView != null) {
   2793             if (mView.hasFocus()) {
   2794                 // i learned the hard way to not trust mFocusedView :)
   2795                 mFocusedView = mView.findFocus();
   2796                 if (!(mFocusedView instanceof ViewGroup)) {
   2797                     // some view has focus, let it keep it
   2798                     return false;
   2799                 } else if (((ViewGroup)mFocusedView).getDescendantFocusability() !=
   2800                         ViewGroup.FOCUS_AFTER_DESCENDANTS) {
   2801                     // some view group has focus, and doesn't prefer its children
   2802                     // over itself for focus, so let them keep it.
   2803                     return false;
   2804                 }
   2805             }
   2806 
   2807             // find the best view to give focus to in this brave new non-touch-mode
   2808             // world
   2809             final View focused = focusSearch(null, View.FOCUS_DOWN);
   2810             if (focused != null) {
   2811                 return focused.requestFocus(View.FOCUS_DOWN);
   2812             }
   2813         }
   2814         return false;
   2815     }
   2816 
   2817     private void deliverPointerEvent(MotionEvent event, boolean sendDone) {
   2818         if (ViewDebug.DEBUG_LATENCY) {
   2819             mInputEventDeliverTimeNanos = System.nanoTime();
   2820         }
   2821 
   2822         final boolean isTouchEvent = event.isTouchEvent();
   2823         if (mInputEventConsistencyVerifier != null) {
   2824             if (isTouchEvent) {
   2825                 mInputEventConsistencyVerifier.onTouchEvent(event, 0);
   2826             } else {
   2827                 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
   2828             }
   2829         }
   2830 
   2831         // If there is no view, then the event will not be handled.
   2832         if (mView == null || !mAdded) {
   2833             finishMotionEvent(event, sendDone, false);
   2834             return;
   2835         }
   2836 
   2837         // Translate the pointer event for compatibility, if needed.
   2838         if (mTranslator != null) {
   2839             mTranslator.translateEventInScreenToAppWindow(event);
   2840         }
   2841 
   2842         // Enter touch mode on down or scroll.
   2843         final int action = event.getAction();
   2844         if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
   2845             ensureTouchMode(true);
   2846         }
   2847 
   2848         // Offset the scroll position.
   2849         if (mCurScrollY != 0) {
   2850             event.offsetLocation(0, mCurScrollY);
   2851         }
   2852         if (MEASURE_LATENCY) {
   2853             lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano());
   2854         }
   2855 
   2856         // Remember the touch position for possible drag-initiation.
   2857         if (isTouchEvent) {
   2858             mLastTouchPoint.x = event.getRawX();
   2859             mLastTouchPoint.y = event.getRawY();
   2860         }
   2861 
   2862         // Dispatch touch to view hierarchy.
   2863         boolean handled = mView.dispatchPointerEvent(event);
   2864         if (MEASURE_LATENCY) {
   2865             lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano());
   2866         }
   2867         if (handled) {
   2868             finishMotionEvent(event, sendDone, true);
   2869             return;
   2870         }
   2871 
   2872         // Pointer event was unhandled.
   2873         finishMotionEvent(event, sendDone, false);
   2874     }
   2875 
   2876     private void finishMotionEvent(MotionEvent event, boolean sendDone, boolean handled) {
   2877         event.recycle();
   2878         if (sendDone) {
   2879             finishInputEvent(event, handled);
   2880         }
   2881         //noinspection ConstantConditions
   2882         if (LOCAL_LOGV || WATCH_POINTER) {
   2883             if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
   2884                 Log.i(TAG, "Done dispatching!");
   2885             }
   2886         }
   2887     }
   2888 
   2889     private void deliverTrackballEvent(MotionEvent event, boolean sendDone) {
   2890         if (ViewDebug.DEBUG_LATENCY) {
   2891             mInputEventDeliverTimeNanos = System.nanoTime();
   2892         }
   2893 
   2894         if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
   2895 
   2896         if (mInputEventConsistencyVerifier != null) {
   2897             mInputEventConsistencyVerifier.onTrackballEvent(event, 0);
   2898         }
   2899 
   2900         // If there is no view, then the event will not be handled.
   2901         if (mView == null || !mAdded) {
   2902             finishMotionEvent(event, sendDone, false);
   2903             return;
   2904         }
   2905 
   2906         // Deliver the trackball event to the view.
   2907         if (mView.dispatchTrackballEvent(event)) {
   2908             // If we reach this, we delivered a trackball event to mView and
   2909             // mView consumed it. Because we will not translate the trackball
   2910             // event into a key event, touch mode will not exit, so we exit
   2911             // touch mode here.
   2912             ensureTouchMode(false);
   2913 
   2914             finishMotionEvent(event, sendDone, true);
   2915             mLastTrackballTime = Integer.MIN_VALUE;
   2916             return;
   2917         }
   2918 
   2919         // Translate the trackball event into DPAD keys and try to deliver those.
   2920         final TrackballAxis x = mTrackballAxisX;
   2921         final TrackballAxis y = mTrackballAxisY;
   2922 
   2923         long curTime = SystemClock.uptimeMillis();
   2924         if ((mLastTrackballTime + MAX_TRACKBALL_DELAY) < curTime) {
   2925             // It has been too long since the last movement,
   2926             // so restart at the beginning.
   2927             x.reset(0);
   2928             y.reset(0);
   2929             mLastTrackballTime = curTime;
   2930         }
   2931 
   2932         final int action = event.getAction();
   2933         final int metaState = event.getMetaState();
   2934         switch (action) {
   2935             case MotionEvent.ACTION_DOWN:
   2936                 x.reset(2);
   2937                 y.reset(2);
   2938                 deliverKeyEvent(new KeyEvent(curTime, curTime,
   2939                         KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
   2940                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   2941                         InputDevice.SOURCE_KEYBOARD), false);
   2942                 break;
   2943             case MotionEvent.ACTION_UP:
   2944                 x.reset(2);
   2945                 y.reset(2);
   2946                 deliverKeyEvent(new KeyEvent(curTime, curTime,
   2947                         KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
   2948                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   2949                         InputDevice.SOURCE_KEYBOARD), false);
   2950                 break;
   2951         }
   2952 
   2953         if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
   2954                 + x.step + " dir=" + x.dir + " acc=" + x.acceleration
   2955                 + " move=" + event.getX()
   2956                 + " / Y=" + y.position + " step="
   2957                 + y.step + " dir=" + y.dir + " acc=" + y.acceleration
   2958                 + " move=" + event.getY());
   2959         final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
   2960         final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
   2961 
   2962         // Generate DPAD events based on the trackball movement.
   2963         // We pick the axis that has moved the most as the direction of
   2964         // the DPAD.  When we generate DPAD events for one axis, then the
   2965         // other axis is reset -- we don't want to perform DPAD jumps due
   2966         // to slight movements in the trackball when making major movements
   2967         // along the other axis.
   2968         int keycode = 0;
   2969         int movement = 0;
   2970         float accel = 1;
   2971         if (xOff > yOff) {
   2972             movement = x.generate((2/event.getXPrecision()));
   2973             if (movement != 0) {
   2974                 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
   2975                         : KeyEvent.KEYCODE_DPAD_LEFT;
   2976                 accel = x.acceleration;
   2977                 y.reset(2);
   2978             }
   2979         } else if (yOff > 0) {
   2980             movement = y.generate((2/event.getYPrecision()));
   2981             if (movement != 0) {
   2982                 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
   2983                         : KeyEvent.KEYCODE_DPAD_UP;
   2984                 accel = y.acceleration;
   2985                 x.reset(2);
   2986             }
   2987         }
   2988 
   2989         if (keycode != 0) {
   2990             if (movement < 0) movement = -movement;
   2991             int accelMovement = (int)(movement * accel);
   2992             if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
   2993                     + " accelMovement=" + accelMovement
   2994                     + " accel=" + accel);
   2995             if (accelMovement > movement) {
   2996                 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
   2997                         + keycode);
   2998                 movement--;
   2999                 int repeatCount = accelMovement - movement;
   3000                 deliverKeyEvent(new KeyEvent(curTime, curTime,
   3001                         KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
   3002                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   3003                         InputDevice.SOURCE_KEYBOARD), false);
   3004             }
   3005             while (movement > 0) {
   3006                 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
   3007                         + keycode);
   3008                 movement--;
   3009                 curTime = SystemClock.uptimeMillis();
   3010                 deliverKeyEvent(new KeyEvent(curTime, curTime,
   3011                         KeyEvent.ACTION_DOWN, keycode, 0, metaState,
   3012                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   3013                         InputDevice.SOURCE_KEYBOARD), false);
   3014                 deliverKeyEvent(new KeyEvent(curTime, curTime,
   3015                         KeyEvent.ACTION_UP, keycode, 0, metaState,
   3016                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   3017                         InputDevice.SOURCE_KEYBOARD), false);
   3018                 }
   3019             mLastTrackballTime = curTime;
   3020         }
   3021 
   3022         // Unfortunately we can't tell whether the application consumed the keys, so
   3023         // we always consider the trackball event handled.
   3024         finishMotionEvent(event, sendDone, true);
   3025     }
   3026 
   3027     private void deliverGenericMotionEvent(MotionEvent event, boolean sendDone) {
   3028         if (ViewDebug.DEBUG_LATENCY) {
   3029             mInputEventDeliverTimeNanos = System.nanoTime();
   3030         }
   3031 
   3032         if (mInputEventConsistencyVerifier != null) {
   3033             mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
   3034         }
   3035 
   3036         final int source = event.getSource();
   3037         final boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0;
   3038 
   3039         // If there is no view, then the event will not be handled.
   3040         if (mView == null || !mAdded) {
   3041             if (isJoystick) {
   3042                 updateJoystickDirection(event, false);
   3043             }
   3044             finishMotionEvent(event, sendDone, false);
   3045             return;
   3046         }
   3047 
   3048         // Deliver the event to the view.
   3049         if (mView.dispatchGenericMotionEvent(event)) {
   3050             if (isJoystick) {
   3051                 updateJoystickDirection(event, false);
   3052             }
   3053             finishMotionEvent(event, sendDone, true);
   3054             return;
   3055         }
   3056 
   3057         if (isJoystick) {
   3058             // Translate the joystick event into DPAD keys and try to deliver those.
   3059             updateJoystickDirection(event, true);
   3060             finishMotionEvent(event, sendDone, true);
   3061         } else {
   3062             finishMotionEvent(event, sendDone, false);
   3063         }
   3064     }
   3065 
   3066     private void updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys) {
   3067         final long time = event.getEventTime();
   3068         final int metaState = event.getMetaState();
   3069         final int deviceId = event.getDeviceId();
   3070         final int source = event.getSource();
   3071 
   3072         int xDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_X));
   3073         if (xDirection == 0) {
   3074             xDirection = joystickAxisValueToDirection(event.getX());
   3075         }
   3076 
   3077         int yDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_Y));
   3078         if (yDirection == 0) {
   3079             yDirection = joystickAxisValueToDirection(event.getY());
   3080         }
   3081 
   3082         if (xDirection != mLastJoystickXDirection) {
   3083             if (mLastJoystickXKeyCode != 0) {
   3084                 deliverKeyEvent(new KeyEvent(time, time,
   3085                         KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState,
   3086                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
   3087                 mLastJoystickXKeyCode = 0;
   3088             }
   3089 
   3090             mLastJoystickXDirection = xDirection;
   3091 
   3092             if (xDirection != 0 && synthesizeNewKeys) {
   3093                 mLastJoystickXKeyCode = xDirection > 0
   3094                         ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
   3095                 deliverKeyEvent(new KeyEvent(time, time,
   3096                         KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState,
   3097                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
   3098             }
   3099         }
   3100 
   3101         if (yDirection != mLastJoystickYDirection) {
   3102             if (mLastJoystickYKeyCode != 0) {
   3103                 deliverKeyEvent(new KeyEvent(time, time,
   3104                         KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState,
   3105                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
   3106                 mLastJoystickYKeyCode = 0;
   3107             }
   3108 
   3109             mLastJoystickYDirection = yDirection;
   3110 
   3111             if (yDirection != 0 && synthesizeNewKeys) {
   3112                 mLastJoystickYKeyCode = yDirection > 0
   3113                         ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
   3114                 deliverKeyEvent(new KeyEvent(time, time,
   3115                         KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState,
   3116                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
   3117             }
   3118         }
   3119     }
   3120 
   3121     private static int joystickAxisValueToDirection(float value) {
   3122         if (value >= 0.5f) {
   3123             return 1;
   3124         } else if (value <= -0.5f) {
   3125             return -1;
   3126         } else {
   3127             return 0;
   3128         }
   3129     }
   3130 
   3131     /**
   3132      * Returns true if the key is used for keyboard navigation.
   3133      * @param keyEvent The key event.
   3134      * @return True if the key is used for keyboard navigation.
   3135      */
   3136     private static boolean isNavigationKey(KeyEvent keyEvent) {
   3137         switch (keyEvent.getKeyCode()) {
   3138         case KeyEvent.KEYCODE_DPAD_LEFT:
   3139         case KeyEvent.KEYCODE_DPAD_RIGHT:
   3140         case KeyEvent.KEYCODE_DPAD_UP:
   3141         case KeyEvent.KEYCODE_DPAD_DOWN:
   3142         case KeyEvent.KEYCODE_DPAD_CENTER:
   3143         case KeyEvent.KEYCODE_PAGE_UP:
   3144         case KeyEvent.KEYCODE_PAGE_DOWN:
   3145         case KeyEvent.KEYCODE_MOVE_HOME:
   3146         case KeyEvent.KEYCODE_MOVE_END:
   3147         case KeyEvent.KEYCODE_TAB:
   3148         case KeyEvent.KEYCODE_SPACE:
   3149         case KeyEvent.KEYCODE_ENTER:
   3150             return true;
   3151         }
   3152         return false;
   3153     }
   3154 
   3155     /**
   3156      * Returns true if the key is used for typing.
   3157      * @param keyEvent The key event.
   3158      * @return True if the key is used for typing.
   3159      */
   3160     private static boolean isTypingKey(KeyEvent keyEvent) {
   3161         return keyEvent.getUnicodeChar() > 0;
   3162     }
   3163 
   3164     /**
   3165      * See if the key event means we should leave touch mode (and leave touch mode if so).
   3166      * @param event The key event.
   3167      * @return Whether this key event should be consumed (meaning the act of
   3168      *   leaving touch mode alone is considered the event).
   3169      */
   3170     private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
   3171         // Only relevant in touch mode.
   3172         if (!mAttachInfo.mInTouchMode) {
   3173             return false;
   3174         }
   3175 
   3176         // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
   3177         final int action = event.getAction();
   3178         if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
   3179             return false;
   3180         }
   3181 
   3182         // Don't leave touch mode if the IME told us not to.
   3183         if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
   3184             return false;
   3185         }
   3186 
   3187         // If the key can be used for keyboard navigation then leave touch mode
   3188         // and select a focused view if needed (in ensureTouchMode).
   3189         // When a new focused view is selected, we consume the navigation key because
   3190         // navigation doesn't make much sense unless a view already has focus so
   3191         // the key's purpose is to set focus.
   3192         if (isNavigationKey(event)) {
   3193             return ensureTouchMode(false);
   3194         }
   3195 
   3196         // If the key can be used for typing then leave touch mode
   3197         // and select a focused view if needed (in ensureTouchMode).
   3198         // Always allow the view to process the typing key.
   3199         if (isTypingKey(event)) {
   3200             ensureTouchMode(false);
   3201             return false;
   3202         }
   3203 
   3204         return false;
   3205     }
   3206 
   3207     int enqueuePendingEvent(Object event, boolean sendDone) {
   3208         int seq = mPendingEventSeq+1;
   3209         if (seq < 0) seq = 0;
   3210         mPendingEventSeq = seq;
   3211         mPendingEvents.put(seq, event);
   3212         return sendDone ? seq : -seq;
   3213     }
   3214 
   3215     Object retrievePendingEvent(int seq) {
   3216         if (seq < 0) seq = -seq;
   3217         Object event = mPendingEvents.get(seq);
   3218         if (event != null) {
   3219             mPendingEvents.remove(seq);
   3220         }
   3221         return event;
   3222     }
   3223 
   3224     private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
   3225         if (ViewDebug.DEBUG_LATENCY) {
   3226             mInputEventDeliverTimeNanos = System.nanoTime();
   3227         }
   3228 
   3229         if (mInputEventConsistencyVerifier != null) {
   3230             mInputEventConsistencyVerifier.onKeyEvent(event, 0);
   3231         }
   3232 
   3233         // If there is no view, then the event will not be handled.
   3234         if (mView == null || !mAdded) {
   3235             finishKeyEvent(event, sendDone, false);
   3236             return;
   3237         }
   3238 
   3239         if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
   3240 
   3241         // Perform predispatching before the IME.
   3242         if (mView.dispatchKeyEventPreIme(event)) {
   3243             finishKeyEvent(event, sendDone, true);
   3244             return;
   3245         }
   3246 
   3247         // Dispatch to the IME before propagating down the view hierarchy.
   3248         // The IME will eventually call back into handleFinishedEvent.
   3249         if (mLastWasImTarget) {
   3250             InputMethodManager imm = InputMethodManager.peekInstance();
   3251             if (imm != null) {
   3252                 int seq = enqueuePendingEvent(event, sendDone);
   3253                 if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
   3254                         + seq + " event=" + event);
   3255                 imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
   3256                 return;
   3257             }
   3258         }
   3259 
   3260         // Not dispatching to IME, continue with post IME actions.
   3261         deliverKeyEventPostIme(event, sendDone);
   3262     }
   3263 
   3264     private void handleFinishedEvent(int seq, boolean handled) {
   3265         final KeyEvent event = (KeyEvent)retrievePendingEvent(seq);
   3266         if (DEBUG_IMF) Log.v(TAG, "IME finished event: seq=" + seq
   3267                 + " handled=" + handled + " event=" + event);
   3268         if (event != null) {
   3269             final boolean sendDone = seq >= 0;
   3270             if (handled) {
   3271                 finishKeyEvent(event, sendDone, true);
   3272             } else {
   3273                 deliverKeyEventPostIme(event, sendDone);
   3274             }
   3275         }
   3276     }
   3277 
   3278     private void deliverKeyEventPostIme(KeyEvent event, boolean sendDone) {
   3279         if (ViewDebug.DEBUG_LATENCY) {
   3280             mInputEventDeliverPostImeTimeNanos = System.nanoTime();
   3281         }
   3282 
   3283         // If the view went away, then the event will not be handled.
   3284         if (mView == null || !mAdded) {
   3285             finishKeyEvent(event, sendDone, false);
   3286             return;
   3287         }
   3288 
   3289         // If the key's purpose is to exit touch mode then we consume it and consider it handled.
   3290         if (checkForLeavingTouchModeAndConsume(event)) {
   3291             finishKeyEvent(event, sendDone, true);
   3292             return;
   3293         }
   3294 
   3295         // Make sure the fallback event policy sees all keys that will be delivered to the
   3296         // view hierarchy.
   3297         mFallbackEventHandler.preDispatchKeyEvent(event);
   3298 
   3299         // Deliver the key to the view hierarchy.
   3300         if (mView.dispatchKeyEvent(event)) {
   3301             finishKeyEvent(event, sendDone, true);
   3302             return;
   3303         }
   3304 
   3305         // If the Control modifier is held, try to interpret the key as a shortcut.
   3306         if (event.getAction() == KeyEvent.ACTION_UP
   3307                 && event.isCtrlPressed()
   3308                 && !KeyEvent.isModifierKey(event.getKeyCode())) {
   3309             if (mView.dispatchKeyShortcutEvent(event)) {
   3310                 finishKeyEvent(event, sendDone, true);
   3311                 return;
   3312             }
   3313         }
   3314 
   3315         // Apply the fallback event policy.
   3316         if (mFallbackEventHandler.dispatchKeyEvent(event)) {
   3317             finishKeyEvent(event, sendDone, true);
   3318             return;
   3319         }
   3320 
   3321         // Handle automatic focus changes.
   3322         if (event.getAction() == KeyEvent.ACTION_DOWN) {
   3323             int direction = 0;
   3324             switch (event.getKeyCode()) {
   3325             case KeyEvent.KEYCODE_DPAD_LEFT:
   3326                 if (event.hasNoModifiers()) {
   3327                     direction = View.FOCUS_LEFT;
   3328                 }
   3329                 break;
   3330             case KeyEvent.KEYCODE_DPAD_RIGHT:
   3331                 if (event.hasNoModifiers()) {
   3332                     direction = View.FOCUS_RIGHT;
   3333                 }
   3334                 break;
   3335             case KeyEvent.KEYCODE_DPAD_UP:
   3336                 if (event.hasNoModifiers()) {
   3337                     direction = View.FOCUS_UP;
   3338                 }
   3339                 break;
   3340             case KeyEvent.KEYCODE_DPAD_DOWN:
   3341                 if (event.hasNoModifiers()) {
   3342                     direction = View.FOCUS_DOWN;
   3343                 }
   3344                 break;
   3345             case KeyEvent.KEYCODE_TAB:
   3346                 if (event.hasNoModifiers()) {
   3347                     direction = View.FOCUS_FORWARD;
   3348                 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
   3349                     direction = View.FOCUS_BACKWARD;
   3350                 }
   3351                 break;
   3352             }
   3353 
   3354             if (direction != 0) {
   3355                 View focused = mView != null ? mView.findFocus() : null;
   3356                 if (focused != null) {
   3357                     View v = focused.focusSearch(direction);
   3358                     if (v != null && v != focused) {
   3359                         // do the math the get the interesting rect
   3360                         // of previous focused into the coord system of
   3361                         // newly focused view
   3362                         focused.getFocusedRect(mTempRect);
   3363                         if (mView instanceof ViewGroup) {
   3364                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
   3365                                     focused, mTempRect);
   3366                             ((ViewGroup) mView).offsetRectIntoDescendantCoords(
   3367                                     v, mTempRect);
   3368                         }
   3369                         if (v.requestFocus(direction, mTempRect)) {
   3370                             playSoundEffect(
   3371                                     SoundEffectConstants.getContantForFocusDirection(direction));
   3372                             finishKeyEvent(event, sendDone, true);
   3373                             return;
   3374                         }
   3375                     }
   3376 
   3377                     // Give the focused view a last chance to handle the dpad key.
   3378                     if (mView.dispatchUnhandledMove(focused, direction)) {
   3379                         finishKeyEvent(event, sendDone, true);
   3380                         return;
   3381                     }
   3382                 }
   3383             }
   3384         }
   3385 
   3386         // Key was unhandled.
   3387         finishKeyEvent(event, sendDone, false);
   3388     }
   3389 
   3390     private void finishKeyEvent(KeyEvent event, boolean sendDone, boolean handled) {
   3391         if (sendDone) {
   3392             finishInputEvent(event, handled);
   3393         }
   3394     }
   3395 
   3396     /* drag/drop */
   3397     void setLocalDragState(Object obj) {
   3398         mLocalDragState = obj;
   3399     }
   3400 
   3401     private void handleDragEvent(DragEvent event) {
   3402         // From the root, only drag start/end/location are dispatched.  entered/exited
   3403         // are determined and dispatched by the viewgroup hierarchy, who then report
   3404         // that back here for ultimate reporting back to the framework.
   3405         if (mView != null && mAdded) {
   3406             final int what = event.mAction;
   3407 
   3408             if (what == DragEvent.ACTION_DRAG_EXITED) {
   3409                 // A direct EXITED event means that the window manager knows we've just crossed
   3410                 // a window boundary, so the current drag target within this one must have
   3411                 // just been exited.  Send it the usual notifications and then we're done
   3412                 // for now.
   3413                 mView.dispatchDragEvent(event);
   3414             } else {
   3415                 // Cache the drag description when the operation starts, then fill it in
   3416                 // on subsequent calls as a convenience
   3417                 if (what == DragEvent.ACTION_DRAG_STARTED) {
   3418                     mCurrentDragView = null;    // Start the current-recipient tracking
   3419                     mDragDescription = event.mClipDescription;
   3420                 } else {
   3421                     event.mClipDescription = mDragDescription;
   3422                 }
   3423 
   3424                 // For events with a [screen] location, translate into window coordinates
   3425                 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
   3426                     mDragPoint.set(event.mX, event.mY);
   3427                     if (mTranslator != null) {
   3428                         mTranslator.translatePointInScreenToAppWindow(mDragPoint);
   3429                     }
   3430 
   3431                     if (mCurScrollY != 0) {
   3432                         mDragPoint.offset(0, mCurScrollY);
   3433                     }
   3434 
   3435                     event.mX = mDragPoint.x;
   3436                     event.mY = mDragPoint.y;
   3437                 }
   3438 
   3439                 // Remember who the current drag target is pre-dispatch
   3440                 final View prevDragView = mCurrentDragView;
   3441 
   3442                 // Now dispatch the drag/drop event
   3443                 boolean result = mView.dispatchDragEvent(event);
   3444 
   3445                 // If we changed apparent drag target, tell the OS about it
   3446                 if (prevDragView != mCurrentDragView) {
   3447                     try {
   3448                         if (prevDragView != null) {
   3449                             sWindowSession.dragRecipientExited(mWindow);
   3450                         }
   3451                         if (mCurrentDragView != null) {
   3452                             sWindowSession.dragRecipientEntered(mWindow);
   3453                         }
   3454                     } catch (RemoteException e) {
   3455                         Slog.e(TAG, "Unable to note drag target change");
   3456                     }
   3457                 }
   3458 
   3459                 // Report the drop result when we're done
   3460                 if (what == DragEvent.ACTION_DROP) {
   3461                     mDragDescription = null;
   3462                     try {
   3463                         Log.i(TAG, "Reporting drop result: " + result);
   3464                         sWindowSession.reportDropResult(mWindow, result);
   3465                     } catch (RemoteException e) {
   3466                         Log.e(TAG, "Unable to report drop result");
   3467                     }
   3468                 }
   3469 
   3470                 // When the drag operation ends, release any local state object
   3471                 // that may have been in use
   3472                 if (what == DragEvent.ACTION_DRAG_ENDED) {
   3473                     setLocalDragState(null);
   3474                 }
   3475             }
   3476         }
   3477         event.recycle();
   3478     }
   3479 
   3480     public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
   3481         if (mSeq != args.seq) {
   3482             // The sequence has changed, so we need to update our value and make
   3483             // sure to do a traversal afterward so the window manager is given our
   3484             // most recent data.
   3485             mSeq = args.seq;
   3486             mAttachInfo.mForceReportNewAttributes = true;
   3487             scheduleTraversals();
   3488         }
   3489         if (mView == null) return;
   3490         if (args.localChanges != 0) {
   3491             if (mAttachInfo != null) {
   3492                 mAttachInfo.mSystemUiVisibility =
   3493                         (mAttachInfo.mSystemUiVisibility&~args.localChanges)
   3494                         | (args.localValue&args.localChanges);
   3495             }
   3496             mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
   3497             mAttachInfo.mRecomputeGlobalAttributes = true;
   3498             scheduleTraversals();
   3499         }
   3500         mView.dispatchSystemUiVisibilityChanged(args.globalVisibility);
   3501     }
   3502 
   3503     public void getLastTouchPoint(Point outLocation) {
   3504         outLocation.x = (int) mLastTouchPoint.x;
   3505         outLocation.y = (int) mLastTouchPoint.y;
   3506     }
   3507 
   3508     public void setDragFocus(View newDragTarget) {
   3509         if (mCurrentDragView != newDragTarget) {
   3510             mCurrentDragView = newDragTarget;
   3511         }
   3512     }
   3513 
   3514     private AudioManager getAudioManager() {
   3515         if (mView == null) {
   3516             throw new IllegalStateException("getAudioManager called when there is no mView");
   3517         }
   3518         if (mAudioManager == null) {
   3519             mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
   3520         }
   3521         return mAudioManager;
   3522     }
   3523 
   3524     public AccessibilityInteractionController getAccessibilityInteractionController() {
   3525         if (mView == null) {
   3526             throw new IllegalStateException("getAccessibilityInteractionController"
   3527                     + " called when there is no mView");
   3528         }
   3529         if (mAccessibilityInteractionContrtoller == null) {
   3530             mAccessibilityInteractionContrtoller = new AccessibilityInteractionController();
   3531         }
   3532         return mAccessibilityInteractionContrtoller;
   3533     }
   3534 
   3535     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
   3536             boolean insetsPending) throws RemoteException {
   3537 
   3538         float appScale = mAttachInfo.mApplicationScale;
   3539         boolean restore = false;
   3540         if (params != null && mTranslator != null) {
   3541             restore = true;
   3542             params.backup();
   3543             mTranslator.translateWindowLayout(params);
   3544         }
   3545         if (params != null) {
   3546             if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
   3547         }
   3548         mPendingConfiguration.seq = 0;
   3549         //Log.d(TAG, ">>>>>> CALLING relayout");
   3550         if (params != null && mOrigWindowType != params.type) {
   3551             // For compatibility with old apps, don't crash here.
   3552             if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
   3553                 Slog.w(TAG, "Window type can not be changed after "
   3554                         + "the window is added; ignoring change of " + mView);
   3555                 params.type = mOrigWindowType;
   3556             }
   3557         }
   3558         int relayoutResult = sWindowSession.relayout(
   3559                 mWindow, mSeq, params,
   3560                 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
   3561                 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
   3562                 viewVisibility, insetsPending, mWinFrame,
   3563                 mPendingContentInsets, mPendingVisibleInsets,
   3564                 mPendingConfiguration, mSurface);
   3565         //Log.d(TAG, "<<<<<< BACK FROM relayout");
   3566         if (restore) {
   3567             params.restore();
   3568         }
   3569 
   3570         if (mTranslator != null) {
   3571             mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
   3572             mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
   3573             mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
   3574         }
   3575         return relayoutResult;
   3576     }
   3577 
   3578     /**
   3579      * {@inheritDoc}
   3580      */
   3581     public void playSoundEffect(int effectId) {
   3582         checkThread();
   3583 
   3584         try {
   3585             final AudioManager audioManager = getAudioManager();
   3586 
   3587             switch (effectId) {
   3588                 case SoundEffectConstants.CLICK:
   3589                     audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
   3590                     return;
   3591                 case SoundEffectConstants.NAVIGATION_DOWN:
   3592                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
   3593                     return;
   3594                 case SoundEffectConstants.NAVIGATION_LEFT:
   3595                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
   3596                     return;
   3597                 case SoundEffectConstants.NAVIGATION_RIGHT:
   3598                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
   3599                     return;
   3600                 case SoundEffectConstants.NAVIGATION_UP:
   3601                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
   3602                     return;
   3603                 default:
   3604                     throw new IllegalArgumentException("unknown effect id " + effectId +
   3605                             " not defined in " + SoundEffectConstants.class.getCanonicalName());
   3606             }
   3607         } catch (IllegalStateException e) {
   3608             // Exception thrown by getAudioManager() when mView is null
   3609             Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
   3610             e.printStackTrace();
   3611         }
   3612     }
   3613 
   3614     /**
   3615      * {@inheritDoc}
   3616      */
   3617     public boolean performHapticFeedback(int effectId, boolean always) {
   3618         try {
   3619             return sWindowSession.performHapticFeedback(mWindow, effectId, always);
   3620         } catch (RemoteException e) {
   3621             return false;
   3622         }
   3623     }
   3624 
   3625     /**
   3626      * {@inheritDoc}
   3627      */
   3628     public View focusSearch(View focused, int direction) {
   3629         checkThread();
   3630         if (!(mView instanceof ViewGroup)) {
   3631             return null;
   3632         }
   3633         return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
   3634     }
   3635 
   3636     public void debug() {
   3637         mView.debug();
   3638     }
   3639 
   3640     public void dumpGfxInfo(PrintWriter pw, int[] info) {
   3641         if (mView != null) {
   3642             getGfxInfo(mView, info);
   3643         } else {
   3644             info[0] = info[1] = 0;
   3645         }
   3646     }
   3647 
   3648     private void getGfxInfo(View view, int[] info) {
   3649         DisplayList displayList = view.mDisplayList;
   3650         info[0]++;
   3651         if (displayList != null) {
   3652             info[1] += displayList.getSize();
   3653         }
   3654 
   3655         if (view instanceof ViewGroup) {
   3656             ViewGroup group = (ViewGroup) view;
   3657 
   3658             int count = group.getChildCount();
   3659             for (int i = 0; i < count; i++) {
   3660                 getGfxInfo(group.getChildAt(i), info);
   3661             }
   3662         }
   3663     }
   3664 
   3665     public void die(boolean immediate) {
   3666         if (immediate) {
   3667             doDie();
   3668         } else {
   3669             sendEmptyMessage(DIE);
   3670         }
   3671     }
   3672 
   3673     void doDie() {
   3674         checkThread();
   3675         if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
   3676         synchronized (this) {
   3677             if (mAdded) {
   3678                 mAdded = false;
   3679                 dispatchDetachedFromWindow();
   3680             }
   3681 
   3682             if (mAdded && !mFirst) {
   3683                 destroyHardwareRenderer();
   3684 
   3685                 int viewVisibility = mView.getVisibility();
   3686                 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
   3687                 if (mWindowAttributesChanged || viewVisibilityChanged) {
   3688                     // If layout params have been changed, first give them
   3689                     // to the window manager to make sure it has the correct
   3690                     // animation info.
   3691                     try {
   3692                         if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
   3693                                 & WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
   3694                             sWindowSession.finishDrawing(mWindow);
   3695                         }
   3696                     } catch (RemoteException e) {
   3697                     }
   3698                 }
   3699 
   3700                 mSurface.release();
   3701             }
   3702         }
   3703     }
   3704 
   3705     public void requestUpdateConfiguration(Configuration config) {
   3706         Message msg = obtainMessage(UPDATE_CONFIGURATION, config);
   3707         sendMessage(msg);
   3708     }
   3709 
   3710     private void destroyHardwareRenderer() {
   3711         if (mAttachInfo.mHardwareRenderer != null) {
   3712             mAttachInfo.mHardwareRenderer.destroy(true);
   3713             mAttachInfo.mHardwareRenderer = null;
   3714             mAttachInfo.mHardwareAccelerated = false;
   3715         }
   3716     }
   3717 
   3718     public void dispatchFinishedEvent(int seq, boolean handled) {
   3719         Message msg = obtainMessage(FINISHED_EVENT);
   3720         msg.arg1 = seq;
   3721         msg.arg2 = handled ? 1 : 0;
   3722         sendMessage(msg);
   3723     }
   3724 
   3725     public void dispatchResized(int w, int h, Rect coveredInsets,
   3726             Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
   3727         if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w
   3728                 + " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
   3729                 + " visibleInsets=" + visibleInsets.toShortString()
   3730                 + " reportDraw=" + reportDraw);
   3731         Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
   3732         if (mTranslator != null) {
   3733             mTranslator.translateRectInScreenToAppWindow(coveredInsets);
   3734             mTranslator.translateRectInScreenToAppWindow(visibleInsets);
   3735             w *= mTranslator.applicationInvertedScale;
   3736             h *= mTranslator.applicationInvertedScale;
   3737         }
   3738         msg.arg1 = w;
   3739         msg.arg2 = h;
   3740         ResizedInfo ri = new ResizedInfo();
   3741         ri.coveredInsets = new Rect(coveredInsets);
   3742         ri.visibleInsets = new Rect(visibleInsets);
   3743         ri.newConfig = newConfig;
   3744         msg.obj = ri;
   3745         sendMessage(msg);
   3746     }
   3747 
   3748     private long mInputEventReceiveTimeNanos;
   3749     private long mInputEventDeliverTimeNanos;
   3750     private long mInputEventDeliverPostImeTimeNanos;
   3751     private InputQueue.FinishedCallback mFinishedCallback;
   3752 
   3753     private final InputHandler mInputHandler = new InputHandler() {
   3754         public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) {
   3755             startInputEvent(finishedCallback);
   3756             dispatchKey(event, true);
   3757         }
   3758 
   3759         public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
   3760             startInputEvent(finishedCallback);
   3761             dispatchMotion(event, true);
   3762         }
   3763     };
   3764 
   3765     public void dispatchKey(KeyEvent event) {
   3766         dispatchKey(event, false);
   3767     }
   3768 
   3769     private void dispatchKey(KeyEvent event, boolean sendDone) {
   3770         //noinspection ConstantConditions
   3771         if (false && event.getAction() == KeyEvent.ACTION_DOWN) {
   3772             if (event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
   3773                 if (DBG) Log.d("keydisp", "===================================================");
   3774                 if (DBG) Log.d("keydisp", "Focused view Hierarchy is:");
   3775 
   3776                 debug();
   3777 
   3778                 if (DBG) Log.d("keydisp", "===================================================");
   3779             }
   3780         }
   3781 
   3782         Message msg = obtainMessage(DISPATCH_KEY);
   3783         msg.obj = event;
   3784         msg.arg1 = sendDone ? 1 : 0;
   3785 
   3786         if (LOCAL_LOGV) Log.v(
   3787             TAG, "sending key " + event + " to " + mView);
   3788 
   3789         sendMessageAtTime(msg, event.getEventTime());
   3790     }
   3791 
   3792     private void dispatchMotion(MotionEvent event, boolean sendDone) {
   3793         int source = event.getSource();
   3794         if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
   3795             dispatchPointer(event, sendDone);
   3796         } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
   3797             dispatchTrackball(event, sendDone);
   3798         } else {
   3799             dispatchGenericMotion(event, sendDone);
   3800         }
   3801     }
   3802 
   3803     private void dispatchPointer(MotionEvent event, boolean sendDone) {
   3804         Message msg = obtainMessage(DISPATCH_POINTER);
   3805         msg.obj = event;
   3806         msg.arg1 = sendDone ? 1 : 0;
   3807         sendMessageAtTime(msg, event.getEventTime());
   3808     }
   3809 
   3810     private void dispatchTrackball(MotionEvent event, boolean sendDone) {
   3811         Message msg = obtainMessage(DISPATCH_TRACKBALL);
   3812         msg.obj = event;
   3813         msg.arg1 = sendDone ? 1 : 0;
   3814         sendMessageAtTime(msg, event.getEventTime());
   3815     }
   3816 
   3817     private void dispatchGenericMotion(MotionEvent event, boolean sendDone) {
   3818         Message msg = obtainMessage(DISPATCH_GENERIC_MOTION);
   3819         msg.obj = event;
   3820         msg.arg1 = sendDone ? 1 : 0;
   3821         sendMessageAtTime(msg, event.getEventTime());
   3822     }
   3823 
   3824     public void dispatchAppVisibility(boolean visible) {
   3825         Message msg = obtainMessage(DISPATCH_APP_VISIBILITY);
   3826         msg.arg1 = visible ? 1 : 0;
   3827         sendMessage(msg);
   3828     }
   3829 
   3830     public void dispatchGetNewSurface() {
   3831         Message msg = obtainMessage(DISPATCH_GET_NEW_SURFACE);
   3832         sendMessage(msg);
   3833     }
   3834 
   3835     public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
   3836         Message msg = Message.obtain();
   3837         msg.what = WINDOW_FOCUS_CHANGED;
   3838         msg.arg1 = hasFocus ? 1 : 0;
   3839         msg.arg2 = inTouchMode ? 1 : 0;
   3840         sendMessage(msg);
   3841     }
   3842 
   3843     public void dispatchCloseSystemDialogs(String reason) {
   3844         Message msg = Message.obtain();
   3845         msg.what = CLOSE_SYSTEM_DIALOGS;
   3846         msg.obj = reason;
   3847         sendMessage(msg);
   3848     }
   3849 
   3850     public void dispatchDragEvent(DragEvent event) {
   3851         final int what;
   3852         if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
   3853             what = DISPATCH_DRAG_LOCATION_EVENT;
   3854             removeMessages(what);
   3855         } else {
   3856             what = DISPATCH_DRAG_EVENT;
   3857         }
   3858         Message msg = obtainMessage(what, event);
   3859         sendMessage(msg);
   3860     }
   3861 
   3862     public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
   3863             int localValue, int localChanges) {
   3864         SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
   3865         args.seq = seq;
   3866         args.globalVisibility = globalVisibility;
   3867         args.localValue = localValue;
   3868         args.localChanges = localChanges;
   3869         sendMessage(obtainMessage(DISPATCH_SYSTEM_UI_VISIBILITY, args));
   3870     }
   3871 
   3872     /**
   3873      * The window is getting focus so if there is anything focused/selected
   3874      * send an {@link AccessibilityEvent} to announce that.
   3875      */
   3876     private void sendAccessibilityEvents() {
   3877         if (!mAccessibilityManager.isEnabled()) {
   3878             return;
   3879         }
   3880         mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
   3881         View focusedView = mView.findFocus();
   3882         if (focusedView != null && focusedView != mView) {
   3883             focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
   3884         }
   3885     }
   3886 
   3887     /**
   3888      * Post a callback to send a
   3889      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
   3890      * This event is send at most once every
   3891      * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
   3892      */
   3893     private void postSendWindowContentChangedCallback() {
   3894         if (mSendWindowContentChangedAccessibilityEvent == null) {
   3895             mSendWindowContentChangedAccessibilityEvent =
   3896                 new SendWindowContentChangedAccessibilityEvent();
   3897         }
   3898         if (!mSendWindowContentChangedAccessibilityEvent.mIsPending) {
   3899             mSendWindowContentChangedAccessibilityEvent.mIsPending = true;
   3900             postDelayed(mSendWindowContentChangedAccessibilityEvent,
   3901                     ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
   3902         }
   3903     }
   3904 
   3905     /**
   3906      * Remove a posted callback to send a
   3907      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
   3908      */
   3909     private void removeSendWindowContentChangedCallback() {
   3910         if (mSendWindowContentChangedAccessibilityEvent != null) {
   3911             removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
   3912         }
   3913     }
   3914 
   3915     public boolean showContextMenuForChild(View originalView) {
   3916         return false;
   3917     }
   3918 
   3919     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
   3920         return null;
   3921     }
   3922 
   3923     public void createContextMenu(ContextMenu menu) {
   3924     }
   3925 
   3926     public void childDrawableStateChanged(View child) {
   3927     }
   3928 
   3929     public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
   3930         if (mView == null) {
   3931             return false;
   3932         }
   3933         mAccessibilityManager.sendAccessibilityEvent(event);
   3934         return true;
   3935     }
   3936 
   3937     void checkThread() {
   3938         if (mThread != Thread.currentThread()) {
   3939             throw new CalledFromWrongThreadException(
   3940                     "Only the original thread that created a view hierarchy can touch its views.");
   3941         }
   3942     }
   3943 
   3944     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
   3945         // ViewAncestor never intercepts touch event, so this can be a no-op
   3946     }
   3947 
   3948     public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
   3949             boolean immediate) {
   3950         return scrollToRectOrFocus(rectangle, immediate);
   3951     }
   3952 
   3953     class TakenSurfaceHolder extends BaseSurfaceHolder {
   3954         @Override
   3955         public boolean onAllowLockCanvas() {
   3956             return mDrawingAllowed;
   3957         }
   3958 
   3959         @Override
   3960         public void onRelayoutContainer() {
   3961             // Not currently interesting -- from changing between fixed and layout size.
   3962         }
   3963 
   3964         public void setFormat(int format) {
   3965             ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
   3966         }
   3967 
   3968         public void setType(int type) {
   3969             ((RootViewSurfaceTaker)mView).setSurfaceType(type);
   3970         }
   3971 
   3972         @Override
   3973         public void onUpdateSurface() {
   3974             // We take care of format and type changes on our own.
   3975             throw new IllegalStateException("Shouldn't be here");
   3976         }
   3977 
   3978         public boolean isCreating() {
   3979             return mIsCreating;
   3980         }
   3981 
   3982         @Override
   3983         public void setFixedSize(int width, int height) {
   3984             throw new UnsupportedOperationException(
   3985                     "Currently only support sizing from layout");
   3986         }
   3987 
   3988         public void setKeepScreenOn(boolean screenOn) {
   3989             ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
   3990         }
   3991     }
   3992 
   3993     static class InputMethodCallback extends IInputMethodCallback.Stub {
   3994         private WeakReference<ViewRootImpl> mViewAncestor;
   3995 
   3996         public InputMethodCallback(ViewRootImpl viewAncestor) {
   3997             mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
   3998         }
   3999 
   4000         public void finishedEvent(int seq, boolean handled) {
   4001             final ViewRootImpl viewAncestor = mViewAncestor.get();
   4002             if (viewAncestor != null) {
   4003                 viewAncestor.dispatchFinishedEvent(seq, handled);
   4004             }
   4005         }
   4006 
   4007         public void sessionCreated(IInputMethodSession session) {
   4008             // Stub -- not for use in the client.
   4009         }
   4010     }
   4011 
   4012     static class W extends IWindow.Stub {
   4013         private final WeakReference<ViewRootImpl> mViewAncestor;
   4014 
   4015         W(ViewRootImpl viewAncestor) {
   4016             mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
   4017         }
   4018 
   4019         public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
   4020                 boolean reportDraw, Configuration newConfig) {
   4021             final ViewRootImpl viewAncestor = mViewAncestor.get();
   4022             if (viewAncestor != null) {
   4023                 viewAncestor.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw,
   4024                         newConfig);
   4025             }
   4026         }
   4027 
   4028         public void dispatchAppVisibility(boolean visible) {
   4029             final ViewRootImpl viewAncestor = mViewAncestor.get();
   4030             if (viewAncestor != null) {
   4031                 viewAncestor.dispatchAppVisibility(visible);
   4032             }
   4033         }
   4034 
   4035         public void dispatchGetNewSurface() {
   4036             final ViewRootImpl viewAncestor = mViewAncestor.get();
   4037             if (viewAncestor != null) {
   4038                 viewAncestor.dispatchGetNewSurface();
   4039             }
   4040         }
   4041 
   4042         public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
   4043             final ViewRootImpl viewAncestor = mViewAncestor.get();
   4044             if (viewAncestor != null) {
   4045                 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
   4046             }
   4047         }
   4048 
   4049         private static int checkCallingPermission(String permission) {
   4050             try {
   4051                 return ActivityManagerNative.getDefault().checkPermission(
   4052                         permission, Binder.getCallingPid(), Binder.getCallingUid());
   4053             } catch (RemoteException e) {
   4054                 return PackageManager.PERMISSION_DENIED;
   4055             }
   4056         }
   4057 
   4058         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
   4059             final ViewRootImpl viewAncestor = mViewAncestor.get();
   4060             if (viewAncestor != null) {
   4061                 final View view = viewAncestor.mView;
   4062                 if (view != null) {
   4063                     if (checkCallingPermission(Manifest.permission.DUMP) !=
   4064                             PackageManager.PERMISSION_GRANTED) {
   4065                         throw new SecurityException("Insufficient permissions to invoke"
   4066                                 + " executeCommand() from pid=" + Binder.getCallingPid()
   4067                                 + ", uid=" + Binder.getCallingUid());
   4068                     }
   4069 
   4070                     OutputStream clientStream = null;
   4071                     try {
   4072                         clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
   4073                         ViewDebug.dispatchCommand(view, command, parameters, clientStream);
   4074                     } catch (IOException e) {
   4075                         e.printStackTrace();
   4076                     } finally {
   4077                         if (clientStream != null) {
   4078                             try {
   4079                                 clientStream.close();
   4080                             } catch (IOException e) {
   4081                                 e.printStackTrace();
   4082                             }
   4083                         }
   4084                     }
   4085                 }
   4086             }
   4087         }
   4088 
   4089         public void closeSystemDialogs(String reason) {
   4090             final ViewRootImpl viewAncestor = mViewAncestor.get();
   4091             if (viewAncestor != null) {
   4092                 viewAncestor.dispatchCloseSystemDialogs(reason);
   4093             }
   4094         }
   4095 
   4096         public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
   4097                 boolean sync) {
   4098             if (sync) {
   4099                 try {
   4100                     sWindowSession.wallpaperOffsetsComplete(asBinder());
   4101                 } catch (RemoteException e) {
   4102                 }
   4103             }
   4104         }
   4105 
   4106         public void dispatchWallpaperCommand(String action, int x, int y,
   4107                 int z, Bundle extras, boolean sync) {
   4108             if (sync) {
   4109                 try {
   4110                     sWindowSession.wallpaperCommandComplete(asBinder(), null);
   4111                 } catch (RemoteException e) {
   4112                 }
   4113             }
   4114         }
   4115 
   4116         /* Drag/drop */
   4117         public void dispatchDragEvent(DragEvent event) {
   4118             final ViewRootImpl viewAncestor = mViewAncestor.get();
   4119             if (viewAncestor != null) {
   4120                 viewAncestor.dispatchDragEvent(event);
   4121             }
   4122         }
   4123 
   4124         public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
   4125                 int localValue, int localChanges) {
   4126             final ViewRootImpl viewAncestor = mViewAncestor.get();
   4127             if (viewAncestor != null) {
   4128                 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
   4129                         localValue, localChanges);
   4130             }
   4131         }
   4132     }
   4133 
   4134     /**
   4135      * Maintains state information for a single trackball axis, generating
   4136      * discrete (DPAD) movements based on raw trackball motion.
   4137      */
   4138     static final class TrackballAxis {
   4139         /**
   4140          * The maximum amount of acceleration we will apply.
   4141          */
   4142         static final float MAX_ACCELERATION = 20;
   4143 
   4144         /**
   4145          * The maximum amount of time (in milliseconds) between events in order
   4146          * for us to consider the user to be doing fast trackball movements,
   4147          * and thus apply an acceleration.
   4148          */
   4149         static final long FAST_MOVE_TIME = 150;
   4150 
   4151         /**
   4152          * Scaling factor to the time (in milliseconds) between events to how
   4153          * much to multiple/divide the current acceleration.  When movement
   4154          * is < FAST_MOVE_TIME this multiplies the acceleration; when >
   4155          * FAST_MOVE_TIME it divides it.
   4156          */
   4157         static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
   4158 
   4159         float position;
   4160         float absPosition;
   4161         float acceleration = 1;
   4162         long lastMoveTime = 0;
   4163         int step;
   4164         int dir;
   4165         int nonAccelMovement;
   4166 
   4167         void reset(int _step) {
   4168             position = 0;
   4169             acceleration = 1;
   4170             lastMoveTime = 0;
   4171             step = _step;
   4172             dir = 0;
   4173         }
   4174 
   4175         /**
   4176          * Add trackball movement into the state.  If the direction of movement
   4177          * has been reversed, the state is reset before adding the
   4178          * movement (so that you don't have to compensate for any previously
   4179          * collected movement before see the result of the movement in the
   4180          * new direction).
   4181          *
   4182          * @return Returns the absolute value of the amount of movement
   4183          * collected so far.
   4184          */
   4185         float collect(float off, long time, String axis) {
   4186             long normTime;
   4187             if (off > 0) {
   4188                 normTime = (long)(off * FAST_MOVE_TIME);
   4189                 if (dir < 0) {
   4190                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
   4191                     position = 0;
   4192                     step = 0;
   4193                     acceleration = 1;
   4194                     lastMoveTime = 0;
   4195                 }
   4196                 dir = 1;
   4197             } else if (off < 0) {
   4198                 normTime = (long)((-off) * FAST_MOVE_TIME);
   4199                 if (dir > 0) {
   4200                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
   4201                     position = 0;
   4202                     step = 0;
   4203                     acceleration = 1;
   4204                     lastMoveTime = 0;
   4205                 }
   4206                 dir = -1;
   4207             } else {
   4208                 normTime = 0;
   4209             }
   4210 
   4211             // The number of milliseconds between each movement that is
   4212             // considered "normal" and will not result in any acceleration
   4213             // or deceleration, scaled by the offset we have here.
   4214             if (normTime > 0) {
   4215                 long delta = time - lastMoveTime;
   4216                 lastMoveTime = time;
   4217                 float acc = acceleration;
   4218                 if (delta < normTime) {
   4219                     // The user is scrolling rapidly, so increase acceleration.
   4220                     float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
   4221                     if (scale > 1) acc *= scale;
   4222                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
   4223                             + off + " normTime=" + normTime + " delta=" + delta
   4224                             + " scale=" + scale + " acc=" + acc);
   4225                     acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
   4226                 } else {
   4227                     // The user is scrolling slowly, so decrease acceleration.
   4228                     float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
   4229                     if (scale > 1) acc /= scale;
   4230                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
   4231                             + off + " normTime=" + normTime + " delta=" + delta
   4232                             + " scale=" + scale + " acc=" + acc);
   4233                     acceleration = acc > 1 ? acc : 1;
   4234                 }
   4235             }
   4236             position += off;
   4237             return (absPosition = Math.abs(position));
   4238         }
   4239 
   4240         /**
   4241          * Generate the number of discrete movement events appropriate for
   4242          * the currently collected trackball movement.
   4243          *
   4244          * @param precision The minimum movement required to generate the
   4245          * first discrete movement.
   4246          *
   4247          * @return Returns the number of discrete movements, either positive
   4248          * or negative, or 0 if there is not enough trackball movement yet
   4249          * for a discrete movement.
   4250          */
   4251         int generate(float precision) {
   4252             int movement = 0;
   4253             nonAccelMovement = 0;
   4254             do {
   4255                 final int dir = position >= 0 ? 1 : -1;
   4256                 switch (step) {
   4257                     // If we are going to execute the first step, then we want
   4258                     // to do this as soon as possible instead of waiting for
   4259                     // a full movement, in order to make things look responsive.
   4260                     case 0:
   4261                         if (absPosition < precision) {
   4262                             return movement;
   4263                         }
   4264                         movement += dir;
   4265                         nonAccelMovement += dir;
   4266                         step = 1;
   4267                         break;
   4268                     // If we have generated the first movement, then we need
   4269                     // to wait for the second complete trackball motion before
   4270                     // generating the second discrete movement.
   4271                     case 1:
   4272                         if (absPosition < 2) {
   4273                             return movement;
   4274                         }
   4275                         movement += dir;
   4276                         nonAccelMovement += dir;
   4277                         position += dir > 0 ? -2 : 2;
   4278                         absPosition = Math.abs(position);
   4279                         step = 2;
   4280                         break;
   4281                     // After the first two, we generate discrete movements
   4282                     // consistently with the trackball, applying an acceleration
   4283                     // if the trackball is moving quickly.  This is a simple
   4284                     // acceleration on top of what we already compute based
   4285                     // on how quickly the wheel is being turned, to apply
   4286                     // a longer increasing acceleration to continuous movement
   4287                     // in one direction.
   4288                     default:
   4289                         if (absPosition < 1) {
   4290                             return movement;
   4291                         }
   4292                         movement += dir;
   4293                         position += dir >= 0 ? -1 : 1;
   4294                         absPosition = Math.abs(position);
   4295                         float acc = acceleration;
   4296                         acc *= 1.1f;
   4297                         acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
   4298                         break;
   4299                 }
   4300             } while (true);
   4301         }
   4302     }
   4303 
   4304     public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
   4305         public CalledFromWrongThreadException(String msg) {
   4306             super(msg);
   4307         }
   4308     }
   4309 
   4310     private SurfaceHolder mHolder = new SurfaceHolder() {
   4311         // we only need a SurfaceHolder for opengl. it would be nice
   4312         // to implement everything else though, especially the callback
   4313         // support (opengl doesn't make use of it right now, but eventually
   4314         // will).
   4315         public Surface getSurface() {
   4316             return mSurface;
   4317         }
   4318 
   4319         public boolean isCreating() {
   4320             return false;
   4321         }
   4322 
   4323         public void addCallback(Callback callback) {
   4324         }
   4325 
   4326         public void removeCallback(Callback callback) {
   4327         }
   4328 
   4329         public void setFixedSize(int width, int height) {
   4330         }
   4331 
   4332         public void setSizeFromLayout() {
   4333         }
   4334 
   4335         public void setFormat(int format) {
   4336         }
   4337 
   4338         public void setType(int type) {
   4339         }
   4340 
   4341         public void setKeepScreenOn(boolean screenOn) {
   4342         }
   4343 
   4344         public Canvas lockCanvas() {
   4345             return null;
   4346         }
   4347 
   4348         public Canvas lockCanvas(Rect dirty) {
   4349             return null;
   4350         }
   4351 
   4352         public void unlockCanvasAndPost(Canvas canvas) {
   4353         }
   4354         public Rect getSurfaceFrame() {
   4355             return null;
   4356         }
   4357     };
   4358 
   4359     static RunQueue getRunQueue() {
   4360         RunQueue rq = sRunQueues.get();
   4361         if (rq != null) {
   4362             return rq;
   4363         }
   4364         rq = new RunQueue();
   4365         sRunQueues.set(rq);
   4366         return rq;
   4367     }
   4368 
   4369     /**
   4370      * @hide
   4371      */
   4372     static final class RunQueue {
   4373         private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
   4374 
   4375         void post(Runnable action) {
   4376             postDelayed(action, 0);
   4377         }
   4378 
   4379         void postDelayed(Runnable action, long delayMillis) {
   4380             HandlerAction handlerAction = new HandlerAction();
   4381             handlerAction.action = action;
   4382             handlerAction.delay = delayMillis;
   4383 
   4384             synchronized (mActions) {
   4385                 mActions.add(handlerAction);
   4386             }
   4387         }
   4388 
   4389         void removeCallbacks(Runnable action) {
   4390             final HandlerAction handlerAction = new HandlerAction();
   4391             handlerAction.action = action;
   4392 
   4393             synchronized (mActions) {
   4394                 final ArrayList<HandlerAction> actions = mActions;
   4395 
   4396                 while (actions.remove(handlerAction)) {
   4397                     // Keep going
   4398                 }
   4399             }
   4400         }
   4401 
   4402         void executeActions(Handler handler) {
   4403             synchronized (mActions) {
   4404                 final ArrayList<HandlerAction> actions = mActions;
   4405                 final int count = actions.size();
   4406 
   4407                 for (int i = 0; i < count; i++) {
   4408                     final HandlerAction handlerAction = actions.get(i);
   4409                     handler.postDelayed(handlerAction.action, handlerAction.delay);
   4410                 }
   4411 
   4412                 actions.clear();
   4413             }
   4414         }
   4415 
   4416         private static class HandlerAction {
   4417             Runnable action;
   4418             long delay;
   4419 
   4420             @Override
   4421             public boolean equals(Object o) {
   4422                 if (this == o) return true;
   4423                 if (o == null || getClass() != o.getClass()) return false;
   4424 
   4425                 HandlerAction that = (HandlerAction) o;
   4426                 return !(action != null ? !action.equals(that.action) : that.action != null);
   4427 
   4428             }
   4429 
   4430             @Override
   4431             public int hashCode() {
   4432                 int result = action != null ? action.hashCode() : 0;
   4433                 result = 31 * result + (int) (delay ^ (delay >>> 32));
   4434                 return result;
   4435             }
   4436         }
   4437     }
   4438 
   4439     /**
   4440      * Class for managing the accessibility interaction connection
   4441      * based on the global accessibility state.
   4442      */
   4443     final class AccessibilityInteractionConnectionManager
   4444             implements AccessibilityStateChangeListener {
   4445         public void onAccessibilityStateChanged(boolean enabled) {
   4446             if (enabled) {
   4447                 ensureConnection();
   4448             } else {
   4449                 ensureNoConnection();
   4450             }
   4451         }
   4452 
   4453         public void ensureConnection() {
   4454             final boolean registered = mAttachInfo.mAccessibilityWindowId != View.NO_ID;
   4455             if (!registered) {
   4456                 mAttachInfo.mAccessibilityWindowId =
   4457                     mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
   4458                             new AccessibilityInteractionConnection(ViewRootImpl.this));
   4459             }
   4460         }
   4461 
   4462         public void ensureNoConnection() {
   4463             final boolean registered = mAttachInfo.mAccessibilityWindowId != View.NO_ID;
   4464             if (registered) {
   4465                 mAttachInfo.mAccessibilityWindowId = View.NO_ID;
   4466                 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
   4467             }
   4468         }
   4469     }
   4470 
   4471     /**
   4472      * This class is an interface this ViewAncestor provides to the
   4473      * AccessibilityManagerService to the latter can interact with
   4474      * the view hierarchy in this ViewAncestor.
   4475      */
   4476     final class AccessibilityInteractionConnection
   4477             extends IAccessibilityInteractionConnection.Stub {
   4478         private final WeakReference<ViewRootImpl> mViewAncestor;
   4479 
   4480         AccessibilityInteractionConnection(ViewRootImpl viewAncestor) {
   4481             mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
   4482         }
   4483 
   4484         public void findAccessibilityNodeInfoByAccessibilityId(int accessibilityId,
   4485                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
   4486                 int interrogatingPid, long interrogatingTid) {
   4487             if (mViewAncestor.get() != null) {
   4488                 getAccessibilityInteractionController()
   4489                     .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityId,
   4490                         interactionId, callback, interrogatingPid, interrogatingTid);
   4491             }
   4492         }
   4493 
   4494         public void performAccessibilityAction(int accessibilityId, int action,
   4495                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
   4496                 int interogatingPid, long interrogatingTid) {
   4497             if (mViewAncestor.get() != null) {
   4498                 getAccessibilityInteractionController()
   4499                     .performAccessibilityActionClientThread(accessibilityId, action, interactionId,
   4500                             callback, interogatingPid, interrogatingTid);
   4501             }
   4502         }
   4503 
   4504         public void findAccessibilityNodeInfoByViewId(int viewId,
   4505                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
   4506                 int interrogatingPid, long interrogatingTid) {
   4507             if (mViewAncestor.get() != null) {
   4508                 getAccessibilityInteractionController()
   4509                     .findAccessibilityNodeInfoByViewIdClientThread(viewId, interactionId, callback,
   4510                             interrogatingPid, interrogatingTid);
   4511             }
   4512         }
   4513 
   4514         public void findAccessibilityNodeInfosByViewText(String text, int accessibilityId,
   4515                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
   4516                 int interrogatingPid, long interrogatingTid) {
   4517             if (mViewAncestor.get() != null) {
   4518                 getAccessibilityInteractionController()
   4519                     .findAccessibilityNodeInfosByViewTextClientThread(text, accessibilityId,
   4520                             interactionId, callback, interrogatingPid, interrogatingTid);
   4521             }
   4522         }
   4523     }
   4524 
   4525     /**
   4526      * Class for managing accessibility interactions initiated from the system
   4527      * and targeting the view hierarchy. A *ClientThread method is to be
   4528      * called from the interaction connection this ViewAncestor gives the
   4529      * system to talk to it and a corresponding *UiThread method that is executed
   4530      * on the UI thread.
   4531      */
   4532     final class AccessibilityInteractionController {
   4533         private static final int POOL_SIZE = 5;
   4534 
   4535         private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
   4536             new ArrayList<AccessibilityNodeInfo>();
   4537 
   4538         // Reusable poolable arguments for interacting with the view hierarchy
   4539         // to fit more arguments than Message and to avoid sharing objects between
   4540         // two messages since several threads can send messages concurrently.
   4541         private final Pool<SomeArgs> mPool = Pools.synchronizedPool(Pools.finitePool(
   4542                 new PoolableManager<SomeArgs>() {
   4543                     public SomeArgs newInstance() {
   4544                         return new SomeArgs();
   4545                     }
   4546 
   4547                     public void onAcquired(SomeArgs info) {
   4548                         /* do nothing */
   4549                     }
   4550 
   4551                     public void onReleased(SomeArgs info) {
   4552                         info.clear();
   4553                     }
   4554                 }, POOL_SIZE)
   4555         );
   4556 
   4557         public class SomeArgs implements Poolable<SomeArgs> {
   4558             private SomeArgs mNext;
   4559             private boolean mIsPooled;
   4560 
   4561             public Object arg1;
   4562             public Object arg2;
   4563             public int argi1;
   4564             public int argi2;
   4565             public int argi3;
   4566 
   4567             public SomeArgs getNextPoolable() {
   4568                 return mNext;
   4569             }
   4570 
   4571             public boolean isPooled() {
   4572                 return mIsPooled;
   4573             }
   4574 
   4575             public void setNextPoolable(SomeArgs args) {
   4576                 mNext = args;
   4577             }
   4578 
   4579             public void setPooled(boolean isPooled) {
   4580                 mIsPooled = isPooled;
   4581             }
   4582 
   4583             private void clear() {
   4584                 arg1 = null;
   4585                 arg2 = null;
   4586                 argi1 = 0;
   4587                 argi2 = 0;
   4588                 argi3 = 0;
   4589             }
   4590         }
   4591 
   4592         public void findAccessibilityNodeInfoByAccessibilityIdClientThread(int accessibilityId,
   4593                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
   4594                 int interrogatingPid, long interrogatingTid) {
   4595             Message message = Message.obtain();
   4596             message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
   4597             message.arg1 = accessibilityId;
   4598             message.arg2 = interactionId;
   4599             message.obj = callback;
   4600             // If the interrogation is performed by the same thread as the main UI
   4601             // thread in this process, set the message as a static reference so
   4602             // after this call completes the same thread but in the interrogating
   4603             // client can handle the message to generate the result.
   4604             if (interrogatingPid == Process.myPid()
   4605                     && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
   4606                 message.setTarget(ViewRootImpl.this);
   4607                 AccessibilityInteractionClient.getInstance().setSameThreadMessage(message);
   4608             } else {
   4609                 sendMessage(message);
   4610             }
   4611         }
   4612 
   4613         public void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
   4614             final int accessibilityId = message.arg1;
   4615             final int interactionId = message.arg2;
   4616             final IAccessibilityInteractionConnectionCallback callback =
   4617                 (IAccessibilityInteractionConnectionCallback) message.obj;
   4618 
   4619             AccessibilityNodeInfo info = null;
   4620             try {
   4621                 View target = findViewByAccessibilityId(accessibilityId);
   4622                 if (target != null) {
   4623                     info = target.createAccessibilityNodeInfo();
   4624                 }
   4625             } finally {
   4626                 try {
   4627                     callback.setFindAccessibilityNodeInfoResult(info, interactionId);
   4628                 } catch (RemoteException re) {
   4629                     /* ignore - the other side will time out */
   4630                 }
   4631             }
   4632         }
   4633 
   4634         public void findAccessibilityNodeInfoByViewIdClientThread(int viewId, int interactionId,
   4635                 IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
   4636                 long interrogatingTid) {
   4637             Message message = Message.obtain();
   4638             message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
   4639             message.arg1 = viewId;
   4640             message.arg2 = interactionId;
   4641             message.obj = callback;
   4642             // If the interrogation is performed by the same thread as the main UI
   4643             // thread in this process, set the message as a static reference so
   4644             // after this call completes the same thread but in the interrogating
   4645             // client can handle the message to generate the result.
   4646             if (interrogatingPid == Process.myPid()
   4647                     && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
   4648                 message.setTarget(ViewRootImpl.this);
   4649                 AccessibilityInteractionClient.getInstance().setSameThreadMessage(message);
   4650             } else {
   4651                 sendMessage(message);
   4652             }
   4653         }
   4654 
   4655         public void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
   4656             final int viewId = message.arg1;
   4657             final int interactionId = message.arg2;
   4658             final IAccessibilityInteractionConnectionCallback callback =
   4659                 (IAccessibilityInteractionConnectionCallback) message.obj;
   4660 
   4661             AccessibilityNodeInfo info = null;
   4662             try {
   4663                 View root = ViewRootImpl.this.mView;
   4664                 View target = root.findViewById(viewId);
   4665                 if (target != null && target.getVisibility() == View.VISIBLE) {
   4666                     info = target.createAccessibilityNodeInfo();
   4667                 }
   4668             } finally {
   4669                 try {
   4670                     callback.setFindAccessibilityNodeInfoResult(info, interactionId);
   4671                 } catch (RemoteException re) {
   4672                     /* ignore - the other side will time out */
   4673                 }
   4674             }
   4675         }
   4676 
   4677         public void findAccessibilityNodeInfosByViewTextClientThread(String text,
   4678                 int accessibilityViewId, int interactionId,
   4679                 IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
   4680                 long interrogatingTid) {
   4681             Message message = Message.obtain();
   4682             message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT;
   4683             SomeArgs args = mPool.acquire();
   4684             args.arg1 = text;
   4685             args.argi1 = accessibilityViewId;
   4686             args.argi2 = interactionId;
   4687             args.arg2 = callback;
   4688             message.obj = args;
   4689             // If the interrogation is performed by the same thread as the main UI
   4690             // thread in this process, set the message as a static reference so
   4691             // after this call completes the same thread but in the interrogating
   4692             // client can handle the message to generate the result.
   4693             if (interrogatingPid == Process.myPid()
   4694                     && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
   4695                 message.setTarget(ViewRootImpl.this);
   4696                 AccessibilityInteractionClient.getInstance().setSameThreadMessage(message);
   4697             } else {
   4698                 sendMessage(message);
   4699             }
   4700         }
   4701 
   4702         public void findAccessibilityNodeInfosByViewTextUiThread(Message message) {
   4703             SomeArgs args = (SomeArgs) message.obj;
   4704             final String text = (String) args.arg1;
   4705             final int accessibilityViewId = args.argi1;
   4706             final int interactionId = args.argi2;
   4707             final IAccessibilityInteractionConnectionCallback callback =
   4708                 (IAccessibilityInteractionConnectionCallback) args.arg2;
   4709             mPool.release(args);
   4710 
   4711             List<AccessibilityNodeInfo> infos = null;
   4712             try {
   4713                 ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList;
   4714                 foundViews.clear();
   4715 
   4716                 View root = null;
   4717                 if (accessibilityViewId != View.NO_ID) {
   4718                     root = findViewByAccessibilityId(accessibilityViewId);
   4719                 } else {
   4720                     root = ViewRootImpl.this.mView;
   4721                 }
   4722 
   4723                 if (root == null || root.getVisibility() != View.VISIBLE) {
   4724                     return;
   4725                 }
   4726 
   4727                 root.findViewsWithText(foundViews, text, View.FIND_VIEWS_WITH_TEXT
   4728                         | View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
   4729                 if (foundViews.isEmpty()) {
   4730                     return;
   4731                 }
   4732 
   4733                 infos = mTempAccessibilityNodeInfoList;
   4734                 infos.clear();
   4735 
   4736                 final int viewCount = foundViews.size();
   4737                 for (int i = 0; i < viewCount; i++) {
   4738                     View foundView = foundViews.get(i);
   4739                     if (foundView.getVisibility() == View.VISIBLE) {
   4740                         infos.add(foundView.createAccessibilityNodeInfo());
   4741                     }
   4742                  }
   4743             } finally {
   4744                 try {
   4745                     callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
   4746                 } catch (RemoteException re) {
   4747                     /* ignore - the other side will time out */
   4748                 }
   4749             }
   4750         }
   4751 
   4752         public void performAccessibilityActionClientThread(int accessibilityId, int action,
   4753                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
   4754                 int interogatingPid, long interrogatingTid) {
   4755             Message message = Message.obtain();
   4756             message.what = DO_PERFORM_ACCESSIBILITY_ACTION;
   4757             SomeArgs args = mPool.acquire();
   4758             args.argi1 = accessibilityId;
   4759             args.argi2 = action;
   4760             args.argi3 = interactionId;
   4761             args.arg1 = callback;
   4762             message.obj = args;
   4763             // If the interrogation is performed by the same thread as the main UI
   4764             // thread in this process, set the message as a static reference so
   4765             // after this call completes the same thread but in the interrogating
   4766             // client can handle the message to generate the result.
   4767             if (interogatingPid == Process.myPid()
   4768                     && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
   4769                 message.setTarget(ViewRootImpl.this);
   4770                 AccessibilityInteractionClient.getInstance().setSameThreadMessage(message);
   4771             } else {
   4772                 sendMessage(message);
   4773             }
   4774         }
   4775 
   4776         public void perfromAccessibilityActionUiThread(Message message) {
   4777             SomeArgs args = (SomeArgs) message.obj;
   4778             final int accessibilityId = args.argi1;
   4779             final int action = args.argi2;
   4780             final int interactionId = args.argi3;
   4781             final IAccessibilityInteractionConnectionCallback callback =
   4782                 (IAccessibilityInteractionConnectionCallback) args.arg1;
   4783             mPool.release(args);
   4784 
   4785             boolean succeeded = false;
   4786             try {
   4787                 switch (action) {
   4788                     case AccessibilityNodeInfo.ACTION_FOCUS: {
   4789                         succeeded = performActionFocus(accessibilityId);
   4790                     } break;
   4791                     case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: {
   4792                         succeeded = performActionClearFocus(accessibilityId);
   4793                     } break;
   4794                     case AccessibilityNodeInfo.ACTION_SELECT: {
   4795                         succeeded = performActionSelect(accessibilityId);
   4796                     } break;
   4797                     case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
   4798                         succeeded = performActionClearSelection(accessibilityId);
   4799                     } break;
   4800                 }
   4801             } finally {
   4802                 try {
   4803                     callback.setPerformAccessibilityActionResult(succeeded, interactionId);
   4804                 } catch (RemoteException re) {
   4805                     /* ignore - the other side will time out */
   4806                 }
   4807             }
   4808         }
   4809 
   4810         private boolean performActionFocus(int accessibilityId) {
   4811             View target = findViewByAccessibilityId(accessibilityId);
   4812             if (target == null || target.getVisibility() != View.VISIBLE) {
   4813                 return false;
   4814             }
   4815             // Get out of touch mode since accessibility wants to move focus around.
   4816             ensureTouchMode(false);
   4817             return target.requestFocus();
   4818         }
   4819 
   4820         private boolean performActionClearFocus(int accessibilityId) {
   4821             View target = findViewByAccessibilityId(accessibilityId);
   4822             if (target == null || target.getVisibility() != View.VISIBLE) {
   4823                 return false;
   4824             }
   4825             if (!target.isFocused()) {
   4826                 return false;
   4827             }
   4828             target.clearFocus();
   4829             return !target.isFocused();
   4830         }
   4831 
   4832         private boolean performActionSelect(int accessibilityId) {
   4833             View target = findViewByAccessibilityId(accessibilityId);
   4834             if (target == null || target.getVisibility() != View.VISIBLE) {
   4835                 return false;
   4836             }
   4837             if (target.isSelected()) {
   4838                 return false;
   4839             }
   4840             target.setSelected(true);
   4841             return target.isSelected();
   4842         }
   4843 
   4844         private boolean performActionClearSelection(int accessibilityId) {
   4845             View target = findViewByAccessibilityId(accessibilityId);
   4846             if (target == null || target.getVisibility() != View.VISIBLE) {
   4847                 return false;
   4848             }
   4849             if (!target.isSelected()) {
   4850                 return false;
   4851             }
   4852             target.setSelected(false);
   4853             return !target.isSelected();
   4854         }
   4855 
   4856         private View findViewByAccessibilityId(int accessibilityId) {
   4857             View root = ViewRootImpl.this.mView;
   4858             if (root == null) {
   4859                 return null;
   4860             }
   4861             View foundView = root.findViewByAccessibilityId(accessibilityId);
   4862             if (foundView != null && foundView.getVisibility() != View.VISIBLE) {
   4863                 return null;
   4864             }
   4865             return foundView;
   4866         }
   4867     }
   4868 
   4869     private class SendWindowContentChangedAccessibilityEvent implements Runnable {
   4870         public volatile boolean mIsPending;
   4871 
   4872         public void run() {
   4873             if (mView != null) {
   4874                 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
   4875                 mIsPending = false;
   4876             }
   4877         }
   4878     }
   4879 }
   4880