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