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