Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.view;
     18 
     19 import android.Manifest;
     20 import android.animation.LayoutTransition;
     21 import android.animation.ValueAnimator;
     22 import android.app.ActivityManagerNative;
     23 import android.content.ClipDescription;
     24 import android.content.ComponentCallbacks;
     25 import android.content.ComponentCallbacks2;
     26 import android.content.Context;
     27 import android.content.pm.ApplicationInfo;
     28 import android.content.pm.PackageManager;
     29 import android.content.res.CompatibilityInfo;
     30 import android.content.res.Configuration;
     31 import android.content.res.Resources;
     32 import android.graphics.Canvas;
     33 import android.graphics.Paint;
     34 import android.graphics.PixelFormat;
     35 import android.graphics.Point;
     36 import android.graphics.PointF;
     37 import android.graphics.PorterDuff;
     38 import android.graphics.Rect;
     39 import android.graphics.Region;
     40 import android.graphics.drawable.Drawable;
     41 import android.media.AudioManager;
     42 import android.os.Binder;
     43 import android.os.Bundle;
     44 import android.os.Debug;
     45 import android.os.Handler;
     46 import android.os.LatencyTimer;
     47 import android.os.Looper;
     48 import android.os.Message;
     49 import android.os.ParcelFileDescriptor;
     50 import android.os.PowerManager;
     51 import android.os.Process;
     52 import android.os.RemoteException;
     53 import android.os.SystemClock;
     54 import android.os.SystemProperties;
     55 import android.os.Trace;
     56 import android.util.AndroidRuntimeException;
     57 import android.util.DisplayMetrics;
     58 import android.util.Log;
     59 import android.util.Slog;
     60 import android.util.TypedValue;
     61 import android.view.View.AttachInfo;
     62 import android.view.View.MeasureSpec;
     63 import android.view.accessibility.AccessibilityEvent;
     64 import android.view.accessibility.AccessibilityManager;
     65 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
     66 import android.view.accessibility.AccessibilityNodeInfo;
     67 import android.view.accessibility.AccessibilityNodeProvider;
     68 import android.view.accessibility.IAccessibilityInteractionConnection;
     69 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
     70 import android.view.animation.AccelerateDecelerateInterpolator;
     71 import android.view.animation.Interpolator;
     72 import android.view.inputmethod.InputConnection;
     73 import android.view.inputmethod.InputMethodManager;
     74 import android.widget.Scroller;
     75 
     76 import com.android.internal.R;
     77 import com.android.internal.policy.PolicyManager;
     78 import com.android.internal.view.BaseSurfaceHolder;
     79 import com.android.internal.view.IInputMethodCallback;
     80 import com.android.internal.view.IInputMethodSession;
     81 import com.android.internal.view.RootViewSurfaceTaker;
     82 
     83 import java.io.IOException;
     84 import java.io.OutputStream;
     85 import java.lang.ref.WeakReference;
     86 import java.util.ArrayList;
     87 import java.util.HashSet;
     88 
     89 /**
     90  * The top of a view hierarchy, implementing the needed protocol between View
     91  * and the WindowManager.  This is for the most part an internal implementation
     92  * detail of {@link WindowManagerImpl}.
     93  *
     94  * {@hide}
     95  */
     96 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
     97 public final class ViewRootImpl implements ViewParent,
     98         View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
     99     private static final String TAG = "ViewRootImpl";
    100     private static final boolean DBG = false;
    101     private static final boolean LOCAL_LOGV = false;
    102     /** @noinspection PointlessBooleanExpression*/
    103     private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
    104     private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
    105     private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
    106     private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
    107     private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
    108     private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
    109     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
    110     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
    111     private static final boolean DEBUG_FPS = false;
    112 
    113     private static final boolean USE_RENDER_THREAD = false;
    114 
    115     /**
    116      * Set this system property to true to force the view hierarchy to render
    117      * at 60 Hz. This can be used to measure the potential framerate.
    118      */
    119     private static final String PROPERTY_PROFILE_RENDERING = "viewancestor.profile_rendering";
    120 
    121     private static final boolean MEASURE_LATENCY = false;
    122     private static LatencyTimer lt;
    123 
    124     /**
    125      * Maximum time we allow the user to roll the trackball enough to generate
    126      * a key event, before resetting the counters.
    127      */
    128     static final int MAX_TRACKBALL_DELAY = 250;
    129 
    130     static IWindowSession sWindowSession;
    131 
    132     static final Object mStaticInit = new Object();
    133     static boolean mInitialized = false;
    134 
    135     static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
    136 
    137     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
    138     static boolean sFirstDrawComplete = false;
    139 
    140     static final ArrayList<ComponentCallbacks> sConfigCallbacks
    141             = new ArrayList<ComponentCallbacks>();
    142 
    143     private static boolean sUseRenderThread = false;
    144     private static boolean sRenderThreadQueried = false;
    145     private static final Object[] sRenderThreadQueryLock = new Object[0];
    146 
    147     long mLastTrackballTime = 0;
    148     final TrackballAxis mTrackballAxisX = new TrackballAxis();
    149     final TrackballAxis mTrackballAxisY = new TrackballAxis();
    150 
    151     int mLastJoystickXDirection;
    152     int mLastJoystickYDirection;
    153     int mLastJoystickXKeyCode;
    154     int mLastJoystickYKeyCode;
    155 
    156     final int[] mTmpLocation = new int[2];
    157 
    158     final TypedValue mTmpValue = new TypedValue();
    159 
    160     final InputMethodCallback mInputMethodCallback;
    161     final Thread mThread;
    162 
    163     final WindowLeaked mLocation;
    164 
    165     final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
    166 
    167     final W mWindow;
    168 
    169     final int mTargetSdkVersion;
    170 
    171     int mSeq;
    172 
    173     View mView;
    174     View mFocusedView;
    175     View mRealFocusedView;  // this is not set to null in touch mode
    176     View mOldFocusedView;
    177 
    178     View mAccessibilityFocusedHost;
    179     AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
    180 
    181     int mViewVisibility;
    182     boolean mAppVisible = true;
    183     int mOrigWindowType = -1;
    184 
    185     // Set to true if the owner of this window is in the stopped state,
    186     // so the window should no longer be active.
    187     boolean mStopped = false;
    188 
    189     boolean mLastInCompatMode = false;
    190 
    191     SurfaceHolder.Callback2 mSurfaceHolderCallback;
    192     BaseSurfaceHolder mSurfaceHolder;
    193     boolean mIsCreating;
    194     boolean mDrawingAllowed;
    195 
    196     final Region mTransparentRegion;
    197     final Region mPreviousTransparentRegion;
    198 
    199     int mWidth;
    200     int mHeight;
    201     Rect mDirty;
    202     final Rect mCurrentDirty = new Rect();
    203     final Rect mPreviousDirty = new Rect();
    204     boolean mIsAnimating;
    205 
    206     CompatibilityInfo.Translator mTranslator;
    207 
    208     final View.AttachInfo mAttachInfo;
    209     InputChannel mInputChannel;
    210     InputQueue.Callback mInputQueueCallback;
    211     InputQueue mInputQueue;
    212     FallbackEventHandler mFallbackEventHandler;
    213     Choreographer mChoreographer;
    214 
    215     final Rect mTempRect; // used in the transaction to not thrash the heap.
    216     final Rect mVisRect; // used to retrieve visible rect of focused view.
    217 
    218     boolean mTraversalScheduled;
    219     int mTraversalBarrier;
    220     boolean mWillDrawSoon;
    221     boolean mFitSystemWindowsRequested;
    222     boolean mLayoutRequested;
    223     boolean mFirst;
    224     boolean mReportNextDraw;
    225     boolean mFullRedrawNeeded;
    226     boolean mNewSurfaceNeeded;
    227     boolean mHasHadWindowFocus;
    228     boolean mLastWasImTarget;
    229     boolean mWindowsAnimating;
    230     boolean mIsDrawing;
    231     int mLastSystemUiVisibility;
    232     int mClientWindowLayoutFlags;
    233 
    234     // Pool of queued input events.
    235     private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
    236     private QueuedInputEvent mQueuedInputEventPool;
    237     private int mQueuedInputEventPoolSize;
    238 
    239     // Input event queue.
    240     QueuedInputEvent mFirstPendingInputEvent;
    241     QueuedInputEvent mCurrentInputEvent;
    242     boolean mProcessInputEventsScheduled;
    243 
    244     boolean mWindowAttributesChanged = false;
    245     int mWindowAttributesChangesFlag = 0;
    246 
    247     // These can be accessed by any thread, must be protected with a lock.
    248     // Surface can never be reassigned or cleared (use Surface.clear()).
    249     private final Surface mSurface = new Surface();
    250 
    251     boolean mAdded;
    252     boolean mAddedTouchMode;
    253 
    254     CompatibilityInfoHolder mCompatibilityInfo;
    255 
    256     /*package*/ int mAddNesting;
    257 
    258     // These are accessed by multiple threads.
    259     final Rect mWinFrame; // frame given by window manager.
    260 
    261     final Rect mPendingVisibleInsets = new Rect();
    262     final Rect mPendingContentInsets = new Rect();
    263     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
    264             = new ViewTreeObserver.InternalInsetsInfo();
    265 
    266     final Rect mFitSystemWindowsInsets = new Rect();
    267 
    268     final Configuration mLastConfiguration = new Configuration();
    269     final Configuration mPendingConfiguration = new Configuration();
    270 
    271     class ResizedInfo {
    272         Rect contentInsets;
    273         Rect visibleInsets;
    274         Configuration newConfig;
    275     }
    276 
    277     boolean mScrollMayChange;
    278     int mSoftInputMode;
    279     View mLastScrolledFocus;
    280     int mScrollY;
    281     int mCurScrollY;
    282     Scroller mScroller;
    283     HardwareLayer mResizeBuffer;
    284     long mResizeBufferStartTime;
    285     int mResizeBufferDuration;
    286     static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
    287     private ArrayList<LayoutTransition> mPendingTransitions;
    288 
    289     final ViewConfiguration mViewConfiguration;
    290 
    291     /* Drag/drop */
    292     ClipDescription mDragDescription;
    293     View mCurrentDragView;
    294     volatile Object mLocalDragState;
    295     final PointF mDragPoint = new PointF();
    296     final PointF mLastTouchPoint = new PointF();
    297 
    298     private boolean mProfileRendering;
    299     private Thread mRenderProfiler;
    300     private volatile boolean mRenderProfilingEnabled;
    301 
    302     // Variables to track frames per second, enabled via DEBUG_FPS flag
    303     private long mFpsStartTime = -1;
    304     private long mFpsPrevTime = -1;
    305     private int mFpsNumFrames;
    306 
    307     private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>(24);
    308 
    309     /**
    310      * see {@link #playSoundEffect(int)}
    311      */
    312     AudioManager mAudioManager;
    313 
    314     final AccessibilityManager mAccessibilityManager;
    315 
    316     AccessibilityInteractionController mAccessibilityInteractionController;
    317 
    318     AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
    319 
    320     SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
    321 
    322     HashSet<View> mTempHashSet;
    323 
    324     private final int mDensity;
    325 
    326     /**
    327      * Consistency verifier for debugging purposes.
    328      */
    329     protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
    330             InputEventConsistencyVerifier.isInstrumentationEnabled() ?
    331                     new InputEventConsistencyVerifier(this, 0) : null;
    332 
    333     public static IWindowSession getWindowSession(Looper mainLooper) {
    334         synchronized (mStaticInit) {
    335             if (!mInitialized) {
    336                 try {
    337                     InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
    338                     IWindowManager windowManager = Display.getWindowManager();
    339                     sWindowSession = windowManager.openSession(
    340                             imm.getClient(), imm.getInputContext());
    341                     float animatorScale = windowManager.getAnimationScale(2);
    342                     ValueAnimator.setDurationScale(animatorScale);
    343                     mInitialized = true;
    344                 } catch (RemoteException e) {
    345                 }
    346             }
    347             return sWindowSession;
    348         }
    349     }
    350 
    351     static final class SystemUiVisibilityInfo {
    352         int seq;
    353         int globalVisibility;
    354         int localValue;
    355         int localChanges;
    356     }
    357 
    358     public ViewRootImpl(Context context) {
    359         super();
    360 
    361         if (MEASURE_LATENCY) {
    362             if (lt == null) {
    363                 lt = new LatencyTimer(100, 1000);
    364             }
    365         }
    366 
    367         // Initialize the statics when this class is first instantiated. This is
    368         // done here instead of in the static block because Zygote does not
    369         // allow the spawning of threads.
    370         getWindowSession(context.getMainLooper());
    371 
    372         mThread = Thread.currentThread();
    373         mLocation = new WindowLeaked(null);
    374         mLocation.fillInStackTrace();
    375         mWidth = -1;
    376         mHeight = -1;
    377         mDirty = new Rect();
    378         mTempRect = new Rect();
    379         mVisRect = new Rect();
    380         mWinFrame = new Rect();
    381         mWindow = new W(this);
    382         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
    383         mInputMethodCallback = new InputMethodCallback(this);
    384         mViewVisibility = View.GONE;
    385         mTransparentRegion = new Region();
    386         mPreviousTransparentRegion = new Region();
    387         mFirst = true; // true for the first time the view is added
    388         mAdded = false;
    389         mAccessibilityManager = AccessibilityManager.getInstance(context);
    390         mAccessibilityInteractionConnectionManager =
    391             new AccessibilityInteractionConnectionManager();
    392         mAccessibilityManager.addAccessibilityStateChangeListener(
    393                 mAccessibilityInteractionConnectionManager);
    394         mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, mHandler, this);
    395         mViewConfiguration = ViewConfiguration.get(context);
    396         mDensity = context.getResources().getDisplayMetrics().densityDpi;
    397         mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
    398         mProfileRendering = Boolean.parseBoolean(
    399                 SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false"));
    400         mChoreographer = Choreographer.getInstance();
    401 
    402         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    403         mAttachInfo.mScreenOn = powerManager.isScreenOn();
    404         loadSystemProperties();
    405     }
    406 
    407     /**
    408      * @return True if the application requests the use of a separate render thread,
    409      *         false otherwise
    410      */
    411     private static boolean isRenderThreadRequested(Context context) {
    412         if (USE_RENDER_THREAD) {
    413             synchronized (sRenderThreadQueryLock) {
    414                 if (!sRenderThreadQueried) {
    415                     final PackageManager packageManager = context.getPackageManager();
    416                     final String packageName = context.getApplicationInfo().packageName;
    417                     try {
    418                         ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
    419                                 PackageManager.GET_META_DATA);
    420                         if (applicationInfo.metaData != null) {
    421                             sUseRenderThread = applicationInfo.metaData.getBoolean(
    422                                     "android.graphics.renderThread", false);
    423                         }
    424                     } catch (PackageManager.NameNotFoundException e) {
    425                     } finally {
    426                         sRenderThreadQueried = true;
    427                     }
    428                 }
    429                 return sUseRenderThread;
    430             }
    431         } else {
    432             return false;
    433         }
    434     }
    435 
    436     public static void addFirstDrawHandler(Runnable callback) {
    437         synchronized (sFirstDrawHandlers) {
    438             if (!sFirstDrawComplete) {
    439                 sFirstDrawHandlers.add(callback);
    440             }
    441         }
    442     }
    443 
    444     public static void addConfigCallback(ComponentCallbacks callback) {
    445         synchronized (sConfigCallbacks) {
    446             sConfigCallbacks.add(callback);
    447         }
    448     }
    449 
    450     // FIXME for perf testing only
    451     private boolean mProfile = false;
    452 
    453     /**
    454      * Call this to profile the next traversal call.
    455      * FIXME for perf testing only. Remove eventually
    456      */
    457     public void profile() {
    458         mProfile = true;
    459     }
    460 
    461     /**
    462      * Indicates whether we are in touch mode. Calling this method triggers an IPC
    463      * call and should be avoided whenever possible.
    464      *
    465      * @return True, if the device is in touch mode, false otherwise.
    466      *
    467      * @hide
    468      */
    469     static boolean isInTouchMode() {
    470         if (mInitialized) {
    471             try {
    472                 return sWindowSession.getInTouchMode();
    473             } catch (RemoteException e) {
    474             }
    475         }
    476         return false;
    477     }
    478 
    479     /**
    480      * We have one child
    481      */
    482     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    483         synchronized (this) {
    484             if (mView == null) {
    485                 mView = view;
    486                 mFallbackEventHandler.setView(view);
    487                 mWindowAttributes.copyFrom(attrs);
    488                 attrs = mWindowAttributes;
    489                 // Keep track of the actual window flags supplied by the client.
    490                 mClientWindowLayoutFlags = attrs.flags;
    491 
    492                 setAccessibilityFocus(null, null);
    493 
    494                 if (view instanceof RootViewSurfaceTaker) {
    495                     mSurfaceHolderCallback =
    496                             ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
    497                     if (mSurfaceHolderCallback != null) {
    498                         mSurfaceHolder = new TakenSurfaceHolder();
    499                         mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
    500                     }
    501                 }
    502 
    503                 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
    504                 mTranslator = compatibilityInfo.getTranslator();
    505 
    506                 // If the application owns the surface, don't enable hardware acceleration
    507                 if (mSurfaceHolder == null) {
    508                     enableHardwareAcceleration(mView.getContext(), attrs);
    509                 }
    510 
    511                 boolean restore = false;
    512                 if (mTranslator != null) {
    513                     mSurface.setCompatibilityTranslator(mTranslator);
    514                     restore = true;
    515                     attrs.backup();
    516                     mTranslator.translateWindowLayout(attrs);
    517                 }
    518                 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
    519 
    520                 if (!compatibilityInfo.supportsScreen()) {
    521                     attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
    522                     mLastInCompatMode = true;
    523                 }
    524 
    525                 mSoftInputMode = attrs.softInputMode;
    526                 mWindowAttributesChanged = true;
    527                 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
    528                 mAttachInfo.mRootView = view;
    529                 mAttachInfo.mScalingRequired = mTranslator != null;
    530                 mAttachInfo.mApplicationScale =
    531                         mTranslator == null ? 1.0f : mTranslator.applicationScale;
    532                 if (panelParentView != null) {
    533                     mAttachInfo.mPanelParentWindowToken
    534                             = panelParentView.getApplicationWindowToken();
    535                 }
    536                 mAdded = true;
    537                 int res; /* = WindowManagerImpl.ADD_OKAY; */
    538 
    539                 // Schedule the first layout -before- adding to the window
    540                 // manager, to make sure we do the relayout before receiving
    541                 // any other events from the system.
    542                 requestLayout();
    543                 if ((mWindowAttributes.inputFeatures
    544                         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
    545                     mInputChannel = new InputChannel();
    546                 }
    547                 try {
    548                     mOrigWindowType = mWindowAttributes.type;
    549                     mAttachInfo.mRecomputeGlobalAttributes = true;
    550                     collectViewAttributes();
    551                     res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
    552                             getHostVisibility(), mAttachInfo.mContentInsets,
    553                             mInputChannel);
    554                 } catch (RemoteException e) {
    555                     mAdded = false;
    556                     mView = null;
    557                     mAttachInfo.mRootView = null;
    558                     mInputChannel = null;
    559                     mFallbackEventHandler.setView(null);
    560                     unscheduleTraversals();
    561                     setAccessibilityFocus(null, null);
    562                     throw new RuntimeException("Adding window failed", e);
    563                 } finally {
    564                     if (restore) {
    565                         attrs.restore();
    566                     }
    567                 }
    568 
    569                 if (mTranslator != null) {
    570                     mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
    571                 }
    572                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
    573                 mPendingVisibleInsets.set(0, 0, 0, 0);
    574                 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
    575                 if (res < WindowManagerImpl.ADD_OKAY) {
    576                     mView = null;
    577                     mAttachInfo.mRootView = null;
    578                     mAdded = false;
    579                     mFallbackEventHandler.setView(null);
    580                     unscheduleTraversals();
    581                     setAccessibilityFocus(null, null);
    582                     switch (res) {
    583                         case WindowManagerImpl.ADD_BAD_APP_TOKEN:
    584                         case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
    585                             throw new WindowManagerImpl.BadTokenException(
    586                                 "Unable to add window -- token " + attrs.token
    587                                 + " is not valid; is your activity running?");
    588                         case WindowManagerImpl.ADD_NOT_APP_TOKEN:
    589                             throw new WindowManagerImpl.BadTokenException(
    590                                 "Unable to add window -- token " + attrs.token
    591                                 + " is not for an application");
    592                         case WindowManagerImpl.ADD_APP_EXITING:
    593                             throw new WindowManagerImpl.BadTokenException(
    594                                 "Unable to add window -- app for token " + attrs.token
    595                                 + " is exiting");
    596                         case WindowManagerImpl.ADD_DUPLICATE_ADD:
    597                             throw new WindowManagerImpl.BadTokenException(
    598                                 "Unable to add window -- window " + mWindow
    599                                 + " has already been added");
    600                         case WindowManagerImpl.ADD_STARTING_NOT_NEEDED:
    601                             // Silently ignore -- we would have just removed it
    602                             // right away, anyway.
    603                             return;
    604                         case WindowManagerImpl.ADD_MULTIPLE_SINGLETON:
    605                             throw new WindowManagerImpl.BadTokenException(
    606                                 "Unable to add window " + mWindow +
    607                                 " -- another window of this type already exists");
    608                         case WindowManagerImpl.ADD_PERMISSION_DENIED:
    609                             throw new WindowManagerImpl.BadTokenException(
    610                                 "Unable to add window " + mWindow +
    611                                 " -- permission denied for this window type");
    612                     }
    613                     throw new RuntimeException(
    614                         "Unable to add window -- unknown error code " + res);
    615                 }
    616 
    617                 if (view instanceof RootViewSurfaceTaker) {
    618                     mInputQueueCallback =
    619                         ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
    620                 }
    621                 if (mInputChannel != null) {
    622                     if (mInputQueueCallback != null) {
    623                         mInputQueue = new InputQueue(mInputChannel);
    624                         mInputQueueCallback.onInputQueueCreated(mInputQueue);
    625                     } else {
    626                         mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
    627                                 Looper.myLooper());
    628                     }
    629                 }
    630 
    631                 view.assignParent(this);
    632                 mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0;
    633                 mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0;
    634 
    635                 if (mAccessibilityManager.isEnabled()) {
    636                     mAccessibilityInteractionConnectionManager.ensureConnection();
    637                 }
    638 
    639                 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
    640                     view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
    641                 }
    642             }
    643         }
    644     }
    645 
    646     void destroyHardwareResources() {
    647         if (mAttachInfo.mHardwareRenderer != null) {
    648             if (mAttachInfo.mHardwareRenderer.isEnabled()) {
    649                 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
    650             }
    651             mAttachInfo.mHardwareRenderer.destroy(false);
    652         }
    653     }
    654 
    655     void terminateHardwareResources() {
    656         if (mAttachInfo.mHardwareRenderer != null) {
    657             mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
    658             mAttachInfo.mHardwareRenderer.destroy(false);
    659         }
    660     }
    661 
    662     void destroyHardwareLayers() {
    663         if (mThread != Thread.currentThread()) {
    664             if (mAttachInfo.mHardwareRenderer != null &&
    665                     mAttachInfo.mHardwareRenderer.isEnabled()) {
    666                 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
    667             }
    668         } else {
    669             if (mAttachInfo.mHardwareRenderer != null &&
    670                     mAttachInfo.mHardwareRenderer.isEnabled()) {
    671                 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
    672             }
    673         }
    674     }
    675 
    676     public boolean attachFunctor(int functor) {
    677         //noinspection SimplifiableIfStatement
    678         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
    679             return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
    680         }
    681         return false;
    682     }
    683 
    684     public void detachFunctor(int functor) {
    685         if (mAttachInfo.mHardwareRenderer != null) {
    686             mAttachInfo.mHardwareRenderer.detachFunctor(functor);
    687         }
    688     }
    689 
    690     private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) {
    691         mAttachInfo.mHardwareAccelerated = false;
    692         mAttachInfo.mHardwareAccelerationRequested = false;
    693 
    694         // Don't enable hardware acceleration when the application is in compatibility mode
    695         if (mTranslator != null) return;
    696 
    697         // Try to enable hardware acceleration if requested
    698         final boolean hardwareAccelerated =
    699                 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
    700 
    701         if (hardwareAccelerated) {
    702             if (!HardwareRenderer.isAvailable()) {
    703                 return;
    704             }
    705 
    706             // Persistent processes (including the system) should not do
    707             // accelerated rendering on low-end devices.  In that case,
    708             // sRendererDisabled will be set.  In addition, the system process
    709             // itself should never do accelerated rendering.  In that case, both
    710             // sRendererDisabled and sSystemRendererDisabled are set.  When
    711             // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
    712             // can be used by code on the system process to escape that and enable
    713             // HW accelerated drawing.  (This is basically for the lock screen.)
    714 
    715             final boolean fakeHwAccelerated = (attrs.privateFlags &
    716                     WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
    717             final boolean forceHwAccelerated = (attrs.privateFlags &
    718                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
    719 
    720             if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
    721                     && forceHwAccelerated)) {
    722                 // Don't enable hardware acceleration when we're not on the main thread
    723                 if (!HardwareRenderer.sSystemRendererDisabled &&
    724                         Looper.getMainLooper() != Looper.myLooper()) {
    725                     Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
    726                             + "acceleration outside of the main thread, aborting");
    727                     return;
    728                 }
    729 
    730                 final boolean renderThread = isRenderThreadRequested(context);
    731                 if (renderThread) {
    732                     Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
    733                 }
    734 
    735                 if (mAttachInfo.mHardwareRenderer != null) {
    736                     mAttachInfo.mHardwareRenderer.destroy(true);
    737                 }
    738 
    739                 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
    740                 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
    741                 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
    742                         = mAttachInfo.mHardwareRenderer != null;
    743 
    744             } else if (fakeHwAccelerated) {
    745                 // The window had wanted to use hardware acceleration, but this
    746                 // is not allowed in its process.  By setting this flag, it can
    747                 // still render as if it was accelerated.  This is basically for
    748                 // the preview windows the window manager shows for launching
    749                 // applications, so they will look more like the app being launched.
    750                 mAttachInfo.mHardwareAccelerationRequested = true;
    751             }
    752         }
    753     }
    754 
    755     public View getView() {
    756         return mView;
    757     }
    758 
    759     final WindowLeaked getLocation() {
    760         return mLocation;
    761     }
    762 
    763     void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
    764         synchronized (this) {
    765             int oldSoftInputMode = mWindowAttributes.softInputMode;
    766             // Keep track of the actual window flags supplied by the client.
    767             mClientWindowLayoutFlags = attrs.flags;
    768             // preserve compatible window flag if exists.
    769             int compatibleWindowFlag =
    770                 mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
    771             // transfer over system UI visibility values as they carry current state.
    772             attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
    773             attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
    774             mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
    775             mWindowAttributes.flags |= compatibleWindowFlag;
    776 
    777             applyKeepScreenOnFlag(mWindowAttributes);
    778 
    779             if (newView) {
    780                 mSoftInputMode = attrs.softInputMode;
    781                 requestLayout();
    782             }
    783             // Don't lose the mode we last auto-computed.
    784             if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
    785                     == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
    786                 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
    787                         & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
    788                         | (oldSoftInputMode
    789                                 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
    790             }
    791             mWindowAttributesChanged = true;
    792             scheduleTraversals();
    793         }
    794     }
    795 
    796     void handleAppVisibility(boolean visible) {
    797         if (mAppVisible != visible) {
    798             mAppVisible = visible;
    799             scheduleTraversals();
    800         }
    801     }
    802 
    803     void handleGetNewSurface() {
    804         mNewSurfaceNeeded = true;
    805         mFullRedrawNeeded = true;
    806         scheduleTraversals();
    807     }
    808 
    809     void handleScreenStateChange(boolean on) {
    810         if (on != mAttachInfo.mScreenOn) {
    811             mAttachInfo.mScreenOn = on;
    812             if (mView != null) {
    813                 mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
    814             }
    815             if (on) {
    816                 mFullRedrawNeeded = true;
    817                 scheduleTraversals();
    818             }
    819         }
    820     }
    821 
    822     /**
    823      * {@inheritDoc}
    824      */
    825     public void requestFitSystemWindows() {
    826         checkThread();
    827         mFitSystemWindowsRequested = true;
    828         scheduleTraversals();
    829     }
    830 
    831     /**
    832      * {@inheritDoc}
    833      */
    834     public void requestLayout() {
    835         checkThread();
    836         mLayoutRequested = true;
    837         scheduleTraversals();
    838     }
    839 
    840     /**
    841      * {@inheritDoc}
    842      */
    843     public boolean isLayoutRequested() {
    844         return mLayoutRequested;
    845     }
    846 
    847     void invalidate() {
    848         mDirty.set(0, 0, mWidth, mHeight);
    849         scheduleTraversals();
    850     }
    851 
    852     void invalidateWorld(View view) {
    853         view.invalidate();
    854         if (view instanceof ViewGroup) {
    855             ViewGroup parent = (ViewGroup)view;
    856             for (int i=0; i<parent.getChildCount(); i++) {
    857                 invalidateWorld(parent.getChildAt(i));
    858             }
    859         }
    860     }
    861 
    862     public void invalidateChild(View child, Rect dirty) {
    863         invalidateChildInParent(null, dirty);
    864     }
    865 
    866     public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
    867         checkThread();
    868         if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
    869 
    870         if (dirty == null) {
    871             invalidate();
    872             return null;
    873         } else if (dirty.isEmpty()) {
    874             return null;
    875         }
    876 
    877         if (mCurScrollY != 0 || mTranslator != null) {
    878             mTempRect.set(dirty);
    879             dirty = mTempRect;
    880             if (mCurScrollY != 0) {
    881                 dirty.offset(0, -mCurScrollY);
    882             }
    883             if (mTranslator != null) {
    884                 mTranslator.translateRectInAppWindowToScreen(dirty);
    885             }
    886             if (mAttachInfo.mScalingRequired) {
    887                 dirty.inset(-1, -1);
    888             }
    889         }
    890 
    891         final Rect localDirty = mDirty;
    892         if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
    893             mAttachInfo.mSetIgnoreDirtyState = true;
    894             mAttachInfo.mIgnoreDirtyState = true;
    895         }
    896 
    897         // Add the new dirty rect to the current one
    898         localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
    899         // Intersect with the bounds of the window to skip
    900         // updates that lie outside of the visible region
    901         final float appScale = mAttachInfo.mApplicationScale;
    902         localDirty.intersect(0, 0,
    903                 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
    904 
    905         if (!mWillDrawSoon) {
    906             scheduleTraversals();
    907         }
    908 
    909         return null;
    910     }
    911 
    912     void setStopped(boolean stopped) {
    913         if (mStopped != stopped) {
    914             mStopped = stopped;
    915             if (!stopped) {
    916                 scheduleTraversals();
    917             }
    918         }
    919     }
    920 
    921     public ViewParent getParent() {
    922         return null;
    923     }
    924 
    925     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
    926         if (child != mView) {
    927             throw new RuntimeException("child is not mine, honest!");
    928         }
    929         // Note: don't apply scroll offset, because we want to know its
    930         // visibility in the virtual canvas being given to the view hierarchy.
    931         return r.intersect(0, 0, mWidth, mHeight);
    932     }
    933 
    934     public void bringChildToFront(View child) {
    935     }
    936 
    937     int getHostVisibility() {
    938         return mAppVisible ? mView.getVisibility() : View.GONE;
    939     }
    940 
    941     void disposeResizeBuffer() {
    942         if (mResizeBuffer != null) {
    943             mResizeBuffer.destroy();
    944             mResizeBuffer = null;
    945         }
    946     }
    947 
    948     /**
    949      * Add LayoutTransition to the list of transitions to be started in the next traversal.
    950      * This list will be cleared after the transitions on the list are start()'ed. These
    951      * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
    952      * happens during the layout phase of traversal, which we want to complete before any of the
    953      * animations are started (because those animations may side-effect properties that layout
    954      * depends upon, like the bounding rectangles of the affected views). So we add the transition
    955      * to the list and it is started just prior to starting the drawing phase of traversal.
    956      *
    957      * @param transition The LayoutTransition to be started on the next traversal.
    958      *
    959      * @hide
    960      */
    961     public void requestTransitionStart(LayoutTransition transition) {
    962         if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
    963             if (mPendingTransitions == null) {
    964                  mPendingTransitions = new ArrayList<LayoutTransition>();
    965             }
    966             mPendingTransitions.add(transition);
    967         }
    968     }
    969 
    970     void scheduleTraversals() {
    971         if (!mTraversalScheduled) {
    972             mTraversalScheduled = true;
    973             mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
    974             mChoreographer.postCallback(
    975                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    976             scheduleConsumeBatchedInput();
    977         }
    978     }
    979 
    980     void unscheduleTraversals() {
    981         if (mTraversalScheduled) {
    982             mTraversalScheduled = false;
    983             mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
    984             mChoreographer.removeCallbacks(
    985                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    986         }
    987     }
    988 
    989     void doTraversal() {
    990         if (mTraversalScheduled) {
    991             mTraversalScheduled = false;
    992             mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
    993 
    994             if (mProfile) {
    995                 Debug.startMethodTracing("ViewAncestor");
    996             }
    997 
    998             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
    999             try {
   1000                 performTraversals();
   1001             } finally {
   1002                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   1003             }
   1004 
   1005             if (mProfile) {
   1006                 Debug.stopMethodTracing();
   1007                 mProfile = false;
   1008             }
   1009         }
   1010     }
   1011 
   1012     private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
   1013         // Update window's global keep screen on flag: if a view has requested
   1014         // that the screen be kept on, then it is always set; otherwise, it is
   1015         // set to whatever the client last requested for the global state.
   1016         if (mAttachInfo.mKeepScreenOn) {
   1017             params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
   1018         } else {
   1019             params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
   1020                     | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
   1021         }
   1022     }
   1023 
   1024     private boolean collectViewAttributes() {
   1025         final View.AttachInfo attachInfo = mAttachInfo;
   1026         if (attachInfo.mRecomputeGlobalAttributes) {
   1027             //Log.i(TAG, "Computing view hierarchy attributes!");
   1028             attachInfo.mRecomputeGlobalAttributes = false;
   1029             boolean oldScreenOn = attachInfo.mKeepScreenOn;
   1030             int oldVis = attachInfo.mSystemUiVisibility;
   1031             boolean oldHasSystemUiListeners = attachInfo.mHasSystemUiListeners;
   1032             attachInfo.mKeepScreenOn = false;
   1033             attachInfo.mSystemUiVisibility = 0;
   1034             attachInfo.mHasSystemUiListeners = false;
   1035             mView.dispatchCollectViewAttributes(attachInfo, 0);
   1036             attachInfo.mSystemUiVisibility &= ~attachInfo.mDisabledSystemUiVisibility;
   1037             if (attachInfo.mKeepScreenOn != oldScreenOn
   1038                     || attachInfo.mSystemUiVisibility != oldVis
   1039                     || attachInfo.mHasSystemUiListeners != oldHasSystemUiListeners) {
   1040                 WindowManager.LayoutParams params = mWindowAttributes;
   1041                 applyKeepScreenOnFlag(params);
   1042                 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
   1043                 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
   1044                 mView.dispatchWindowSystemUiVisiblityChanged(attachInfo.mSystemUiVisibility);
   1045                 return true;
   1046             }
   1047         }
   1048         return false;
   1049     }
   1050 
   1051     private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
   1052             final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
   1053         int childWidthMeasureSpec;
   1054         int childHeightMeasureSpec;
   1055         boolean windowSizeMayChange = false;
   1056 
   1057         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
   1058                 "Measuring " + host + " in display " + desiredWindowWidth
   1059                 + "x" + desiredWindowHeight + "...");
   1060 
   1061         boolean goodMeasure = false;
   1062         if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
   1063             // On large screens, we don't want to allow dialogs to just
   1064             // stretch to fill the entire width of the screen to display
   1065             // one line of text.  First try doing the layout at a smaller
   1066             // size to see if it will fit.
   1067             final DisplayMetrics packageMetrics = res.getDisplayMetrics();
   1068             res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
   1069             int baseSize = 0;
   1070             if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
   1071                 baseSize = (int)mTmpValue.getDimension(packageMetrics);
   1072             }
   1073             if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
   1074             if (baseSize != 0 && desiredWindowWidth > baseSize) {
   1075                 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
   1076                 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
   1077                 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   1078                 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
   1079                         + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
   1080                 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
   1081                     goodMeasure = true;
   1082                 } else {
   1083                     // Didn't fit in that size... try expanding a bit.
   1084                     baseSize = (baseSize+desiredWindowWidth)/2;
   1085                     if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
   1086                             + baseSize);
   1087                     childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
   1088                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   1089                     if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
   1090                             + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
   1091                     if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
   1092                         if (DEBUG_DIALOG) Log.v(TAG, "Good!");
   1093                         goodMeasure = true;
   1094                     }
   1095                 }
   1096             }
   1097         }
   1098 
   1099         if (!goodMeasure) {
   1100             childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
   1101             childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
   1102             performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   1103             if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
   1104                 windowSizeMayChange = true;
   1105             }
   1106         }
   1107 
   1108         if (DBG) {
   1109             System.out.println("======================================");
   1110             System.out.println("performTraversals -- after measure");
   1111             host.debug();
   1112         }
   1113 
   1114         return windowSizeMayChange;
   1115     }
   1116 
   1117     private void performTraversals() {
   1118         // cache mView since it is used so much below...
   1119         final View host = mView;
   1120 
   1121         if (DBG) {
   1122             System.out.println("======================================");
   1123             System.out.println("performTraversals");
   1124             host.debug();
   1125         }
   1126 
   1127         if (host == null || !mAdded)
   1128             return;
   1129 
   1130         mWillDrawSoon = true;
   1131         boolean windowSizeMayChange = false;
   1132         boolean newSurface = false;
   1133         boolean surfaceChanged = false;
   1134         WindowManager.LayoutParams lp = mWindowAttributes;
   1135 
   1136         int desiredWindowWidth;
   1137         int desiredWindowHeight;
   1138 
   1139         final View.AttachInfo attachInfo = mAttachInfo;
   1140 
   1141         final int viewVisibility = getHostVisibility();
   1142         boolean viewVisibilityChanged = mViewVisibility != viewVisibility
   1143                 || mNewSurfaceNeeded;
   1144 
   1145         WindowManager.LayoutParams params = null;
   1146         if (mWindowAttributesChanged) {
   1147             mWindowAttributesChanged = false;
   1148             surfaceChanged = true;
   1149             params = lp;
   1150         }
   1151         CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
   1152         if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
   1153             params = lp;
   1154             mFullRedrawNeeded = true;
   1155             mLayoutRequested = true;
   1156             if (mLastInCompatMode) {
   1157                 params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
   1158                 mLastInCompatMode = false;
   1159             } else {
   1160                 params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
   1161                 mLastInCompatMode = true;
   1162             }
   1163         }
   1164 
   1165         mWindowAttributesChangesFlag = 0;
   1166 
   1167         Rect frame = mWinFrame;
   1168         if (mFirst) {
   1169             mFullRedrawNeeded = true;
   1170             mLayoutRequested = true;
   1171 
   1172             if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
   1173                 // NOTE -- system code, won't try to do compat mode.
   1174                 Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
   1175                 Point size = new Point();
   1176                 disp.getRealSize(size);
   1177                 desiredWindowWidth = size.x;
   1178                 desiredWindowHeight = size.y;
   1179             } else {
   1180                 DisplayMetrics packageMetrics =
   1181                     mView.getContext().getResources().getDisplayMetrics();
   1182                 desiredWindowWidth = packageMetrics.widthPixels;
   1183                 desiredWindowHeight = packageMetrics.heightPixels;
   1184             }
   1185 
   1186             // For the very first time, tell the view hierarchy that it
   1187             // is attached to the window.  Note that at this point the surface
   1188             // object is not initialized to its backing store, but soon it
   1189             // will be (assuming the window is visible).
   1190             attachInfo.mSurface = mSurface;
   1191             // We used to use the following condition to choose 32 bits drawing caches:
   1192             // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
   1193             // However, windows are now always 32 bits by default, so choose 32 bits
   1194             attachInfo.mUse32BitDrawingCache = true;
   1195             attachInfo.mHasWindowFocus = false;
   1196             attachInfo.mWindowVisibility = viewVisibility;
   1197             attachInfo.mRecomputeGlobalAttributes = false;
   1198             viewVisibilityChanged = false;
   1199             mLastConfiguration.setTo(host.getResources().getConfiguration());
   1200             mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
   1201             host.dispatchAttachedToWindow(attachInfo, 0);
   1202             mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
   1203             host.fitSystemWindows(mFitSystemWindowsInsets);
   1204             //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
   1205 
   1206         } else {
   1207             desiredWindowWidth = frame.width();
   1208             desiredWindowHeight = frame.height();
   1209             if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
   1210                 if (DEBUG_ORIENTATION) Log.v(TAG,
   1211                         "View " + host + " resized to: " + frame);
   1212                 mFullRedrawNeeded = true;
   1213                 mLayoutRequested = true;
   1214                 windowSizeMayChange = true;
   1215             }
   1216         }
   1217 
   1218         if (viewVisibilityChanged) {
   1219             attachInfo.mWindowVisibility = viewVisibility;
   1220             host.dispatchWindowVisibilityChanged(viewVisibility);
   1221             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
   1222                 destroyHardwareResources();
   1223             }
   1224             if (viewVisibility == View.GONE) {
   1225                 // After making a window gone, we will count it as being
   1226                 // shown for the first time the next time it gets focus.
   1227                 mHasHadWindowFocus = false;
   1228             }
   1229         }
   1230 
   1231         // Execute enqueued actions on every traversal in case a detached view enqueued an action
   1232         getRunQueue().executeActions(attachInfo.mHandler);
   1233 
   1234         boolean insetsChanged = false;
   1235 
   1236         boolean layoutRequested = mLayoutRequested && !mStopped;
   1237         if (layoutRequested) {
   1238 
   1239             final Resources res = mView.getContext().getResources();
   1240 
   1241             if (mFirst) {
   1242                 // make sure touch mode code executes by setting cached value
   1243                 // to opposite of the added touch mode.
   1244                 mAttachInfo.mInTouchMode = !mAddedTouchMode;
   1245                 ensureTouchModeLocally(mAddedTouchMode);
   1246             } else {
   1247                 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
   1248                     insetsChanged = true;
   1249                 }
   1250                 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
   1251                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
   1252                     if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
   1253                             + mAttachInfo.mVisibleInsets);
   1254                 }
   1255                 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
   1256                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
   1257                     windowSizeMayChange = true;
   1258 
   1259                     if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
   1260                         // NOTE -- system code, won't try to do compat mode.
   1261                         Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
   1262                         Point size = new Point();
   1263                         disp.getRealSize(size);
   1264                         desiredWindowWidth = size.x;
   1265                         desiredWindowHeight = size.y;
   1266                     } else {
   1267                         DisplayMetrics packageMetrics = res.getDisplayMetrics();
   1268                         desiredWindowWidth = packageMetrics.widthPixels;
   1269                         desiredWindowHeight = packageMetrics.heightPixels;
   1270                     }
   1271                 }
   1272             }
   1273 
   1274             // Ask host how big it wants to be
   1275             windowSizeMayChange |= measureHierarchy(host, lp, res,
   1276                     desiredWindowWidth, desiredWindowHeight);
   1277         }
   1278 
   1279         if (collectViewAttributes()) {
   1280             params = lp;
   1281         }
   1282         if (attachInfo.mForceReportNewAttributes) {
   1283             attachInfo.mForceReportNewAttributes = false;
   1284             params = lp;
   1285         }
   1286 
   1287         if (mFirst || attachInfo.mViewVisibilityChanged) {
   1288             attachInfo.mViewVisibilityChanged = false;
   1289             int resizeMode = mSoftInputMode &
   1290                     WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
   1291             // If we are in auto resize mode, then we need to determine
   1292             // what mode to use now.
   1293             if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
   1294                 final int N = attachInfo.mScrollContainers.size();
   1295                 for (int i=0; i<N; i++) {
   1296                     if (attachInfo.mScrollContainers.get(i).isShown()) {
   1297                         resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
   1298                     }
   1299                 }
   1300                 if (resizeMode == 0) {
   1301                     resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
   1302                 }
   1303                 if ((lp.softInputMode &
   1304                         WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
   1305                     lp.softInputMode = (lp.softInputMode &
   1306                             ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
   1307                             resizeMode;
   1308                     params = lp;
   1309                 }
   1310             }
   1311         }
   1312 
   1313         if (params != null && (host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
   1314             if (!PixelFormat.formatHasAlpha(params.format)) {
   1315                 params.format = PixelFormat.TRANSLUCENT;
   1316             }
   1317         }
   1318 
   1319         if (mFitSystemWindowsRequested) {
   1320             mFitSystemWindowsRequested = false;
   1321             mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
   1322             host.fitSystemWindows(mFitSystemWindowsInsets);
   1323             if (mLayoutRequested) {
   1324                 // Short-circuit catching a new layout request here, so
   1325                 // we don't need to go through two layout passes when things
   1326                 // change due to fitting system windows, which can happen a lot.
   1327                 windowSizeMayChange |= measureHierarchy(host, lp,
   1328                         mView.getContext().getResources(),
   1329                         desiredWindowWidth, desiredWindowHeight);
   1330             }
   1331         }
   1332 
   1333         if (layoutRequested) {
   1334             // Clear this now, so that if anything requests a layout in the
   1335             // rest of this function we will catch it and re-run a full
   1336             // layout pass.
   1337             mLayoutRequested = false;
   1338         }
   1339 
   1340         boolean windowShouldResize = layoutRequested && windowSizeMayChange
   1341             && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
   1342                 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
   1343                         frame.width() < desiredWindowWidth && frame.width() != mWidth)
   1344                 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
   1345                         frame.height() < desiredWindowHeight && frame.height() != mHeight));
   1346 
   1347         final boolean computesInternalInsets =
   1348                 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
   1349 
   1350         boolean insetsPending = false;
   1351         int relayoutResult = 0;
   1352 
   1353         if (mFirst || windowShouldResize || insetsChanged ||
   1354                 viewVisibilityChanged || params != null) {
   1355 
   1356             if (viewVisibility == View.VISIBLE) {
   1357                 // If this window is giving internal insets to the window
   1358                 // manager, and it is being added or changing its visibility,
   1359                 // then we want to first give the window manager "fake"
   1360                 // insets to cause it to effectively ignore the content of
   1361                 // the window during layout.  This avoids it briefly causing
   1362                 // other windows to resize/move based on the raw frame of the
   1363                 // window, waiting until we can finish laying out this window
   1364                 // and get back to the window manager with the ultimately
   1365                 // computed insets.
   1366                 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
   1367             }
   1368 
   1369             if (mSurfaceHolder != null) {
   1370                 mSurfaceHolder.mSurfaceLock.lock();
   1371                 mDrawingAllowed = true;
   1372             }
   1373 
   1374             boolean hwInitialized = false;
   1375             boolean contentInsetsChanged = false;
   1376             boolean visibleInsetsChanged;
   1377             boolean hadSurface = mSurface.isValid();
   1378 
   1379             try {
   1380                 if (DEBUG_LAYOUT) {
   1381                     Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
   1382                             host.getMeasuredHeight() + ", params=" + params);
   1383                 }
   1384 
   1385                 final int surfaceGenerationId = mSurface.getGenerationId();
   1386                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
   1387 
   1388                 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
   1389                         + " content=" + mPendingContentInsets.toShortString()
   1390                         + " visible=" + mPendingVisibleInsets.toShortString()
   1391                         + " surface=" + mSurface);
   1392 
   1393                 if (mPendingConfiguration.seq != 0) {
   1394                     if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
   1395                             + mPendingConfiguration);
   1396                     updateConfiguration(mPendingConfiguration, !mFirst);
   1397                     mPendingConfiguration.seq = 0;
   1398                 }
   1399 
   1400                 contentInsetsChanged = !mPendingContentInsets.equals(
   1401                         mAttachInfo.mContentInsets);
   1402                 visibleInsetsChanged = !mPendingVisibleInsets.equals(
   1403                         mAttachInfo.mVisibleInsets);
   1404                 if (contentInsetsChanged) {
   1405                     if (mWidth > 0 && mHeight > 0 && lp != null &&
   1406                             ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
   1407                                     & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
   1408                             mSurface != null && mSurface.isValid() &&
   1409                             !mAttachInfo.mTurnOffWindowResizeAnim &&
   1410                             mAttachInfo.mHardwareRenderer != null &&
   1411                             mAttachInfo.mHardwareRenderer.isEnabled() &&
   1412                             mAttachInfo.mHardwareRenderer.validate() &&
   1413                             lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
   1414 
   1415                         disposeResizeBuffer();
   1416 
   1417                         boolean completed = false;
   1418                         HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
   1419                         HardwareCanvas layerCanvas = null;
   1420                         try {
   1421                             if (mResizeBuffer == null) {
   1422                                 mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
   1423                                         mWidth, mHeight, false);
   1424                             } else if (mResizeBuffer.getWidth() != mWidth ||
   1425                                     mResizeBuffer.getHeight() != mHeight) {
   1426                                 mResizeBuffer.resize(mWidth, mHeight);
   1427                             }
   1428                             layerCanvas = mResizeBuffer.start(hwRendererCanvas);
   1429                             layerCanvas.setViewport(mWidth, mHeight);
   1430                             layerCanvas.onPreDraw(null);
   1431                             final int restoreCount = layerCanvas.save();
   1432 
   1433                             layerCanvas.drawColor(0xff000000, PorterDuff.Mode.SRC);
   1434 
   1435                             int yoff;
   1436                             final boolean scrolling = mScroller != null
   1437                                     && mScroller.computeScrollOffset();
   1438                             if (scrolling) {
   1439                                 yoff = mScroller.getCurrY();
   1440                                 mScroller.abortAnimation();
   1441                             } else {
   1442                                 yoff = mScrollY;
   1443                             }
   1444 
   1445                             layerCanvas.translate(0, -yoff);
   1446                             if (mTranslator != null) {
   1447                                 mTranslator.translateCanvas(layerCanvas);
   1448                             }
   1449 
   1450                             mView.draw(layerCanvas);
   1451 
   1452                             drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
   1453 
   1454                             mResizeBufferStartTime = SystemClock.uptimeMillis();
   1455                             mResizeBufferDuration = mView.getResources().getInteger(
   1456                                     com.android.internal.R.integer.config_mediumAnimTime);
   1457                             completed = true;
   1458 
   1459                             layerCanvas.restoreToCount(restoreCount);
   1460                         } catch (OutOfMemoryError e) {
   1461                             Log.w(TAG, "Not enough memory for content change anim buffer", e);
   1462                         } finally {
   1463                             if (layerCanvas != null) {
   1464                                 layerCanvas.onPostDraw();
   1465                             }
   1466                             if (mResizeBuffer != null) {
   1467                                 mResizeBuffer.end(hwRendererCanvas);
   1468                                 if (!completed) {
   1469                                     mResizeBuffer.destroy();
   1470                                     mResizeBuffer = null;
   1471                                 }
   1472                             }
   1473                         }
   1474                     }
   1475                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
   1476                     if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
   1477                             + mAttachInfo.mContentInsets);
   1478                 }
   1479                 if (contentInsetsChanged || mLastSystemUiVisibility !=
   1480                         mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested) {
   1481                     mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
   1482                     mFitSystemWindowsRequested = false;
   1483                     mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
   1484                     host.fitSystemWindows(mFitSystemWindowsInsets);
   1485                 }
   1486                 if (visibleInsetsChanged) {
   1487                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
   1488                     if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
   1489                             + mAttachInfo.mVisibleInsets);
   1490                 }
   1491 
   1492                 if (!hadSurface) {
   1493                     if (mSurface.isValid()) {
   1494                         // If we are creating a new surface, then we need to
   1495                         // completely redraw it.  Also, when we get to the
   1496                         // point of drawing it we will hold off and schedule
   1497                         // a new traversal instead.  This is so we can tell the
   1498                         // window manager about all of the windows being displayed
   1499                         // before actually drawing them, so it can display then
   1500                         // all at once.
   1501                         newSurface = true;
   1502                         mFullRedrawNeeded = true;
   1503                         mPreviousTransparentRegion.setEmpty();
   1504 
   1505                         if (mAttachInfo.mHardwareRenderer != null) {
   1506                             try {
   1507                                 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(mHolder);
   1508                             } catch (Surface.OutOfResourcesException e) {
   1509                                 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
   1510                                 try {
   1511                                     if (!sWindowSession.outOfMemory(mWindow)) {
   1512                                         Slog.w(TAG, "No processes killed for memory; killing self");
   1513                                         Process.killProcess(Process.myPid());
   1514                                     }
   1515                                 } catch (RemoteException ex) {
   1516                                 }
   1517                                 mLayoutRequested = true;    // ask wm for a new surface next time.
   1518                                 return;
   1519                             }
   1520                         }
   1521                     }
   1522                 } else if (!mSurface.isValid()) {
   1523                     // If the surface has been removed, then reset the scroll
   1524                     // positions.
   1525                     mLastScrolledFocus = null;
   1526                     mScrollY = mCurScrollY = 0;
   1527                     if (mScroller != null) {
   1528                         mScroller.abortAnimation();
   1529                     }
   1530                     disposeResizeBuffer();
   1531                     // Our surface is gone
   1532                     if (mAttachInfo.mHardwareRenderer != null &&
   1533                             mAttachInfo.mHardwareRenderer.isEnabled()) {
   1534                         mAttachInfo.mHardwareRenderer.destroy(true);
   1535                     }
   1536                 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
   1537                         mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
   1538                     mFullRedrawNeeded = true;
   1539                     try {
   1540                         mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
   1541                     } catch (Surface.OutOfResourcesException e) {
   1542                         Log.e(TAG, "OutOfResourcesException updating HW surface", e);
   1543                         try {
   1544                             if (!sWindowSession.outOfMemory(mWindow)) {
   1545                                 Slog.w(TAG, "No processes killed for memory; killing self");
   1546                                 Process.killProcess(Process.myPid());
   1547                             }
   1548                         } catch (RemoteException ex) {
   1549                         }
   1550                         mLayoutRequested = true;    // ask wm for a new surface next time.
   1551                         return;
   1552                     }
   1553                 }
   1554             } catch (RemoteException e) {
   1555             }
   1556 
   1557             if (DEBUG_ORIENTATION) Log.v(
   1558                     TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
   1559 
   1560             attachInfo.mWindowLeft = frame.left;
   1561             attachInfo.mWindowTop = frame.top;
   1562 
   1563             // !!FIXME!! This next section handles the case where we did not get the
   1564             // window size we asked for. We should avoid this by getting a maximum size from
   1565             // the window session beforehand.
   1566             if (mWidth != frame.width() || mHeight != frame.height()) {
   1567                 mWidth = frame.width();
   1568                 mHeight = frame.height();
   1569             }
   1570 
   1571             if (mSurfaceHolder != null) {
   1572                 // The app owns the surface; tell it about what is going on.
   1573                 if (mSurface.isValid()) {
   1574                     // XXX .copyFrom() doesn't work!
   1575                     //mSurfaceHolder.mSurface.copyFrom(mSurface);
   1576                     mSurfaceHolder.mSurface = mSurface;
   1577                 }
   1578                 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
   1579                 mSurfaceHolder.mSurfaceLock.unlock();
   1580                 if (mSurface.isValid()) {
   1581                     if (!hadSurface) {
   1582                         mSurfaceHolder.ungetCallbacks();
   1583 
   1584                         mIsCreating = true;
   1585                         mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
   1586                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   1587                         if (callbacks != null) {
   1588                             for (SurfaceHolder.Callback c : callbacks) {
   1589                                 c.surfaceCreated(mSurfaceHolder);
   1590                             }
   1591                         }
   1592                         surfaceChanged = true;
   1593                     }
   1594                     if (surfaceChanged) {
   1595                         mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
   1596                                 lp.format, mWidth, mHeight);
   1597                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   1598                         if (callbacks != null) {
   1599                             for (SurfaceHolder.Callback c : callbacks) {
   1600                                 c.surfaceChanged(mSurfaceHolder, lp.format,
   1601                                         mWidth, mHeight);
   1602                             }
   1603                         }
   1604                     }
   1605                     mIsCreating = false;
   1606                 } else if (hadSurface) {
   1607                     mSurfaceHolder.ungetCallbacks();
   1608                     SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   1609                     mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
   1610                     if (callbacks != null) {
   1611                         for (SurfaceHolder.Callback c : callbacks) {
   1612                             c.surfaceDestroyed(mSurfaceHolder);
   1613                         }
   1614                     }
   1615                     mSurfaceHolder.mSurfaceLock.lock();
   1616                     try {
   1617                         mSurfaceHolder.mSurface = new Surface();
   1618                     } finally {
   1619                         mSurfaceHolder.mSurfaceLock.unlock();
   1620                     }
   1621                 }
   1622             }
   1623 
   1624             if (mAttachInfo.mHardwareRenderer != null &&
   1625                     mAttachInfo.mHardwareRenderer.isEnabled()) {
   1626                 if (hwInitialized || windowShouldResize ||
   1627                         mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
   1628                         mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
   1629                     mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
   1630                     if (!hwInitialized) {
   1631                         mAttachInfo.mHardwareRenderer.invalidate(mHolder);
   1632                     }
   1633                 }
   1634             }
   1635 
   1636             if (!mStopped) {
   1637                 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
   1638                         (relayoutResult&WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
   1639                 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
   1640                         || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
   1641                     int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
   1642                     int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
   1643 
   1644                     if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
   1645                             + mWidth + " measuredWidth=" + host.getMeasuredWidth()
   1646                             + " mHeight=" + mHeight
   1647                             + " measuredHeight=" + host.getMeasuredHeight()
   1648                             + " coveredInsetsChanged=" + contentInsetsChanged);
   1649 
   1650                      // Ask host how big it wants to be
   1651                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   1652 
   1653                     // Implementation of weights from WindowManager.LayoutParams
   1654                     // We just grow the dimensions as needed and re-measure if
   1655                     // needs be
   1656                     int width = host.getMeasuredWidth();
   1657                     int height = host.getMeasuredHeight();
   1658                     boolean measureAgain = false;
   1659 
   1660                     if (lp.horizontalWeight > 0.0f) {
   1661                         width += (int) ((mWidth - width) * lp.horizontalWeight);
   1662                         childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
   1663                                 MeasureSpec.EXACTLY);
   1664                         measureAgain = true;
   1665                     }
   1666                     if (lp.verticalWeight > 0.0f) {
   1667                         height += (int) ((mHeight - height) * lp.verticalWeight);
   1668                         childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
   1669                                 MeasureSpec.EXACTLY);
   1670                         measureAgain = true;
   1671                     }
   1672 
   1673                     if (measureAgain) {
   1674                         if (DEBUG_LAYOUT) Log.v(TAG,
   1675                                 "And hey let's measure once more: width=" + width
   1676                                 + " height=" + height);
   1677                         performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   1678                     }
   1679 
   1680                     layoutRequested = true;
   1681                 }
   1682             }
   1683         }
   1684 
   1685         final boolean didLayout = layoutRequested && !mStopped;
   1686         boolean triggerGlobalLayoutListener = didLayout
   1687                 || attachInfo.mRecomputeGlobalAttributes;
   1688         if (didLayout) {
   1689             performLayout();
   1690 
   1691             // By this point all views have been sized and positionned
   1692             // We can compute the transparent area
   1693 
   1694             if ((host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
   1695                 // start out transparent
   1696                 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
   1697                 host.getLocationInWindow(mTmpLocation);
   1698                 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
   1699                         mTmpLocation[0] + host.mRight - host.mLeft,
   1700                         mTmpLocation[1] + host.mBottom - host.mTop);
   1701 
   1702                 host.gatherTransparentRegion(mTransparentRegion);
   1703                 if (mTranslator != null) {
   1704                     mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
   1705                 }
   1706 
   1707                 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
   1708                     mPreviousTransparentRegion.set(mTransparentRegion);
   1709                     // reconfigure window manager
   1710                     try {
   1711                         sWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
   1712                     } catch (RemoteException e) {
   1713                     }
   1714                 }
   1715             }
   1716 
   1717             if (DBG) {
   1718                 System.out.println("======================================");
   1719                 System.out.println("performTraversals -- after setFrame");
   1720                 host.debug();
   1721             }
   1722         }
   1723 
   1724         if (triggerGlobalLayoutListener) {
   1725             attachInfo.mRecomputeGlobalAttributes = false;
   1726             attachInfo.mTreeObserver.dispatchOnGlobalLayout();
   1727 
   1728             if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
   1729                 postSendWindowContentChangedCallback(mView);
   1730             }
   1731         }
   1732 
   1733         if (computesInternalInsets) {
   1734             // Clear the original insets.
   1735             final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
   1736             insets.reset();
   1737 
   1738             // Compute new insets in place.
   1739             attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
   1740 
   1741             // Tell the window manager.
   1742             if (insetsPending || !mLastGivenInsets.equals(insets)) {
   1743                 mLastGivenInsets.set(insets);
   1744 
   1745                 // Translate insets to screen coordinates if needed.
   1746                 final Rect contentInsets;
   1747                 final Rect visibleInsets;
   1748                 final Region touchableRegion;
   1749                 if (mTranslator != null) {
   1750                     contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
   1751                     visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
   1752                     touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
   1753                 } else {
   1754                     contentInsets = insets.contentInsets;
   1755                     visibleInsets = insets.visibleInsets;
   1756                     touchableRegion = insets.touchableRegion;
   1757                 }
   1758 
   1759                 try {
   1760                     sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
   1761                             contentInsets, visibleInsets, touchableRegion);
   1762                 } catch (RemoteException e) {
   1763                 }
   1764             }
   1765         }
   1766 
   1767         boolean skipDraw = false;
   1768 
   1769         if (mFirst) {
   1770             // handle first focus request
   1771             if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
   1772                     + mView.hasFocus());
   1773             if (mView != null) {
   1774                 if (!mView.hasFocus()) {
   1775                     mView.requestFocus(View.FOCUS_FORWARD);
   1776                     mFocusedView = mRealFocusedView = mView.findFocus();
   1777                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
   1778                             + mFocusedView);
   1779                 } else {
   1780                     mRealFocusedView = mView.findFocus();
   1781                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
   1782                             + mRealFocusedView);
   1783                 }
   1784             }
   1785             if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_ANIMATING) != 0) {
   1786                 // The first time we relayout the window, if the system is
   1787                 // doing window animations, we want to hold of on any future
   1788                 // draws until the animation is done.
   1789                 mWindowsAnimating = true;
   1790             }
   1791         } else if (mWindowsAnimating) {
   1792             skipDraw = true;
   1793         }
   1794 
   1795         mFirst = false;
   1796         mWillDrawSoon = false;
   1797         mNewSurfaceNeeded = false;
   1798         mViewVisibility = viewVisibility;
   1799 
   1800         if (mAttachInfo.mHasWindowFocus) {
   1801             final boolean imTarget = WindowManager.LayoutParams
   1802                     .mayUseInputMethod(mWindowAttributes.flags);
   1803             if (imTarget != mLastWasImTarget) {
   1804                 mLastWasImTarget = imTarget;
   1805                 InputMethodManager imm = InputMethodManager.peekInstance();
   1806                 if (imm != null && imTarget) {
   1807                     imm.startGettingWindowFocus(mView);
   1808                     imm.onWindowFocus(mView, mView.findFocus(),
   1809                             mWindowAttributes.softInputMode,
   1810                             !mHasHadWindowFocus, mWindowAttributes.flags);
   1811                 }
   1812             }
   1813         }
   1814 
   1815         // Remember if we must report the next draw.
   1816         if ((relayoutResult & WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
   1817             mReportNextDraw = true;
   1818         }
   1819 
   1820         boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
   1821                 viewVisibility != View.VISIBLE;
   1822 
   1823         if (!cancelDraw && !newSurface) {
   1824             if (!skipDraw || mReportNextDraw) {
   1825                 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
   1826                     for (int i = 0; i < mPendingTransitions.size(); ++i) {
   1827                         mPendingTransitions.get(i).startChangingAnimations();
   1828                     }
   1829                     mPendingTransitions.clear();
   1830                 }
   1831 
   1832                 performDraw();
   1833             }
   1834         } else {
   1835             if (viewVisibility == View.VISIBLE) {
   1836                 // Try again
   1837                 scheduleTraversals();
   1838             } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
   1839                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
   1840                     mPendingTransitions.get(i).endChangingAnimations();
   1841                 }
   1842                 mPendingTransitions.clear();
   1843             }
   1844         }
   1845     }
   1846 
   1847     private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
   1848         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
   1849         try {
   1850             mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   1851         } finally {
   1852             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   1853         }
   1854     }
   1855 
   1856     private void performLayout() {
   1857         mLayoutRequested = false;
   1858         mScrollMayChange = true;
   1859 
   1860         final View host = mView;
   1861         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
   1862             Log.v(TAG, "Laying out " + host + " to (" +
   1863                     host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
   1864         }
   1865 
   1866         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
   1867         try {
   1868             host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
   1869         } finally {
   1870             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   1871         }
   1872     }
   1873 
   1874     public void requestTransparentRegion(View child) {
   1875         // the test below should not fail unless someone is messing with us
   1876         checkThread();
   1877         if (mView == child) {
   1878             mView.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
   1879             // Need to make sure we re-evaluate the window attributes next
   1880             // time around, to ensure the window has the correct format.
   1881             mWindowAttributesChanged = true;
   1882             mWindowAttributesChangesFlag = 0;
   1883             requestLayout();
   1884         }
   1885     }
   1886 
   1887     /**
   1888      * Figures out the measure spec for the root view in a window based on it's
   1889      * layout params.
   1890      *
   1891      * @param windowSize
   1892      *            The available width or height of the window
   1893      *
   1894      * @param rootDimension
   1895      *            The layout params for one dimension (width or height) of the
   1896      *            window.
   1897      *
   1898      * @return The measure spec to use to measure the root view.
   1899      */
   1900     private static int getRootMeasureSpec(int windowSize, int rootDimension) {
   1901         int measureSpec;
   1902         switch (rootDimension) {
   1903 
   1904         case ViewGroup.LayoutParams.MATCH_PARENT:
   1905             // Window can't resize. Force root view to be windowSize.
   1906             measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
   1907             break;
   1908         case ViewGroup.LayoutParams.WRAP_CONTENT:
   1909             // Window can resize. Set max size for root view.
   1910             measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
   1911             break;
   1912         default:
   1913             // Window wants to be an exact size. Force root view to be that size.
   1914             measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
   1915             break;
   1916         }
   1917         return measureSpec;
   1918     }
   1919 
   1920     int mHardwareYOffset;
   1921     int mResizeAlpha;
   1922     final Paint mResizePaint = new Paint();
   1923 
   1924     public void onHardwarePreDraw(HardwareCanvas canvas) {
   1925         canvas.translate(0, -mHardwareYOffset);
   1926     }
   1927 
   1928     public void onHardwarePostDraw(HardwareCanvas canvas) {
   1929         if (mResizeBuffer != null) {
   1930             mResizePaint.setAlpha(mResizeAlpha);
   1931             canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
   1932         }
   1933         drawAccessibilityFocusedDrawableIfNeeded(canvas);
   1934     }
   1935 
   1936     /**
   1937      * @hide
   1938      */
   1939     void outputDisplayList(View view) {
   1940         if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
   1941             DisplayList displayList = view.getDisplayList();
   1942             if (displayList != null) {
   1943                 mAttachInfo.mHardwareCanvas.outputDisplayList(displayList);
   1944             }
   1945         }
   1946     }
   1947 
   1948     /**
   1949      * @see #PROPERTY_PROFILE_RENDERING
   1950      */
   1951     private void profileRendering(boolean enabled) {
   1952         if (mProfileRendering) {
   1953             mRenderProfilingEnabled = enabled;
   1954             if (mRenderProfiler == null) {
   1955                 mRenderProfiler = new Thread(new Runnable() {
   1956                     @Override
   1957                     public void run() {
   1958                         Log.d(TAG, "Starting profiling thread");
   1959                         while (mRenderProfilingEnabled) {
   1960                             mAttachInfo.mHandler.post(new Runnable() {
   1961                                 @Override
   1962                                 public void run() {
   1963                                     mDirty.set(0, 0, mWidth, mHeight);
   1964                                     scheduleTraversals();
   1965                                 }
   1966                             });
   1967                             try {
   1968                                 // TODO: This should use vsync when we get an API
   1969                                 Thread.sleep(15);
   1970                             } catch (InterruptedException e) {
   1971                                 Log.d(TAG, "Exiting profiling thread");
   1972                             }
   1973                         }
   1974                     }
   1975                 }, "Rendering Profiler");
   1976                 mRenderProfiler.start();
   1977             } else {
   1978                 mRenderProfiler.interrupt();
   1979                 mRenderProfiler = null;
   1980             }
   1981         }
   1982     }
   1983 
   1984     /**
   1985      * Called from draw() when DEBUG_FPS is enabled
   1986      */
   1987     private void trackFPS() {
   1988         // Tracks frames per second drawn. First value in a series of draws may be bogus
   1989         // because it down not account for the intervening idle time
   1990         long nowTime = System.currentTimeMillis();
   1991         if (mFpsStartTime < 0) {
   1992             mFpsStartTime = mFpsPrevTime = nowTime;
   1993             mFpsNumFrames = 0;
   1994         } else {
   1995             ++mFpsNumFrames;
   1996             String thisHash = Integer.toHexString(System.identityHashCode(this));
   1997             long frameTime = nowTime - mFpsPrevTime;
   1998             long totalTime = nowTime - mFpsStartTime;
   1999             Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
   2000             mFpsPrevTime = nowTime;
   2001             if (totalTime > 1000) {
   2002                 float fps = (float) mFpsNumFrames * 1000 / totalTime;
   2003                 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
   2004                 mFpsStartTime = nowTime;
   2005                 mFpsNumFrames = 0;
   2006             }
   2007         }
   2008     }
   2009 
   2010     private void performDraw() {
   2011         if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
   2012             return;
   2013         }
   2014 
   2015         final boolean fullRedrawNeeded = mFullRedrawNeeded;
   2016         mFullRedrawNeeded = false;
   2017 
   2018         mIsDrawing = true;
   2019         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
   2020         try {
   2021             draw(fullRedrawNeeded);
   2022         } finally {
   2023             mIsDrawing = false;
   2024             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   2025         }
   2026 
   2027         if (mReportNextDraw) {
   2028             mReportNextDraw = false;
   2029 
   2030             if (LOCAL_LOGV) {
   2031                 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
   2032             }
   2033             if (mSurfaceHolder != null && mSurface.isValid()) {
   2034                 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
   2035                 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   2036                 if (callbacks != null) {
   2037                     for (SurfaceHolder.Callback c : callbacks) {
   2038                         if (c instanceof SurfaceHolder.Callback2) {
   2039                             ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
   2040                                     mSurfaceHolder);
   2041                         }
   2042                     }
   2043                 }
   2044             }
   2045             try {
   2046                 sWindowSession.finishDrawing(mWindow);
   2047             } catch (RemoteException e) {
   2048             }
   2049         }
   2050     }
   2051 
   2052     private void draw(boolean fullRedrawNeeded) {
   2053         Surface surface = mSurface;
   2054         if (surface == null || !surface.isValid()) {
   2055             return;
   2056         }
   2057 
   2058         if (DEBUG_FPS) {
   2059             trackFPS();
   2060         }
   2061 
   2062         if (!sFirstDrawComplete) {
   2063             synchronized (sFirstDrawHandlers) {
   2064                 sFirstDrawComplete = true;
   2065                 final int count = sFirstDrawHandlers.size();
   2066                 for (int i = 0; i< count; i++) {
   2067                     mHandler.post(sFirstDrawHandlers.get(i));
   2068                 }
   2069             }
   2070         }
   2071 
   2072         scrollToRectOrFocus(null, false);
   2073 
   2074         final AttachInfo attachInfo = mAttachInfo;
   2075         if (attachInfo.mViewScrollChanged) {
   2076             attachInfo.mViewScrollChanged = false;
   2077             attachInfo.mTreeObserver.dispatchOnScrollChanged();
   2078         }
   2079 
   2080         int yoff;
   2081         boolean animating = mScroller != null && mScroller.computeScrollOffset();
   2082         if (animating) {
   2083             yoff = mScroller.getCurrY();
   2084         } else {
   2085             yoff = mScrollY;
   2086         }
   2087         if (mCurScrollY != yoff) {
   2088             mCurScrollY = yoff;
   2089             fullRedrawNeeded = true;
   2090         }
   2091 
   2092         final float appScale = attachInfo.mApplicationScale;
   2093         final boolean scalingRequired = attachInfo.mScalingRequired;
   2094 
   2095         int resizeAlpha = 0;
   2096         if (mResizeBuffer != null) {
   2097             long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
   2098             if (deltaTime < mResizeBufferDuration) {
   2099                 float amt = deltaTime/(float) mResizeBufferDuration;
   2100                 amt = mResizeInterpolator.getInterpolation(amt);
   2101                 animating = true;
   2102                 resizeAlpha = 255 - (int)(amt*255);
   2103             } else {
   2104                 disposeResizeBuffer();
   2105             }
   2106         }
   2107 
   2108         final Rect dirty = mDirty;
   2109         if (mSurfaceHolder != null) {
   2110             // The app owns the surface, we won't draw.
   2111             dirty.setEmpty();
   2112             if (animating) {
   2113                 if (mScroller != null) {
   2114                     mScroller.abortAnimation();
   2115                 }
   2116                 disposeResizeBuffer();
   2117             }
   2118             return;
   2119         }
   2120 
   2121         if (fullRedrawNeeded) {
   2122             attachInfo.mIgnoreDirtyState = true;
   2123             dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
   2124         }
   2125 
   2126         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
   2127             Log.v(TAG, "Draw " + mView + "/"
   2128                     + mWindowAttributes.getTitle()
   2129                     + ": dirty={" + dirty.left + "," + dirty.top
   2130                     + "," + dirty.right + "," + dirty.bottom + "} surface="
   2131                     + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
   2132                     appScale + ", width=" + mWidth + ", height=" + mHeight);
   2133         }
   2134 
   2135         attachInfo.mTreeObserver.dispatchOnDraw();
   2136 
   2137         if (!dirty.isEmpty() || mIsAnimating) {
   2138             if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
   2139                 // Draw with hardware renderer.
   2140                 mIsAnimating = false;
   2141                 mHardwareYOffset = yoff;
   2142                 mResizeAlpha = resizeAlpha;
   2143 
   2144                 mCurrentDirty.set(dirty);
   2145                 mCurrentDirty.union(mPreviousDirty);
   2146                 mPreviousDirty.set(dirty);
   2147                 dirty.setEmpty();
   2148 
   2149                 if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
   2150                         animating ? null : mCurrentDirty)) {
   2151                     mPreviousDirty.set(0, 0, mWidth, mHeight);
   2152                 }
   2153             } else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
   2154                 return;
   2155             }
   2156         }
   2157 
   2158         if (animating) {
   2159             mFullRedrawNeeded = true;
   2160             scheduleTraversals();
   2161         }
   2162     }
   2163 
   2164     /**
   2165      * @return true if drawing was succesfull, false if an error occurred
   2166      */
   2167     private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
   2168             boolean scalingRequired, Rect dirty) {
   2169 
   2170         // If we get here with a disabled & requested hardware renderer, something went
   2171         // wrong (an invalidate posted right before we destroyed the hardware surface
   2172         // for instance) so we should just bail out. Locking the surface with software
   2173         // rendering at this point would lock it forever and prevent hardware renderer
   2174         // from doing its job when it comes back.
   2175         if (attachInfo.mHardwareRenderer != null && !attachInfo.mHardwareRenderer.isEnabled() &&
   2176                 attachInfo.mHardwareRenderer.isRequested()) {
   2177             mFullRedrawNeeded = true;
   2178             scheduleTraversals();
   2179             return false;
   2180         }
   2181 
   2182         // Draw with software renderer.
   2183         Canvas canvas;
   2184         try {
   2185             int left = dirty.left;
   2186             int top = dirty.top;
   2187             int right = dirty.right;
   2188             int bottom = dirty.bottom;
   2189 
   2190             canvas = mSurface.lockCanvas(dirty);
   2191 
   2192             if (left != dirty.left || top != dirty.top || right != dirty.right ||
   2193                     bottom != dirty.bottom) {
   2194                 attachInfo.mIgnoreDirtyState = true;
   2195             }
   2196 
   2197             // TODO: Do this in native
   2198             canvas.setDensity(mDensity);
   2199         } catch (Surface.OutOfResourcesException e) {
   2200             Log.e(TAG, "OutOfResourcesException locking surface", e);
   2201             try {
   2202                 if (!sWindowSession.outOfMemory(mWindow)) {
   2203                     Slog.w(TAG, "No processes killed for memory; killing self");
   2204                     Process.killProcess(Process.myPid());
   2205                 }
   2206             } catch (RemoteException ex) {
   2207             }
   2208             mLayoutRequested = true;    // ask wm for a new surface next time.
   2209             return false;
   2210         } catch (IllegalArgumentException e) {
   2211             Log.e(TAG, "Could not lock surface", e);
   2212             // Don't assume this is due to out of memory, it could be
   2213             // something else, and if it is something else then we could
   2214             // kill stuff (or ourself) for no reason.
   2215             mLayoutRequested = true;    // ask wm for a new surface next time.
   2216             return false;
   2217         }
   2218 
   2219         try {
   2220             if (DEBUG_ORIENTATION || DEBUG_DRAW) {
   2221                 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
   2222                         + canvas.getWidth() + ", h=" + canvas.getHeight());
   2223                 //canvas.drawARGB(255, 255, 0, 0);
   2224             }
   2225 
   2226             // If this bitmap's format includes an alpha channel, we
   2227             // need to clear it before drawing so that the child will
   2228             // properly re-composite its drawing on a transparent
   2229             // background. This automatically respects the clip/dirty region
   2230             // or
   2231             // If we are applying an offset, we need to clear the area
   2232             // where the offset doesn't appear to avoid having garbage
   2233             // left in the blank areas.
   2234             if (!canvas.isOpaque() || yoff != 0) {
   2235                 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
   2236             }
   2237 
   2238             dirty.setEmpty();
   2239             mIsAnimating = false;
   2240             attachInfo.mDrawingTime = SystemClock.uptimeMillis();
   2241             mView.mPrivateFlags |= View.DRAWN;
   2242 
   2243             if (DEBUG_DRAW) {
   2244                 Context cxt = mView.getContext();
   2245                 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
   2246                         ", metrics=" + cxt.getResources().getDisplayMetrics() +
   2247                         ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
   2248             }
   2249             try {
   2250                 canvas.translate(0, -yoff);
   2251                 if (mTranslator != null) {
   2252                     mTranslator.translateCanvas(canvas);
   2253                 }
   2254                 canvas.setScreenDensity(scalingRequired
   2255                         ? DisplayMetrics.DENSITY_DEVICE : 0);
   2256                 attachInfo.mSetIgnoreDirtyState = false;
   2257 
   2258                 mView.draw(canvas);
   2259 
   2260                 drawAccessibilityFocusedDrawableIfNeeded(canvas);
   2261             } finally {
   2262                 if (!attachInfo.mSetIgnoreDirtyState) {
   2263                     // Only clear the flag if it was not set during the mView.draw() call
   2264                     attachInfo.mIgnoreDirtyState = false;
   2265                 }
   2266             }
   2267         } finally {
   2268             try {
   2269                 surface.unlockCanvasAndPost(canvas);
   2270             } catch (IllegalArgumentException e) {
   2271                 Log.e(TAG, "Could not unlock surface", e);
   2272                 mLayoutRequested = true;    // ask wm for a new surface next time.
   2273                 //noinspection ReturnInsideFinallyBlock
   2274                 return false;
   2275             }
   2276 
   2277             if (LOCAL_LOGV) {
   2278                 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
   2279             }
   2280         }
   2281         return true;
   2282     }
   2283 
   2284     @Override
   2285     public View findViewToTakeAccessibilityFocusFromHover(View child, View descendant) {
   2286         if (descendant.includeForAccessibility()) {
   2287             return descendant;
   2288         }
   2289         return null;
   2290     }
   2291 
   2292     /**
   2293      * We want to draw a highlight around the current accessibility focused.
   2294      * Since adding a style for all possible view is not a viable option we
   2295      * have this specialized drawing method.
   2296      *
   2297      * Note: We are doing this here to be able to draw the highlight for
   2298      *       virtual views in addition to real ones.
   2299      *
   2300      * @param canvas The canvas on which to draw.
   2301      */
   2302     private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
   2303         AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
   2304         if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
   2305             return;
   2306         }
   2307         if (mAccessibilityFocusedHost == null || mAccessibilityFocusedHost.mAttachInfo == null) {
   2308             return;
   2309         }
   2310         Drawable drawable = getAccessibilityFocusedDrawable();
   2311         if (drawable == null) {
   2312             return;
   2313         }
   2314         AccessibilityNodeProvider provider =
   2315             mAccessibilityFocusedHost.getAccessibilityNodeProvider();
   2316         Rect bounds = mView.mAttachInfo.mTmpInvalRect;
   2317         if (provider == null) {
   2318             mAccessibilityFocusedHost.getDrawingRect(bounds);
   2319             if (mView instanceof ViewGroup) {
   2320                 ViewGroup viewGroup = (ViewGroup) mView;
   2321                 viewGroup.offsetDescendantRectToMyCoords(mAccessibilityFocusedHost, bounds);
   2322             }
   2323         } else {
   2324             if (mAccessibilityFocusedVirtualView == null) {
   2325                 return;
   2326             }
   2327             mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
   2328             bounds.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
   2329         }
   2330         drawable.setBounds(bounds);
   2331         drawable.draw(canvas);
   2332     }
   2333 
   2334     private Drawable getAccessibilityFocusedDrawable() {
   2335         if (mAttachInfo != null) {
   2336             // Lazily load the accessibility focus drawable.
   2337             if (mAttachInfo.mAccessibilityFocusDrawable == null) {
   2338                 TypedValue value = new TypedValue();
   2339                 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
   2340                         R.attr.accessibilityFocusedDrawable, value, true);
   2341                 if (resolved) {
   2342                     mAttachInfo.mAccessibilityFocusDrawable =
   2343                         mView.mContext.getResources().getDrawable(value.resourceId);
   2344                 }
   2345             }
   2346             return mAttachInfo.mAccessibilityFocusDrawable;
   2347         }
   2348         return null;
   2349     }
   2350 
   2351     void invalidateDisplayLists() {
   2352         final ArrayList<DisplayList> displayLists = mDisplayLists;
   2353         final int count = displayLists.size();
   2354 
   2355         for (int i = 0; i < count; i++) {
   2356             final DisplayList displayList = displayLists.get(i);
   2357             displayList.invalidate();
   2358             displayList.clear();
   2359         }
   2360 
   2361         displayLists.clear();
   2362     }
   2363 
   2364     boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
   2365         final View.AttachInfo attachInfo = mAttachInfo;
   2366         final Rect ci = attachInfo.mContentInsets;
   2367         final Rect vi = attachInfo.mVisibleInsets;
   2368         int scrollY = 0;
   2369         boolean handled = false;
   2370 
   2371         if (vi.left > ci.left || vi.top > ci.top
   2372                 || vi.right > ci.right || vi.bottom > ci.bottom) {
   2373             // We'll assume that we aren't going to change the scroll
   2374             // offset, since we want to avoid that unless it is actually
   2375             // going to make the focus visible...  otherwise we scroll
   2376             // all over the place.
   2377             scrollY = mScrollY;
   2378             // We can be called for two different situations: during a draw,
   2379             // to update the scroll position if the focus has changed (in which
   2380             // case 'rectangle' is null), or in response to a
   2381             // requestChildRectangleOnScreen() call (in which case 'rectangle'
   2382             // is non-null and we just want to scroll to whatever that
   2383             // rectangle is).
   2384             View focus = mRealFocusedView;
   2385 
   2386             // When in touch mode, focus points to the previously focused view,
   2387             // which may have been removed from the view hierarchy. The following
   2388             // line checks whether the view is still in our hierarchy.
   2389             if (focus == null || focus.mAttachInfo != mAttachInfo) {
   2390                 mRealFocusedView = null;
   2391                 return false;
   2392             }
   2393 
   2394             if (focus != mLastScrolledFocus) {
   2395                 // If the focus has changed, then ignore any requests to scroll
   2396                 // to a rectangle; first we want to make sure the entire focus
   2397                 // view is visible.
   2398                 rectangle = null;
   2399             }
   2400             if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
   2401                     + " rectangle=" + rectangle + " ci=" + ci
   2402                     + " vi=" + vi);
   2403             if (focus == mLastScrolledFocus && !mScrollMayChange
   2404                     && rectangle == null) {
   2405                 // Optimization: if the focus hasn't changed since last
   2406                 // time, and no layout has happened, then just leave things
   2407                 // as they are.
   2408                 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
   2409                         + mScrollY + " vi=" + vi.toShortString());
   2410             } else if (focus != null) {
   2411                 // We need to determine if the currently focused view is
   2412                 // within the visible part of the window and, if not, apply
   2413                 // a pan so it can be seen.
   2414                 mLastScrolledFocus = focus;
   2415                 mScrollMayChange = false;
   2416                 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
   2417                 // Try to find the rectangle from the focus view.
   2418                 if (focus.getGlobalVisibleRect(mVisRect, null)) {
   2419                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
   2420                             + mView.getWidth() + " h=" + mView.getHeight()
   2421                             + " ci=" + ci.toShortString()
   2422                             + " vi=" + vi.toShortString());
   2423                     if (rectangle == null) {
   2424                         focus.getFocusedRect(mTempRect);
   2425                         if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
   2426                                 + ": focusRect=" + mTempRect.toShortString());
   2427                         if (mView instanceof ViewGroup) {
   2428                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
   2429                                     focus, mTempRect);
   2430                         }
   2431                         if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2432                                 "Focus in window: focusRect="
   2433                                 + mTempRect.toShortString()
   2434                                 + " visRect=" + mVisRect.toShortString());
   2435                     } else {
   2436                         mTempRect.set(rectangle);
   2437                         if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2438                                 "Request scroll to rect: "
   2439                                 + mTempRect.toShortString()
   2440                                 + " visRect=" + mVisRect.toShortString());
   2441                     }
   2442                     if (mTempRect.intersect(mVisRect)) {
   2443                         if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2444                                 "Focus window visible rect: "
   2445                                 + mTempRect.toShortString());
   2446                         if (mTempRect.height() >
   2447                                 (mView.getHeight()-vi.top-vi.bottom)) {
   2448                             // If the focus simply is not going to fit, then
   2449                             // best is probably just to leave things as-is.
   2450                             if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2451                                     "Too tall; leaving scrollY=" + scrollY);
   2452                         } else if ((mTempRect.top-scrollY) < vi.top) {
   2453                             scrollY -= vi.top - (mTempRect.top-scrollY);
   2454                             if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2455                                     "Top covered; scrollY=" + scrollY);
   2456                         } else if ((mTempRect.bottom-scrollY)
   2457                                 > (mView.getHeight()-vi.bottom)) {
   2458                             scrollY += (mTempRect.bottom-scrollY)
   2459                                     - (mView.getHeight()-vi.bottom);
   2460                             if (DEBUG_INPUT_RESIZE) Log.v(TAG,
   2461                                     "Bottom covered; scrollY=" + scrollY);
   2462                         }
   2463                         handled = true;
   2464                     }
   2465                 }
   2466             }
   2467         }
   2468 
   2469         if (scrollY != mScrollY) {
   2470             if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
   2471                     + mScrollY + " , new=" + scrollY);
   2472             if (!immediate && mResizeBuffer == null) {
   2473                 if (mScroller == null) {
   2474                     mScroller = new Scroller(mView.getContext());
   2475                 }
   2476                 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
   2477             } else if (mScroller != null) {
   2478                 mScroller.abortAnimation();
   2479             }
   2480             mScrollY = scrollY;
   2481         }
   2482 
   2483         return handled;
   2484     }
   2485 
   2486     /**
   2487      * @hide
   2488      */
   2489     public View getAccessibilityFocusedHost() {
   2490         return mAccessibilityFocusedHost;
   2491     }
   2492 
   2493     /**
   2494      * @hide
   2495      */
   2496     public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
   2497         return mAccessibilityFocusedVirtualView;
   2498     }
   2499 
   2500     void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
   2501         // If we have a virtual view with accessibility focus we need
   2502         // to clear the focus and invalidate the virtual view bounds.
   2503         if (mAccessibilityFocusedVirtualView != null) {
   2504 
   2505             AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
   2506             View focusHost = mAccessibilityFocusedHost;
   2507             focusHost.clearAccessibilityFocusNoCallbacks();
   2508 
   2509             // Wipe the state of the current accessibility focus since
   2510             // the call into the provider to clear accessibility focus
   2511             // will fire an accessibility event which will end up calling
   2512             // this method and we want to have clean state when this
   2513             // invocation happens.
   2514             mAccessibilityFocusedHost = null;
   2515             mAccessibilityFocusedVirtualView = null;
   2516 
   2517             AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
   2518             if (provider != null) {
   2519                 // Invalidate the area of the cleared accessibility focus.
   2520                 focusNode.getBoundsInParent(mTempRect);
   2521                 focusHost.invalidate(mTempRect);
   2522                 // Clear accessibility focus in the virtual node.
   2523                 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
   2524                         focusNode.getSourceNodeId());
   2525                 provider.performAction(virtualNodeId,
   2526                         AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
   2527             }
   2528             focusNode.recycle();
   2529         }
   2530         if (mAccessibilityFocusedHost != null) {
   2531             // Clear accessibility focus in the view.
   2532             mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
   2533         }
   2534 
   2535         // Set the new focus host and node.
   2536         mAccessibilityFocusedHost = view;
   2537         mAccessibilityFocusedVirtualView = node;
   2538     }
   2539 
   2540     public void requestChildFocus(View child, View focused) {
   2541         checkThread();
   2542 
   2543         if (DEBUG_INPUT_RESIZE) {
   2544             Log.v(TAG, "Request child focus: focus now " + focused);
   2545         }
   2546 
   2547         mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, focused);
   2548         scheduleTraversals();
   2549 
   2550         mFocusedView = mRealFocusedView = focused;
   2551     }
   2552 
   2553     public void clearChildFocus(View child) {
   2554         checkThread();
   2555 
   2556         if (DEBUG_INPUT_RESIZE) {
   2557             Log.v(TAG, "Clearing child focus");
   2558         }
   2559 
   2560         mOldFocusedView = mFocusedView;
   2561 
   2562         // Invoke the listener only if there is no view to take focus
   2563         if (focusSearch(null, View.FOCUS_FORWARD) == null) {
   2564             mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, null);
   2565         }
   2566 
   2567         mFocusedView = mRealFocusedView = null;
   2568     }
   2569 
   2570     @Override
   2571     public ViewParent getParentForAccessibility() {
   2572         return null;
   2573     }
   2574 
   2575     public void focusableViewAvailable(View v) {
   2576         checkThread();
   2577         if (mView != null) {
   2578             if (!mView.hasFocus()) {
   2579                 v.requestFocus();
   2580             } else {
   2581                 // the one case where will transfer focus away from the current one
   2582                 // is if the current view is a view group that prefers to give focus
   2583                 // to its children first AND the view is a descendant of it.
   2584                 mFocusedView = mView.findFocus();
   2585                 boolean descendantsHaveDibsOnFocus =
   2586                         (mFocusedView instanceof ViewGroup) &&
   2587                             (((ViewGroup) mFocusedView).getDescendantFocusability() ==
   2588                                     ViewGroup.FOCUS_AFTER_DESCENDANTS);
   2589                 if (descendantsHaveDibsOnFocus && isViewDescendantOf(v, mFocusedView)) {
   2590                     // If a view gets the focus, the listener will be invoked from requestChildFocus()
   2591                     v.requestFocus();
   2592                 }
   2593             }
   2594         }
   2595     }
   2596 
   2597     public void recomputeViewAttributes(View child) {
   2598         checkThread();
   2599         if (mView == child) {
   2600             mAttachInfo.mRecomputeGlobalAttributes = true;
   2601             if (!mWillDrawSoon) {
   2602                 scheduleTraversals();
   2603             }
   2604         }
   2605     }
   2606 
   2607     void dispatchDetachedFromWindow() {
   2608         if (mView != null && mView.mAttachInfo != null) {
   2609             if (mAttachInfo.mHardwareRenderer != null &&
   2610                     mAttachInfo.mHardwareRenderer.isEnabled()) {
   2611                 mAttachInfo.mHardwareRenderer.validate();
   2612             }
   2613             mView.dispatchDetachedFromWindow();
   2614         }
   2615 
   2616         mAccessibilityInteractionConnectionManager.ensureNoConnection();
   2617         mAccessibilityManager.removeAccessibilityStateChangeListener(
   2618                 mAccessibilityInteractionConnectionManager);
   2619         removeSendWindowContentChangedCallback();
   2620 
   2621         destroyHardwareRenderer();
   2622 
   2623         setAccessibilityFocus(null, null);
   2624 
   2625         mView = null;
   2626         mAttachInfo.mRootView = null;
   2627         mAttachInfo.mSurface = null;
   2628 
   2629         mSurface.release();
   2630 
   2631         if (mInputQueueCallback != null && mInputQueue != null) {
   2632             mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
   2633             mInputQueueCallback = null;
   2634             mInputQueue = null;
   2635         } else if (mInputEventReceiver != null) {
   2636             mInputEventReceiver.dispose();
   2637             mInputEventReceiver = null;
   2638         }
   2639         try {
   2640             sWindowSession.remove(mWindow);
   2641         } catch (RemoteException e) {
   2642         }
   2643 
   2644         // Dispose the input channel after removing the window so the Window Manager
   2645         // doesn't interpret the input channel being closed as an abnormal termination.
   2646         if (mInputChannel != null) {
   2647             mInputChannel.dispose();
   2648             mInputChannel = null;
   2649         }
   2650 
   2651         unscheduleTraversals();
   2652     }
   2653 
   2654     void updateConfiguration(Configuration config, boolean force) {
   2655         if (DEBUG_CONFIGURATION) Log.v(TAG,
   2656                 "Applying new config to window "
   2657                 + mWindowAttributes.getTitle()
   2658                 + ": " + config);
   2659 
   2660         CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
   2661         if (ci != null) {
   2662             config = new Configuration(config);
   2663             ci.applyToConfiguration(config);
   2664         }
   2665 
   2666         synchronized (sConfigCallbacks) {
   2667             for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
   2668                 sConfigCallbacks.get(i).onConfigurationChanged(config);
   2669             }
   2670         }
   2671         if (mView != null) {
   2672             // At this point the resources have been updated to
   2673             // have the most recent config, whatever that is.  Use
   2674             // the on in them which may be newer.
   2675             config = mView.getResources().getConfiguration();
   2676             if (force || mLastConfiguration.diff(config) != 0) {
   2677                 mLastConfiguration.setTo(config);
   2678                 mView.dispatchConfigurationChanged(config);
   2679             }
   2680         }
   2681     }
   2682 
   2683     /**
   2684      * Return true if child is an ancestor of parent, (or equal to the parent).
   2685      */
   2686     public static boolean isViewDescendantOf(View child, View parent) {
   2687         if (child == parent) {
   2688             return true;
   2689         }
   2690 
   2691         final ViewParent theParent = child.getParent();
   2692         return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
   2693     }
   2694 
   2695     private static void forceLayout(View view) {
   2696         view.forceLayout();
   2697         if (view instanceof ViewGroup) {
   2698             ViewGroup group = (ViewGroup) view;
   2699             final int count = group.getChildCount();
   2700             for (int i = 0; i < count; i++) {
   2701                 forceLayout(group.getChildAt(i));
   2702             }
   2703         }
   2704     }
   2705 
   2706     private final static int MSG_INVALIDATE = 1;
   2707     private final static int MSG_INVALIDATE_RECT = 2;
   2708     private final static int MSG_DIE = 3;
   2709     private final static int MSG_RESIZED = 4;
   2710     private final static int MSG_RESIZED_REPORT = 5;
   2711     private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
   2712     private final static int MSG_DISPATCH_KEY = 7;
   2713     private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
   2714     private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
   2715     private final static int MSG_IME_FINISHED_EVENT = 10;
   2716     private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
   2717     private final static int MSG_FINISH_INPUT_CONNECTION = 12;
   2718     private final static int MSG_CHECK_FOCUS = 13;
   2719     private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
   2720     private final static int MSG_DISPATCH_DRAG_EVENT = 15;
   2721     private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
   2722     private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
   2723     private final static int MSG_UPDATE_CONFIGURATION = 18;
   2724     private final static int MSG_PROCESS_INPUT_EVENTS = 19;
   2725     private final static int MSG_DISPATCH_SCREEN_STATE = 20;
   2726     private final static int MSG_INVALIDATE_DISPLAY_LIST = 21;
   2727     private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22;
   2728     private final static int MSG_DISPATCH_DONE_ANIMATING = 23;
   2729     private final static int MSG_INVALIDATE_WORLD = 24;
   2730 
   2731     final class ViewRootHandler extends Handler {
   2732         @Override
   2733         public String getMessageName(Message message) {
   2734             switch (message.what) {
   2735                 case MSG_INVALIDATE:
   2736                     return "MSG_INVALIDATE";
   2737                 case MSG_INVALIDATE_RECT:
   2738                     return "MSG_INVALIDATE_RECT";
   2739                 case MSG_DIE:
   2740                     return "MSG_DIE";
   2741                 case MSG_RESIZED:
   2742                     return "MSG_RESIZED";
   2743                 case MSG_RESIZED_REPORT:
   2744                     return "MSG_RESIZED_REPORT";
   2745                 case MSG_WINDOW_FOCUS_CHANGED:
   2746                     return "MSG_WINDOW_FOCUS_CHANGED";
   2747                 case MSG_DISPATCH_KEY:
   2748                     return "MSG_DISPATCH_KEY";
   2749                 case MSG_DISPATCH_APP_VISIBILITY:
   2750                     return "MSG_DISPATCH_APP_VISIBILITY";
   2751                 case MSG_DISPATCH_GET_NEW_SURFACE:
   2752                     return "MSG_DISPATCH_GET_NEW_SURFACE";
   2753                 case MSG_IME_FINISHED_EVENT:
   2754                     return "MSG_IME_FINISHED_EVENT";
   2755                 case MSG_DISPATCH_KEY_FROM_IME:
   2756                     return "MSG_DISPATCH_KEY_FROM_IME";
   2757                 case MSG_FINISH_INPUT_CONNECTION:
   2758                     return "MSG_FINISH_INPUT_CONNECTION";
   2759                 case MSG_CHECK_FOCUS:
   2760                     return "MSG_CHECK_FOCUS";
   2761                 case MSG_CLOSE_SYSTEM_DIALOGS:
   2762                     return "MSG_CLOSE_SYSTEM_DIALOGS";
   2763                 case MSG_DISPATCH_DRAG_EVENT:
   2764                     return "MSG_DISPATCH_DRAG_EVENT";
   2765                 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
   2766                     return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
   2767                 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
   2768                     return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
   2769                 case MSG_UPDATE_CONFIGURATION:
   2770                     return "MSG_UPDATE_CONFIGURATION";
   2771                 case MSG_PROCESS_INPUT_EVENTS:
   2772                     return "MSG_PROCESS_INPUT_EVENTS";
   2773                 case MSG_DISPATCH_SCREEN_STATE:
   2774                     return "MSG_DISPATCH_SCREEN_STATE";
   2775                 case MSG_INVALIDATE_DISPLAY_LIST:
   2776                     return "MSG_INVALIDATE_DISPLAY_LIST";
   2777                 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
   2778                     return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
   2779                 case MSG_DISPATCH_DONE_ANIMATING:
   2780                     return "MSG_DISPATCH_DONE_ANIMATING";
   2781             }
   2782             return super.getMessageName(message);
   2783         }
   2784 
   2785         @Override
   2786         public void handleMessage(Message msg) {
   2787             switch (msg.what) {
   2788             case MSG_INVALIDATE:
   2789                 ((View) msg.obj).invalidate();
   2790                 break;
   2791             case MSG_INVALIDATE_RECT:
   2792                 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
   2793                 info.target.invalidate(info.left, info.top, info.right, info.bottom);
   2794                 info.release();
   2795                 break;
   2796             case MSG_IME_FINISHED_EVENT:
   2797                 handleImeFinishedEvent(msg.arg1, msg.arg2 != 0);
   2798                 break;
   2799             case MSG_PROCESS_INPUT_EVENTS:
   2800                 mProcessInputEventsScheduled = false;
   2801                 doProcessInputEvents();
   2802                 break;
   2803             case MSG_DISPATCH_APP_VISIBILITY:
   2804                 handleAppVisibility(msg.arg1 != 0);
   2805                 break;
   2806             case MSG_DISPATCH_GET_NEW_SURFACE:
   2807                 handleGetNewSurface();
   2808                 break;
   2809             case MSG_RESIZED:
   2810                 ResizedInfo ri = (ResizedInfo)msg.obj;
   2811 
   2812                 if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
   2813                         && mPendingContentInsets.equals(ri.contentInsets)
   2814                         && mPendingVisibleInsets.equals(ri.visibleInsets)
   2815                         && ((ResizedInfo)msg.obj).newConfig == null) {
   2816                     break;
   2817                 }
   2818                 // fall through...
   2819             case MSG_RESIZED_REPORT:
   2820                 if (mAdded) {
   2821                     Configuration config = ((ResizedInfo)msg.obj).newConfig;
   2822                     if (config != null) {
   2823                         updateConfiguration(config, false);
   2824                     }
   2825                     mWinFrame.left = 0;
   2826                     mWinFrame.right = msg.arg1;
   2827                     mWinFrame.top = 0;
   2828                     mWinFrame.bottom = msg.arg2;
   2829                     mPendingContentInsets.set(((ResizedInfo)msg.obj).contentInsets);
   2830                     mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
   2831                     if (msg.what == MSG_RESIZED_REPORT) {
   2832                         mReportNextDraw = true;
   2833                     }
   2834 
   2835                     if (mView != null) {
   2836                         forceLayout(mView);
   2837                     }
   2838                     requestLayout();
   2839                 }
   2840                 break;
   2841             case MSG_WINDOW_FOCUS_CHANGED: {
   2842                 if (mAdded) {
   2843                     boolean hasWindowFocus = msg.arg1 != 0;
   2844                     mAttachInfo.mHasWindowFocus = hasWindowFocus;
   2845 
   2846                     profileRendering(hasWindowFocus);
   2847 
   2848                     if (hasWindowFocus) {
   2849                         boolean inTouchMode = msg.arg2 != 0;
   2850                         ensureTouchModeLocally(inTouchMode);
   2851 
   2852                         if (mAttachInfo.mHardwareRenderer != null &&
   2853                                 mSurface != null && mSurface.isValid()) {
   2854                             mFullRedrawNeeded = true;
   2855                             try {
   2856                                 mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
   2857                                         mHolder);
   2858                             } catch (Surface.OutOfResourcesException e) {
   2859                                 Log.e(TAG, "OutOfResourcesException locking surface", e);
   2860                                 try {
   2861                                     if (!sWindowSession.outOfMemory(mWindow)) {
   2862                                         Slog.w(TAG, "No processes killed for memory; killing self");
   2863                                         Process.killProcess(Process.myPid());
   2864                                     }
   2865                                 } catch (RemoteException ex) {
   2866                                 }
   2867                                 // Retry in a bit.
   2868                                 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
   2869                                 return;
   2870                             }
   2871                         }
   2872                     }
   2873 
   2874                     mLastWasImTarget = WindowManager.LayoutParams
   2875                             .mayUseInputMethod(mWindowAttributes.flags);
   2876 
   2877                     InputMethodManager imm = InputMethodManager.peekInstance();
   2878                     if (mView != null) {
   2879                         if (hasWindowFocus && imm != null && mLastWasImTarget) {
   2880                             imm.startGettingWindowFocus(mView);
   2881                         }
   2882                         mAttachInfo.mKeyDispatchState.reset();
   2883                         mView.dispatchWindowFocusChanged(hasWindowFocus);
   2884                     }
   2885 
   2886                     // Note: must be done after the focus change callbacks,
   2887                     // so all of the view state is set up correctly.
   2888                     if (hasWindowFocus) {
   2889                         if (imm != null && mLastWasImTarget) {
   2890                             imm.onWindowFocus(mView, mView.findFocus(),
   2891                                     mWindowAttributes.softInputMode,
   2892                                     !mHasHadWindowFocus, mWindowAttributes.flags);
   2893                         }
   2894                         // Clear the forward bit.  We can just do this directly, since
   2895                         // the window manager doesn't care about it.
   2896                         mWindowAttributes.softInputMode &=
   2897                                 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
   2898                         ((WindowManager.LayoutParams)mView.getLayoutParams())
   2899                                 .softInputMode &=
   2900                                     ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
   2901                         mHasHadWindowFocus = true;
   2902                     }
   2903 
   2904                     setAccessibilityFocus(null, null);
   2905 
   2906                     if (mView != null && mAccessibilityManager.isEnabled()) {
   2907                         if (hasWindowFocus) {
   2908                             mView.sendAccessibilityEvent(
   2909                                     AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
   2910                         }
   2911                     }
   2912                 }
   2913             } break;
   2914             case MSG_DIE:
   2915                 doDie();
   2916                 break;
   2917             case MSG_DISPATCH_KEY: {
   2918                 KeyEvent event = (KeyEvent)msg.obj;
   2919                 enqueueInputEvent(event, null, 0, true);
   2920             } break;
   2921             case MSG_DISPATCH_KEY_FROM_IME: {
   2922                 if (LOCAL_LOGV) Log.v(
   2923                     TAG, "Dispatching key "
   2924                     + msg.obj + " from IME to " + mView);
   2925                 KeyEvent event = (KeyEvent)msg.obj;
   2926                 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
   2927                     // The IME is trying to say this event is from the
   2928                     // system!  Bad bad bad!
   2929                     //noinspection UnusedAssignment
   2930                     event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
   2931                 }
   2932                 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
   2933             } break;
   2934             case MSG_FINISH_INPUT_CONNECTION: {
   2935                 InputMethodManager imm = InputMethodManager.peekInstance();
   2936                 if (imm != null) {
   2937                     imm.reportFinishInputConnection((InputConnection)msg.obj);
   2938                 }
   2939             } break;
   2940             case MSG_CHECK_FOCUS: {
   2941                 InputMethodManager imm = InputMethodManager.peekInstance();
   2942                 if (imm != null) {
   2943                     imm.checkFocus();
   2944                 }
   2945             } break;
   2946             case MSG_CLOSE_SYSTEM_DIALOGS: {
   2947                 if (mView != null) {
   2948                     mView.onCloseSystemDialogs((String)msg.obj);
   2949                 }
   2950             } break;
   2951             case MSG_DISPATCH_DRAG_EVENT:
   2952             case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
   2953                 DragEvent event = (DragEvent)msg.obj;
   2954                 event.mLocalState = mLocalDragState;    // only present when this app called startDrag()
   2955                 handleDragEvent(event);
   2956             } break;
   2957             case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
   2958                 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj);
   2959             } break;
   2960             case MSG_UPDATE_CONFIGURATION: {
   2961                 Configuration config = (Configuration)msg.obj;
   2962                 if (config.isOtherSeqNewer(mLastConfiguration)) {
   2963                     config = mLastConfiguration;
   2964                 }
   2965                 updateConfiguration(config, false);
   2966             } break;
   2967             case MSG_DISPATCH_SCREEN_STATE: {
   2968                 if (mView != null) {
   2969                     handleScreenStateChange(msg.arg1 == 1);
   2970                 }
   2971             } break;
   2972             case MSG_INVALIDATE_DISPLAY_LIST: {
   2973                 invalidateDisplayLists();
   2974             } break;
   2975             case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
   2976                 setAccessibilityFocus(null, null);
   2977             } break;
   2978             case MSG_DISPATCH_DONE_ANIMATING: {
   2979                 handleDispatchDoneAnimating();
   2980             } break;
   2981             case MSG_INVALIDATE_WORLD: {
   2982                 invalidateWorld(mView);
   2983             } break;
   2984             }
   2985         }
   2986     }
   2987 
   2988     final ViewRootHandler mHandler = new ViewRootHandler();
   2989 
   2990     /**
   2991      * Something in the current window tells us we need to change the touch mode.  For
   2992      * example, we are not in touch mode, and the user touches the screen.
   2993      *
   2994      * If the touch mode has changed, tell the window manager, and handle it locally.
   2995      *
   2996      * @param inTouchMode Whether we want to be in touch mode.
   2997      * @return True if the touch mode changed and focus changed was changed as a result
   2998      */
   2999     boolean ensureTouchMode(boolean inTouchMode) {
   3000         if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
   3001                 + "touch mode is " + mAttachInfo.mInTouchMode);
   3002         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
   3003 
   3004         // tell the window manager
   3005         try {
   3006             sWindowSession.setInTouchMode(inTouchMode);
   3007         } catch (RemoteException e) {
   3008             throw new RuntimeException(e);
   3009         }
   3010 
   3011         // handle the change
   3012         return ensureTouchModeLocally(inTouchMode);
   3013     }
   3014 
   3015     /**
   3016      * Ensure that the touch mode for this window is set, and if it is changing,
   3017      * take the appropriate action.
   3018      * @param inTouchMode Whether we want to be in touch mode.
   3019      * @return True if the touch mode changed and focus changed was changed as a result
   3020      */
   3021     private boolean ensureTouchModeLocally(boolean inTouchMode) {
   3022         if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
   3023                 + "touch mode is " + mAttachInfo.mInTouchMode);
   3024 
   3025         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
   3026 
   3027         mAttachInfo.mInTouchMode = inTouchMode;
   3028         mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
   3029 
   3030         return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
   3031     }
   3032 
   3033     private boolean enterTouchMode() {
   3034         if (mView != null) {
   3035             if (mView.hasFocus()) {
   3036                 // note: not relying on mFocusedView here because this could
   3037                 // be when the window is first being added, and mFocused isn't
   3038                 // set yet.
   3039                 final View focused = mView.findFocus();
   3040                 if (focused != null && !focused.isFocusableInTouchMode()) {
   3041 
   3042                     final ViewGroup ancestorToTakeFocus =
   3043                             findAncestorToTakeFocusInTouchMode(focused);
   3044                     if (ancestorToTakeFocus != null) {
   3045                         // there is an ancestor that wants focus after its descendants that
   3046                         // is focusable in touch mode.. give it focus
   3047                         return ancestorToTakeFocus.requestFocus();
   3048                     } else {
   3049                         // nothing appropriate to have focus in touch mode, clear it out
   3050                         mView.unFocus();
   3051                         mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
   3052                         mFocusedView = null;
   3053                         mOldFocusedView = null;
   3054                         return true;
   3055                     }
   3056                 }
   3057             }
   3058         }
   3059         return false;
   3060     }
   3061 
   3062     /**
   3063      * Find an ancestor of focused that wants focus after its descendants and is
   3064      * focusable in touch mode.
   3065      * @param focused The currently focused view.
   3066      * @return An appropriate view, or null if no such view exists.
   3067      */
   3068     private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
   3069         ViewParent parent = focused.getParent();
   3070         while (parent instanceof ViewGroup) {
   3071             final ViewGroup vgParent = (ViewGroup) parent;
   3072             if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
   3073                     && vgParent.isFocusableInTouchMode()) {
   3074                 return vgParent;
   3075             }
   3076             if (vgParent.isRootNamespace()) {
   3077                 return null;
   3078             } else {
   3079                 parent = vgParent.getParent();
   3080             }
   3081         }
   3082         return null;
   3083     }
   3084 
   3085     private boolean leaveTouchMode() {
   3086         if (mView != null) {
   3087             if (mView.hasFocus()) {
   3088                 // i learned the hard way to not trust mFocusedView :)
   3089                 mFocusedView = mView.findFocus();
   3090                 if (!(mFocusedView instanceof ViewGroup)) {
   3091                     // some view has focus, let it keep it
   3092                     return false;
   3093                 } else if (((ViewGroup)mFocusedView).getDescendantFocusability() !=
   3094                         ViewGroup.FOCUS_AFTER_DESCENDANTS) {
   3095                     // some view group has focus, and doesn't prefer its children
   3096                     // over itself for focus, so let them keep it.
   3097                     return false;
   3098                 }
   3099             }
   3100 
   3101             // find the best view to give focus to in this brave new non-touch-mode
   3102             // world
   3103             final View focused = focusSearch(null, View.FOCUS_DOWN);
   3104             if (focused != null) {
   3105                 return focused.requestFocus(View.FOCUS_DOWN);
   3106             }
   3107         }
   3108         return false;
   3109     }
   3110 
   3111     private void deliverInputEvent(QueuedInputEvent q) {
   3112         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
   3113         try {
   3114             if (q.mEvent instanceof KeyEvent) {
   3115                 deliverKeyEvent(q);
   3116             } else {
   3117                 final int source = q.mEvent.getSource();
   3118                 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
   3119                     deliverPointerEvent(q);
   3120                 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
   3121                     deliverTrackballEvent(q);
   3122                 } else {
   3123                     deliverGenericMotionEvent(q);
   3124                 }
   3125             }
   3126         } finally {
   3127             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   3128         }
   3129     }
   3130 
   3131     private void deliverPointerEvent(QueuedInputEvent q) {
   3132         final MotionEvent event = (MotionEvent)q.mEvent;
   3133         final boolean isTouchEvent = event.isTouchEvent();
   3134         if (mInputEventConsistencyVerifier != null) {
   3135             if (isTouchEvent) {
   3136                 mInputEventConsistencyVerifier.onTouchEvent(event, 0);
   3137             } else {
   3138                 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
   3139             }
   3140         }
   3141 
   3142         // If there is no view, then the event will not be handled.
   3143         if (mView == null || !mAdded) {
   3144             finishInputEvent(q, false);
   3145             return;
   3146         }
   3147 
   3148         // Translate the pointer event for compatibility, if needed.
   3149         if (mTranslator != null) {
   3150             mTranslator.translateEventInScreenToAppWindow(event);
   3151         }
   3152 
   3153         // Enter touch mode on down or scroll.
   3154         final int action = event.getAction();
   3155         if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
   3156             ensureTouchMode(true);
   3157         }
   3158 
   3159         // Offset the scroll position.
   3160         if (mCurScrollY != 0) {
   3161             event.offsetLocation(0, mCurScrollY);
   3162         }
   3163         if (MEASURE_LATENCY) {
   3164             lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano());
   3165         }
   3166 
   3167         // Remember the touch position for possible drag-initiation.
   3168         if (isTouchEvent) {
   3169             mLastTouchPoint.x = event.getRawX();
   3170             mLastTouchPoint.y = event.getRawY();
   3171         }
   3172 
   3173         // Dispatch touch to view hierarchy.
   3174         boolean handled = mView.dispatchPointerEvent(event);
   3175         if (MEASURE_LATENCY) {
   3176             lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano());
   3177         }
   3178         if (handled) {
   3179             finishInputEvent(q, true);
   3180             return;
   3181         }
   3182 
   3183         // Pointer event was unhandled.
   3184         finishInputEvent(q, false);
   3185     }
   3186 
   3187     private void deliverTrackballEvent(QueuedInputEvent q) {
   3188         final MotionEvent event = (MotionEvent)q.mEvent;
   3189         if (mInputEventConsistencyVerifier != null) {
   3190             mInputEventConsistencyVerifier.onTrackballEvent(event, 0);
   3191         }
   3192 
   3193         // If there is no view, then the event will not be handled.
   3194         if (mView == null || !mAdded) {
   3195             finishInputEvent(q, false);
   3196             return;
   3197         }
   3198 
   3199         // Deliver the trackball event to the view.
   3200         if (mView.dispatchTrackballEvent(event)) {
   3201             // If we reach this, we delivered a trackball event to mView and
   3202             // mView consumed it. Because we will not translate the trackball
   3203             // event into a key event, touch mode will not exit, so we exit
   3204             // touch mode here.
   3205             ensureTouchMode(false);
   3206 
   3207             finishInputEvent(q, true);
   3208             mLastTrackballTime = Integer.MIN_VALUE;
   3209             return;
   3210         }
   3211 
   3212         // Translate the trackball event into DPAD keys and try to deliver those.
   3213         final TrackballAxis x = mTrackballAxisX;
   3214         final TrackballAxis y = mTrackballAxisY;
   3215 
   3216         long curTime = SystemClock.uptimeMillis();
   3217         if ((mLastTrackballTime + MAX_TRACKBALL_DELAY) < curTime) {
   3218             // It has been too long since the last movement,
   3219             // so restart at the beginning.
   3220             x.reset(0);
   3221             y.reset(0);
   3222             mLastTrackballTime = curTime;
   3223         }
   3224 
   3225         final int action = event.getAction();
   3226         final int metaState = event.getMetaState();
   3227         switch (action) {
   3228             case MotionEvent.ACTION_DOWN:
   3229                 x.reset(2);
   3230                 y.reset(2);
   3231                 enqueueInputEvent(new KeyEvent(curTime, curTime,
   3232                         KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
   3233                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   3234                         InputDevice.SOURCE_KEYBOARD));
   3235                 break;
   3236             case MotionEvent.ACTION_UP:
   3237                 x.reset(2);
   3238                 y.reset(2);
   3239                 enqueueInputEvent(new KeyEvent(curTime, curTime,
   3240                         KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
   3241                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   3242                         InputDevice.SOURCE_KEYBOARD));
   3243                 break;
   3244         }
   3245 
   3246         if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
   3247                 + x.step + " dir=" + x.dir + " acc=" + x.acceleration
   3248                 + " move=" + event.getX()
   3249                 + " / Y=" + y.position + " step="
   3250                 + y.step + " dir=" + y.dir + " acc=" + y.acceleration
   3251                 + " move=" + event.getY());
   3252         final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
   3253         final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
   3254 
   3255         // Generate DPAD events based on the trackball movement.
   3256         // We pick the axis that has moved the most as the direction of
   3257         // the DPAD.  When we generate DPAD events for one axis, then the
   3258         // other axis is reset -- we don't want to perform DPAD jumps due
   3259         // to slight movements in the trackball when making major movements
   3260         // along the other axis.
   3261         int keycode = 0;
   3262         int movement = 0;
   3263         float accel = 1;
   3264         if (xOff > yOff) {
   3265             movement = x.generate((2/event.getXPrecision()));
   3266             if (movement != 0) {
   3267                 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
   3268                         : KeyEvent.KEYCODE_DPAD_LEFT;
   3269                 accel = x.acceleration;
   3270                 y.reset(2);
   3271             }
   3272         } else if (yOff > 0) {
   3273             movement = y.generate((2/event.getYPrecision()));
   3274             if (movement != 0) {
   3275                 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
   3276                         : KeyEvent.KEYCODE_DPAD_UP;
   3277                 accel = y.acceleration;
   3278                 x.reset(2);
   3279             }
   3280         }
   3281 
   3282         if (keycode != 0) {
   3283             if (movement < 0) movement = -movement;
   3284             int accelMovement = (int)(movement * accel);
   3285             if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
   3286                     + " accelMovement=" + accelMovement
   3287                     + " accel=" + accel);
   3288             if (accelMovement > movement) {
   3289                 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
   3290                         + keycode);
   3291                 movement--;
   3292                 int repeatCount = accelMovement - movement;
   3293                 enqueueInputEvent(new KeyEvent(curTime, curTime,
   3294                         KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
   3295                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   3296                         InputDevice.SOURCE_KEYBOARD));
   3297             }
   3298             while (movement > 0) {
   3299                 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
   3300                         + keycode);
   3301                 movement--;
   3302                 curTime = SystemClock.uptimeMillis();
   3303                 enqueueInputEvent(new KeyEvent(curTime, curTime,
   3304                         KeyEvent.ACTION_DOWN, keycode, 0, metaState,
   3305                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   3306                         InputDevice.SOURCE_KEYBOARD));
   3307                 enqueueInputEvent(new KeyEvent(curTime, curTime,
   3308                         KeyEvent.ACTION_UP, keycode, 0, metaState,
   3309                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   3310                         InputDevice.SOURCE_KEYBOARD));
   3311             }
   3312             mLastTrackballTime = curTime;
   3313         }
   3314 
   3315         // Unfortunately we can't tell whether the application consumed the keys, so
   3316         // we always consider the trackball event handled.
   3317         finishInputEvent(q, true);
   3318     }
   3319 
   3320     private void deliverGenericMotionEvent(QueuedInputEvent q) {
   3321         final MotionEvent event = (MotionEvent)q.mEvent;
   3322         if (mInputEventConsistencyVerifier != null) {
   3323             mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
   3324         }
   3325 
   3326         final int source = event.getSource();
   3327         final boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0;
   3328 
   3329         // If there is no view, then the event will not be handled.
   3330         if (mView == null || !mAdded) {
   3331             if (isJoystick) {
   3332                 updateJoystickDirection(event, false);
   3333             }
   3334             finishInputEvent(q, false);
   3335             return;
   3336         }
   3337 
   3338         // Deliver the event to the view.
   3339         if (mView.dispatchGenericMotionEvent(event)) {
   3340             if (isJoystick) {
   3341                 updateJoystickDirection(event, false);
   3342             }
   3343             finishInputEvent(q, true);
   3344             return;
   3345         }
   3346 
   3347         if (isJoystick) {
   3348             // Translate the joystick event into DPAD keys and try to deliver those.
   3349             updateJoystickDirection(event, true);
   3350             finishInputEvent(q, true);
   3351         } else {
   3352             finishInputEvent(q, false);
   3353         }
   3354     }
   3355 
   3356     private void updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys) {
   3357         final long time = event.getEventTime();
   3358         final int metaState = event.getMetaState();
   3359         final int deviceId = event.getDeviceId();
   3360         final int source = event.getSource();
   3361 
   3362         int xDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_X));
   3363         if (xDirection == 0) {
   3364             xDirection = joystickAxisValueToDirection(event.getX());
   3365         }
   3366 
   3367         int yDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_Y));
   3368         if (yDirection == 0) {
   3369             yDirection = joystickAxisValueToDirection(event.getY());
   3370         }
   3371 
   3372         if (xDirection != mLastJoystickXDirection) {
   3373             if (mLastJoystickXKeyCode != 0) {
   3374                 enqueueInputEvent(new KeyEvent(time, time,
   3375                         KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState,
   3376                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
   3377                 mLastJoystickXKeyCode = 0;
   3378             }
   3379 
   3380             mLastJoystickXDirection = xDirection;
   3381 
   3382             if (xDirection != 0 && synthesizeNewKeys) {
   3383                 mLastJoystickXKeyCode = xDirection > 0
   3384                         ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
   3385                 enqueueInputEvent(new KeyEvent(time, time,
   3386                         KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState,
   3387                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
   3388             }
   3389         }
   3390 
   3391         if (yDirection != mLastJoystickYDirection) {
   3392             if (mLastJoystickYKeyCode != 0) {
   3393                 enqueueInputEvent(new KeyEvent(time, time,
   3394                         KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState,
   3395                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
   3396                 mLastJoystickYKeyCode = 0;
   3397             }
   3398 
   3399             mLastJoystickYDirection = yDirection;
   3400 
   3401             if (yDirection != 0 && synthesizeNewKeys) {
   3402                 mLastJoystickYKeyCode = yDirection > 0
   3403                         ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
   3404                 enqueueInputEvent(new KeyEvent(time, time,
   3405                         KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState,
   3406                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
   3407             }
   3408         }
   3409     }
   3410 
   3411     private static int joystickAxisValueToDirection(float value) {
   3412         if (value >= 0.5f) {
   3413             return 1;
   3414         } else if (value <= -0.5f) {
   3415             return -1;
   3416         } else {
   3417             return 0;
   3418         }
   3419     }
   3420 
   3421     /**
   3422      * Returns true if the key is used for keyboard navigation.
   3423      * @param keyEvent The key event.
   3424      * @return True if the key is used for keyboard navigation.
   3425      */
   3426     private static boolean isNavigationKey(KeyEvent keyEvent) {
   3427         switch (keyEvent.getKeyCode()) {
   3428         case KeyEvent.KEYCODE_DPAD_LEFT:
   3429         case KeyEvent.KEYCODE_DPAD_RIGHT:
   3430         case KeyEvent.KEYCODE_DPAD_UP:
   3431         case KeyEvent.KEYCODE_DPAD_DOWN:
   3432         case KeyEvent.KEYCODE_DPAD_CENTER:
   3433         case KeyEvent.KEYCODE_PAGE_UP:
   3434         case KeyEvent.KEYCODE_PAGE_DOWN:
   3435         case KeyEvent.KEYCODE_MOVE_HOME:
   3436         case KeyEvent.KEYCODE_MOVE_END:
   3437         case KeyEvent.KEYCODE_TAB:
   3438         case KeyEvent.KEYCODE_SPACE:
   3439         case KeyEvent.KEYCODE_ENTER:
   3440             return true;
   3441         }
   3442         return false;
   3443     }
   3444 
   3445     /**
   3446      * Returns true if the key is used for typing.
   3447      * @param keyEvent The key event.
   3448      * @return True if the key is used for typing.
   3449      */
   3450     private static boolean isTypingKey(KeyEvent keyEvent) {
   3451         return keyEvent.getUnicodeChar() > 0;
   3452     }
   3453 
   3454     /**
   3455      * See if the key event means we should leave touch mode (and leave touch mode if so).
   3456      * @param event The key event.
   3457      * @return Whether this key event should be consumed (meaning the act of
   3458      *   leaving touch mode alone is considered the event).
   3459      */
   3460     private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
   3461         // Only relevant in touch mode.
   3462         if (!mAttachInfo.mInTouchMode) {
   3463             return false;
   3464         }
   3465 
   3466         // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
   3467         final int action = event.getAction();
   3468         if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
   3469             return false;
   3470         }
   3471 
   3472         // Don't leave touch mode if the IME told us not to.
   3473         if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
   3474             return false;
   3475         }
   3476 
   3477         // If the key can be used for keyboard navigation then leave touch mode
   3478         // and select a focused view if needed (in ensureTouchMode).
   3479         // When a new focused view is selected, we consume the navigation key because
   3480         // navigation doesn't make much sense unless a view already has focus so
   3481         // the key's purpose is to set focus.
   3482         if (isNavigationKey(event)) {
   3483             return ensureTouchMode(false);
   3484         }
   3485 
   3486         // If the key can be used for typing then leave touch mode
   3487         // and select a focused view if needed (in ensureTouchMode).
   3488         // Always allow the view to process the typing key.
   3489         if (isTypingKey(event)) {
   3490             ensureTouchMode(false);
   3491             return false;
   3492         }
   3493 
   3494         return false;
   3495     }
   3496 
   3497     private void deliverKeyEvent(QueuedInputEvent q) {
   3498         final KeyEvent event = (KeyEvent)q.mEvent;
   3499         if (mInputEventConsistencyVerifier != null) {
   3500             mInputEventConsistencyVerifier.onKeyEvent(event, 0);
   3501         }
   3502 
   3503         if ((q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
   3504             // If there is no view, then the event will not be handled.
   3505             if (mView == null || !mAdded) {
   3506                 finishInputEvent(q, false);
   3507                 return;
   3508             }
   3509 
   3510             if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
   3511 
   3512             // Perform predispatching before the IME.
   3513             if (mView.dispatchKeyEventPreIme(event)) {
   3514                 finishInputEvent(q, true);
   3515                 return;
   3516             }
   3517 
   3518             // Dispatch to the IME before propagating down the view hierarchy.
   3519             // The IME will eventually call back into handleImeFinishedEvent.
   3520             if (mLastWasImTarget) {
   3521                 InputMethodManager imm = InputMethodManager.peekInstance();
   3522                 if (imm != null) {
   3523                     final int seq = event.getSequenceNumber();
   3524                     if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
   3525                             + seq + " event=" + event);
   3526                     imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
   3527                     return;
   3528