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