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 static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
     20 import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
     21 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
     22 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
     23 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
     24 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
     25 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
     26 
     27 import android.Manifest;
     28 import android.animation.LayoutTransition;
     29 import android.annotation.NonNull;
     30 import android.app.ActivityManagerNative;
     31 import android.app.ResourcesManager;
     32 import android.content.ClipDescription;
     33 import android.content.ComponentCallbacks;
     34 import android.content.Context;
     35 import android.content.pm.PackageManager;
     36 import android.content.res.CompatibilityInfo;
     37 import android.content.res.Configuration;
     38 import android.content.res.Resources;
     39 import android.graphics.Canvas;
     40 import android.graphics.Matrix;
     41 import android.graphics.PixelFormat;
     42 import android.graphics.Point;
     43 import android.graphics.PointF;
     44 import android.graphics.PorterDuff;
     45 import android.graphics.Rect;
     46 import android.graphics.Region;
     47 import android.graphics.drawable.AnimatedVectorDrawable;
     48 import android.graphics.drawable.Drawable;
     49 import android.hardware.display.DisplayManager;
     50 import android.hardware.display.DisplayManager.DisplayListener;
     51 import android.hardware.input.InputManager;
     52 import android.media.AudioManager;
     53 import android.os.Binder;
     54 import android.os.Build;
     55 import android.os.Bundle;
     56 import android.os.Debug;
     57 import android.os.Handler;
     58 import android.os.Looper;
     59 import android.os.Message;
     60 import android.os.ParcelFileDescriptor;
     61 import android.os.Process;
     62 import android.os.RemoteException;
     63 import android.os.SystemClock;
     64 import android.os.SystemProperties;
     65 import android.os.Trace;
     66 import android.util.AndroidRuntimeException;
     67 import android.util.DisplayMetrics;
     68 import android.util.Log;
     69 import android.util.Slog;
     70 import android.util.TimeUtils;
     71 import android.util.TypedValue;
     72 import android.view.Surface.OutOfResourcesException;
     73 import android.view.View.AttachInfo;
     74 import android.view.View.MeasureSpec;
     75 import android.view.accessibility.AccessibilityEvent;
     76 import android.view.accessibility.AccessibilityManager;
     77 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
     78 import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
     79 import android.view.accessibility.AccessibilityNodeInfo;
     80 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
     81 import android.view.accessibility.AccessibilityNodeProvider;
     82 import android.view.accessibility.IAccessibilityInteractionConnection;
     83 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
     84 import android.view.animation.AccelerateDecelerateInterpolator;
     85 import android.view.animation.Interpolator;
     86 import android.view.inputmethod.InputMethodManager;
     87 import android.widget.Scroller;
     88 
     89 import com.android.internal.R;
     90 import com.android.internal.annotations.GuardedBy;
     91 import com.android.internal.os.IResultReceiver;
     92 import com.android.internal.os.SomeArgs;
     93 import com.android.internal.policy.PhoneFallbackEventHandler;
     94 import com.android.internal.view.BaseSurfaceHolder;
     95 import com.android.internal.view.RootViewSurfaceTaker;
     96 
     97 import java.io.FileDescriptor;
     98 import java.io.IOException;
     99 import java.io.OutputStream;
    100 import java.io.PrintWriter;
    101 import java.lang.ref.WeakReference;
    102 import java.util.ArrayList;
    103 import java.util.HashSet;
    104 import java.util.concurrent.CountDownLatch;
    105 
    106 /**
    107  * The top of a view hierarchy, implementing the needed protocol between View
    108  * and the WindowManager.  This is for the most part an internal implementation
    109  * detail of {@link WindowManagerGlobal}.
    110  *
    111  * {@hide}
    112  */
    113 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
    114 public final class ViewRootImpl implements ViewParent,
    115         View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
    116     private static final String TAG = "ViewRootImpl";
    117     private static final boolean DBG = false;
    118     private static final boolean LOCAL_LOGV = false;
    119     /** @noinspection PointlessBooleanExpression*/
    120     private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
    121     private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
    122     private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
    123     private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
    124     private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
    125     private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
    126     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
    127     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
    128     private static final boolean DEBUG_FPS = false;
    129     private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
    130     private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
    131 
    132     /**
    133      * Set to false if we do not want to use the multi threaded renderer. Note that by disabling
    134      * this, WindowCallbacks will not fire.
    135      */
    136     private static final boolean USE_MT_RENDERER = true;
    137 
    138     /**
    139      * Set this system property to true to force the view hierarchy to render
    140      * at 60 Hz. This can be used to measure the potential framerate.
    141      */
    142     private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
    143 
    144     // properties used by emulator to determine display shape
    145     public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
    146             "ro.emu.win_outset_bottom_px";
    147 
    148     /**
    149      * Maximum time we allow the user to roll the trackball enough to generate
    150      * a key event, before resetting the counters.
    151      */
    152     static final int MAX_TRACKBALL_DELAY = 250;
    153 
    154     static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
    155 
    156     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
    157     static boolean sFirstDrawComplete = false;
    158 
    159     static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList();
    160 
    161     /**
    162      * This list must only be modified by the main thread, so a lock is only needed when changing
    163      * the list or when accessing the list from a non-main thread.
    164      */
    165     @GuardedBy("mWindowCallbacks")
    166     final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
    167     final Context mContext;
    168     final IWindowSession mWindowSession;
    169     @NonNull Display mDisplay;
    170     final DisplayManager mDisplayManager;
    171     final String mBasePackageName;
    172 
    173     final int[] mTmpLocation = new int[2];
    174 
    175     final TypedValue mTmpValue = new TypedValue();
    176 
    177     final Thread mThread;
    178 
    179     final WindowLeaked mLocation;
    180 
    181     final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
    182 
    183     final W mWindow;
    184 
    185     final int mTargetSdkVersion;
    186 
    187     int mSeq;
    188 
    189     View mView;
    190 
    191     View mAccessibilityFocusedHost;
    192     AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
    193 
    194     // The view which captures mouse input, or null when no one is capturing.
    195     View mCapturingView;
    196 
    197     int mViewVisibility;
    198     boolean mAppVisible = true;
    199     // For recents to freeform transition we need to keep drawing after the app receives information
    200     // that it became invisible. This will ignore that information and depend on the decor view
    201     // visibility to control drawing. The decor view visibility will get adjusted when the app get
    202     // stopped and that's when the app will stop drawing further frames.
    203     private boolean mForceDecorViewVisibility = false;
    204     int mOrigWindowType = -1;
    205 
    206     /** Whether the window had focus during the most recent traversal. */
    207     boolean mHadWindowFocus;
    208 
    209     /**
    210      * Whether the window lost focus during a previous traversal and has not
    211      * yet gained it back. Used to determine whether a WINDOW_STATE_CHANGE
    212      * accessibility events should be sent during traversal.
    213      */
    214     boolean mLostWindowFocus;
    215 
    216     // Set to true if the owner of this window is in the stopped state,
    217     // so the window should no longer be active.
    218     boolean mStopped = false;
    219 
    220     // Set to true if the owner of this window is in ambient mode,
    221     // which means it won't receive input events.
    222     boolean mIsAmbientMode = false;
    223 
    224     // Set to true to stop input during an Activity Transition.
    225     boolean mPausedForTransition = false;
    226 
    227     boolean mLastInCompatMode = false;
    228 
    229     SurfaceHolder.Callback2 mSurfaceHolderCallback;
    230     BaseSurfaceHolder mSurfaceHolder;
    231     boolean mIsCreating;
    232     boolean mDrawingAllowed;
    233 
    234     final Region mTransparentRegion;
    235     final Region mPreviousTransparentRegion;
    236 
    237     int mWidth;
    238     int mHeight;
    239     Rect mDirty;
    240     boolean mIsAnimating;
    241 
    242     private boolean mDragResizing;
    243     private boolean mInvalidateRootRequested;
    244     private int mResizeMode;
    245     private int mCanvasOffsetX;
    246     private int mCanvasOffsetY;
    247     private boolean mActivityRelaunched;
    248 
    249     CompatibilityInfo.Translator mTranslator;
    250 
    251     final View.AttachInfo mAttachInfo;
    252     InputChannel mInputChannel;
    253     InputQueue.Callback mInputQueueCallback;
    254     InputQueue mInputQueue;
    255     FallbackEventHandler mFallbackEventHandler;
    256     Choreographer mChoreographer;
    257 
    258     final Rect mTempRect; // used in the transaction to not thrash the heap.
    259     final Rect mVisRect; // used to retrieve visible rect of focused view.
    260 
    261     boolean mTraversalScheduled;
    262     int mTraversalBarrier;
    263     boolean mWillDrawSoon;
    264     /** Set to true while in performTraversals for detecting when die(true) is called from internal
    265      * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
    266     boolean mIsInTraversal;
    267     boolean mApplyInsetsRequested;
    268     boolean mLayoutRequested;
    269     boolean mFirst;
    270     boolean mReportNextDraw;
    271     boolean mFullRedrawNeeded;
    272     boolean mNewSurfaceNeeded;
    273     boolean mHasHadWindowFocus;
    274     boolean mLastWasImTarget;
    275     boolean mForceNextWindowRelayout;
    276     CountDownLatch mWindowDrawCountDown;
    277 
    278     boolean mIsDrawing;
    279     int mLastSystemUiVisibility;
    280     int mClientWindowLayoutFlags;
    281     boolean mLastOverscanRequested;
    282 
    283     // Pool of queued input events.
    284     private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
    285     private QueuedInputEvent mQueuedInputEventPool;
    286     private int mQueuedInputEventPoolSize;
    287 
    288     /* Input event queue.
    289      * Pending input events are input events waiting to be delivered to the input stages
    290      * and handled by the application.
    291      */
    292     QueuedInputEvent mPendingInputEventHead;
    293     QueuedInputEvent mPendingInputEventTail;
    294     int mPendingInputEventCount;
    295     boolean mProcessInputEventsScheduled;
    296     boolean mUnbufferedInputDispatch;
    297     String mPendingInputEventQueueLengthCounterName = "pq";
    298 
    299     InputStage mFirstInputStage;
    300     InputStage mFirstPostImeInputStage;
    301     InputStage mSyntheticInputStage;
    302 
    303     boolean mWindowAttributesChanged = false;
    304     int mWindowAttributesChangesFlag = 0;
    305 
    306     // These can be accessed by any thread, must be protected with a lock.
    307     // Surface can never be reassigned or cleared (use Surface.clear()).
    308     final Surface mSurface = new Surface();
    309 
    310     boolean mAdded;
    311     boolean mAddedTouchMode;
    312 
    313     // These are accessed by multiple threads.
    314     final Rect mWinFrame; // frame given by window manager.
    315 
    316     final Rect mPendingOverscanInsets = new Rect();
    317     final Rect mPendingVisibleInsets = new Rect();
    318     final Rect mPendingStableInsets = new Rect();
    319     final Rect mPendingContentInsets = new Rect();
    320     final Rect mPendingOutsets = new Rect();
    321     final Rect mPendingBackDropFrame = new Rect();
    322     boolean mPendingAlwaysConsumeNavBar;
    323     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
    324             = new ViewTreeObserver.InternalInsetsInfo();
    325 
    326     final Rect mDispatchContentInsets = new Rect();
    327     final Rect mDispatchStableInsets = new Rect();
    328 
    329     private WindowInsets mLastWindowInsets;
    330 
    331     final Configuration mLastConfiguration = new Configuration();
    332     final Configuration mPendingConfiguration = new Configuration();
    333 
    334     boolean mScrollMayChange;
    335     int mSoftInputMode;
    336     WeakReference<View> mLastScrolledFocus;
    337     int mScrollY;
    338     int mCurScrollY;
    339     Scroller mScroller;
    340     static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
    341     private ArrayList<LayoutTransition> mPendingTransitions;
    342 
    343     final ViewConfiguration mViewConfiguration;
    344 
    345     /* Drag/drop */
    346     ClipDescription mDragDescription;
    347     View mCurrentDragView;
    348     volatile Object mLocalDragState;
    349     final PointF mDragPoint = new PointF();
    350     final PointF mLastTouchPoint = new PointF();
    351     int mLastTouchSource;
    352 
    353     private boolean mProfileRendering;
    354     private Choreographer.FrameCallback mRenderProfiler;
    355     private boolean mRenderProfilingEnabled;
    356 
    357     // Variables to track frames per second, enabled via DEBUG_FPS flag
    358     private long mFpsStartTime = -1;
    359     private long mFpsPrevTime = -1;
    360     private int mFpsNumFrames;
    361 
    362     private int mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
    363     private PointerIcon mCustomPointerIcon = null;
    364 
    365     /**
    366      * see {@link #playSoundEffect(int)}
    367      */
    368     AudioManager mAudioManager;
    369 
    370     final AccessibilityManager mAccessibilityManager;
    371 
    372     AccessibilityInteractionController mAccessibilityInteractionController;
    373 
    374     AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
    375     HighContrastTextManager mHighContrastTextManager;
    376 
    377     SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
    378 
    379     HashSet<View> mTempHashSet;
    380 
    381     private final int mDensity;
    382     private final int mNoncompatDensity;
    383 
    384     private boolean mInLayout = false;
    385     ArrayList<View> mLayoutRequesters = new ArrayList<View>();
    386     boolean mHandlingLayoutInLayoutRequest = false;
    387 
    388     private int mViewLayoutDirectionInitial;
    389 
    390     /** Set to true once doDie() has been called. */
    391     private boolean mRemoved;
    392 
    393     private boolean mNeedsHwRendererSetup;
    394 
    395     /**
    396      * Consistency verifier for debugging purposes.
    397      */
    398     protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
    399             InputEventConsistencyVerifier.isInstrumentationEnabled() ?
    400                     new InputEventConsistencyVerifier(this, 0) : null;
    401 
    402     static final class SystemUiVisibilityInfo {
    403         int seq;
    404         int globalVisibility;
    405         int localValue;
    406         int localChanges;
    407     }
    408 
    409     private String mTag = TAG;
    410 
    411     public ViewRootImpl(Context context, Display display) {
    412         mContext = context;
    413         mWindowSession = WindowManagerGlobal.getWindowSession();
    414         mDisplay = display;
    415         mBasePackageName = context.getBasePackageName();
    416         mThread = Thread.currentThread();
    417         mLocation = new WindowLeaked(null);
    418         mLocation.fillInStackTrace();
    419         mWidth = -1;
    420         mHeight = -1;
    421         mDirty = new Rect();
    422         mTempRect = new Rect();
    423         mVisRect = new Rect();
    424         mWinFrame = new Rect();
    425         mWindow = new W(this);
    426         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
    427         mViewVisibility = View.GONE;
    428         mTransparentRegion = new Region();
    429         mPreviousTransparentRegion = new Region();
    430         mFirst = true; // true for the first time the view is added
    431         mAdded = false;
    432         mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
    433         mAccessibilityManager = AccessibilityManager.getInstance(context);
    434         mAccessibilityInteractionConnectionManager =
    435             new AccessibilityInteractionConnectionManager();
    436         mAccessibilityManager.addAccessibilityStateChangeListener(
    437                 mAccessibilityInteractionConnectionManager);
    438         mHighContrastTextManager = new HighContrastTextManager();
    439         mAccessibilityManager.addHighTextContrastStateChangeListener(
    440                 mHighContrastTextManager);
    441         mViewConfiguration = ViewConfiguration.get(context);
    442         mDensity = context.getResources().getDisplayMetrics().densityDpi;
    443         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
    444         mFallbackEventHandler = new PhoneFallbackEventHandler(context);
    445         mChoreographer = Choreographer.getInstance();
    446         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    447         loadSystemProperties();
    448     }
    449 
    450     public static void addFirstDrawHandler(Runnable callback) {
    451         synchronized (sFirstDrawHandlers) {
    452             if (!sFirstDrawComplete) {
    453                 sFirstDrawHandlers.add(callback);
    454             }
    455         }
    456     }
    457 
    458     public static void addConfigCallback(ComponentCallbacks callback) {
    459         synchronized (sConfigCallbacks) {
    460             sConfigCallbacks.add(callback);
    461         }
    462     }
    463 
    464     public void addWindowCallbacks(WindowCallbacks callback) {
    465         if (USE_MT_RENDERER) {
    466             synchronized (mWindowCallbacks) {
    467                 mWindowCallbacks.add(callback);
    468             }
    469         }
    470     }
    471 
    472     public void removeWindowCallbacks(WindowCallbacks callback) {
    473         if (USE_MT_RENDERER) {
    474             synchronized (mWindowCallbacks) {
    475                 mWindowCallbacks.remove(callback);
    476             }
    477         }
    478     }
    479 
    480     public void reportDrawFinish() {
    481         if (mWindowDrawCountDown != null) {
    482             mWindowDrawCountDown.countDown();
    483         }
    484     }
    485 
    486     // FIXME for perf testing only
    487     private boolean mProfile = false;
    488 
    489     /**
    490      * Call this to profile the next traversal call.
    491      * FIXME for perf testing only. Remove eventually
    492      */
    493     public void profile() {
    494         mProfile = true;
    495     }
    496 
    497     /**
    498      * Indicates whether we are in touch mode. Calling this method triggers an IPC
    499      * call and should be avoided whenever possible.
    500      *
    501      * @return True, if the device is in touch mode, false otherwise.
    502      *
    503      * @hide
    504      */
    505     static boolean isInTouchMode() {
    506         IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
    507         if (windowSession != null) {
    508             try {
    509                 return windowSession.getInTouchMode();
    510             } catch (RemoteException e) {
    511             }
    512         }
    513         return false;
    514     }
    515 
    516     /**
    517      * Notifies us that our child has been rebuilt, following
    518      * a window preservation operation. In these cases we
    519      * keep the same DecorView, but the activity controlling it
    520      * is a different instance, and we need to update our
    521      * callbacks.
    522      *
    523      * @hide
    524      */
    525     public void notifyChildRebuilt() {
    526         if (mView instanceof RootViewSurfaceTaker) {
    527             mSurfaceHolderCallback =
    528                 ((RootViewSurfaceTaker)mView).willYouTakeTheSurface();
    529             if (mSurfaceHolderCallback != null) {
    530                 mSurfaceHolder = new TakenSurfaceHolder();
    531                 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
    532             } else {
    533                 mSurfaceHolder = null;
    534             }
    535 
    536             mInputQueueCallback =
    537                 ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue();
    538             if (mInputQueueCallback != null) {
    539                 mInputQueueCallback.onInputQueueCreated(mInputQueue);
    540             }
    541         }
    542     }
    543 
    544     /**
    545      * We have one child
    546      */
    547     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    548         synchronized (this) {
    549             if (mView == null) {
    550                 mView = view;
    551 
    552                 mAttachInfo.mDisplayState = mDisplay.getState();
    553                 mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
    554 
    555                 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
    556                 mFallbackEventHandler.setView(view);
    557                 mWindowAttributes.copyFrom(attrs);
    558                 if (mWindowAttributes.packageName == null) {
    559                     mWindowAttributes.packageName = mBasePackageName;
    560                 }
    561                 attrs = mWindowAttributes;
    562                 setTag();
    563 
    564                 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
    565                         & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
    566                         && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
    567                     Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
    568                 }
    569                 // Keep track of the actual window flags supplied by the client.
    570                 mClientWindowLayoutFlags = attrs.flags;
    571 
    572                 setAccessibilityFocus(null, null);
    573 
    574                 if (view instanceof RootViewSurfaceTaker) {
    575                     mSurfaceHolderCallback =
    576                             ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
    577                     if (mSurfaceHolderCallback != null) {
    578                         mSurfaceHolder = new TakenSurfaceHolder();
    579                         mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
    580                     }
    581                 }
    582 
    583                 // Compute surface insets required to draw at specified Z value.
    584                 // TODO: Use real shadow insets for a constant max Z.
    585                 if (!attrs.hasManualSurfaceInsets) {
    586                     attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
    587                 }
    588 
    589                 CompatibilityInfo compatibilityInfo =
    590                         mDisplay.getDisplayAdjustments().getCompatibilityInfo();
    591                 mTranslator = compatibilityInfo.getTranslator();
    592 
    593                 // If the application owns the surface, don't enable hardware acceleration
    594                 if (mSurfaceHolder == null) {
    595                     enableHardwareAcceleration(attrs);
    596                 }
    597 
    598                 boolean restore = false;
    599                 if (mTranslator != null) {
    600                     mSurface.setCompatibilityTranslator(mTranslator);
    601                     restore = true;
    602                     attrs.backup();
    603                     mTranslator.translateWindowLayout(attrs);
    604                 }
    605                 if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
    606 
    607                 if (!compatibilityInfo.supportsScreen()) {
    608                     attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
    609                     mLastInCompatMode = true;
    610                 }
    611 
    612                 mSoftInputMode = attrs.softInputMode;
    613                 mWindowAttributesChanged = true;
    614                 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
    615                 mAttachInfo.mRootView = view;
    616                 mAttachInfo.mScalingRequired = mTranslator != null;
    617                 mAttachInfo.mApplicationScale =
    618                         mTranslator == null ? 1.0f : mTranslator.applicationScale;
    619                 if (panelParentView != null) {
    620                     mAttachInfo.mPanelParentWindowToken
    621                             = panelParentView.getApplicationWindowToken();
    622                 }
    623                 mAdded = true;
    624                 int res; /* = WindowManagerImpl.ADD_OKAY; */
    625 
    626                 // Schedule the first layout -before- adding to the window
    627                 // manager, to make sure we do the relayout before receiving
    628                 // any other events from the system.
    629                 requestLayout();
    630                 if ((mWindowAttributes.inputFeatures
    631                         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
    632                     mInputChannel = new InputChannel();
    633                 }
    634                 mForceDecorViewVisibility = (mWindowAttributes.privateFlags
    635                         & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
    636                 try {
    637                     mOrigWindowType = mWindowAttributes.type;
    638                     mAttachInfo.mRecomputeGlobalAttributes = true;
    639                     collectViewAttributes();
    640                     res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
    641                             getHostVisibility(), mDisplay.getDisplayId(),
    642                             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
    643                             mAttachInfo.mOutsets, mInputChannel);
    644                 } catch (RemoteException e) {
    645                     mAdded = false;
    646                     mView = null;
    647                     mAttachInfo.mRootView = null;
    648                     mInputChannel = null;
    649                     mFallbackEventHandler.setView(null);
    650                     unscheduleTraversals();
    651                     setAccessibilityFocus(null, null);
    652                     throw new RuntimeException("Adding window failed", e);
    653                 } finally {
    654                     if (restore) {
    655                         attrs.restore();
    656                     }
    657                 }
    658 
    659                 if (mTranslator != null) {
    660                     mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
    661                 }
    662                 mPendingOverscanInsets.set(0, 0, 0, 0);
    663                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
    664                 mPendingStableInsets.set(mAttachInfo.mStableInsets);
    665                 mPendingVisibleInsets.set(0, 0, 0, 0);
    666                 mAttachInfo.mAlwaysConsumeNavBar =
    667                         (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
    668                 mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
    669                 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
    670                 if (res < WindowManagerGlobal.ADD_OKAY) {
    671                     mAttachInfo.mRootView = null;
    672                     mAdded = false;
    673                     mFallbackEventHandler.setView(null);
    674                     unscheduleTraversals();
    675                     setAccessibilityFocus(null, null);
    676                     switch (res) {
    677                         case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
    678                         case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
    679                             throw new WindowManager.BadTokenException(
    680                                     "Unable to add window -- token " + attrs.token
    681                                     + " is not valid; is your activity running?");
    682                         case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
    683                             throw new WindowManager.BadTokenException(
    684                                     "Unable to add window -- token " + attrs.token
    685                                     + " is not for an application");
    686                         case WindowManagerGlobal.ADD_APP_EXITING:
    687                             throw new WindowManager.BadTokenException(
    688                                     "Unable to add window -- app for token " + attrs.token
    689                                     + " is exiting");
    690                         case WindowManagerGlobal.ADD_DUPLICATE_ADD:
    691                             throw new WindowManager.BadTokenException(
    692                                     "Unable to add window -- window " + mWindow
    693                                     + " has already been added");
    694                         case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
    695                             // Silently ignore -- we would have just removed it
    696                             // right away, anyway.
    697                             return;
    698                         case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
    699                             throw new WindowManager.BadTokenException("Unable to add window "
    700                                     + mWindow + " -- another window of type "
    701                                     + mWindowAttributes.type + " already exists");
    702                         case WindowManagerGlobal.ADD_PERMISSION_DENIED:
    703                             throw new WindowManager.BadTokenException("Unable to add window "
    704                                     + mWindow + " -- permission denied for window type "
    705                                     + mWindowAttributes.type);
    706                         case WindowManagerGlobal.ADD_INVALID_DISPLAY:
    707                             throw new WindowManager.InvalidDisplayException("Unable to add window "
    708                                     + mWindow + " -- the specified display can not be found");
    709                         case WindowManagerGlobal.ADD_INVALID_TYPE:
    710                             throw new WindowManager.InvalidDisplayException("Unable to add window "
    711                                     + mWindow + " -- the specified window type "
    712                                     + mWindowAttributes.type + " is not valid");
    713                     }
    714                     throw new RuntimeException(
    715                             "Unable to add window -- unknown error code " + res);
    716                 }
    717 
    718                 if (view instanceof RootViewSurfaceTaker) {
    719                     mInputQueueCallback =
    720                         ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
    721                 }
    722                 if (mInputChannel != null) {
    723                     if (mInputQueueCallback != null) {
    724                         mInputQueue = new InputQueue();
    725                         mInputQueueCallback.onInputQueueCreated(mInputQueue);
    726                     }
    727                     mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
    728                             Looper.myLooper());
    729                 }
    730 
    731                 view.assignParent(this);
    732                 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
    733                 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
    734 
    735                 if (mAccessibilityManager.isEnabled()) {
    736                     mAccessibilityInteractionConnectionManager.ensureConnection();
    737                 }
    738 
    739                 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
    740                     view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
    741                 }
    742 
    743                 // Set up the input pipeline.
    744                 CharSequence counterSuffix = attrs.getTitle();
    745                 mSyntheticInputStage = new SyntheticInputStage();
    746                 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
    747                 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
    748                         "aq:native-post-ime:" + counterSuffix);
    749                 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
    750                 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
    751                         "aq:ime:" + counterSuffix);
    752                 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
    753                 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
    754                         "aq:native-pre-ime:" + counterSuffix);
    755 
    756                 mFirstInputStage = nativePreImeStage;
    757                 mFirstPostImeInputStage = earlyPostImeStage;
    758                 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
    759             }
    760         }
    761     }
    762 
    763     private void setTag() {
    764         final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
    765         if (split.length > 0) {
    766             mTag = TAG + "[" + split[split.length - 1] + "]";
    767         }
    768     }
    769 
    770     /** Whether the window is in local focus mode or not */
    771     private boolean isInLocalFocusMode() {
    772         return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
    773     }
    774 
    775     public int getWindowFlags() {
    776         return mWindowAttributes.flags;
    777     }
    778 
    779     public int getDisplayId() {
    780         return mDisplay.getDisplayId();
    781     }
    782 
    783     public CharSequence getTitle() {
    784         return mWindowAttributes.getTitle();
    785     }
    786 
    787     void destroyHardwareResources() {
    788         if (mAttachInfo.mHardwareRenderer != null) {
    789             mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
    790             mAttachInfo.mHardwareRenderer.destroy();
    791         }
    792     }
    793 
    794     public void detachFunctor(long functor) {
    795         if (mAttachInfo.mHardwareRenderer != null) {
    796             // Fence so that any pending invokeFunctor() messages will be processed
    797             // before we return from detachFunctor.
    798             mAttachInfo.mHardwareRenderer.stopDrawing();
    799         }
    800     }
    801 
    802     /**
    803      * Schedules the functor for execution in either kModeProcess or
    804      * kModeProcessNoContext, depending on whether or not there is an EGLContext.
    805      *
    806      * @param functor The native functor to invoke
    807      * @param waitForCompletion If true, this will not return until the functor
    808      *                          has invoked. If false, the functor may be invoked
    809      *                          asynchronously.
    810      */
    811     public static void invokeFunctor(long functor, boolean waitForCompletion) {
    812         ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
    813     }
    814 
    815     public void registerAnimatingRenderNode(RenderNode animator) {
    816         if (mAttachInfo.mHardwareRenderer != null) {
    817             mAttachInfo.mHardwareRenderer.registerAnimatingRenderNode(animator);
    818         } else {
    819             if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
    820                 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
    821             }
    822             mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
    823         }
    824     }
    825 
    826     public void registerVectorDrawableAnimator(
    827             AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
    828         if (mAttachInfo.mHardwareRenderer != null) {
    829             mAttachInfo.mHardwareRenderer.registerVectorDrawableAnimator(animator);
    830         }
    831     }
    832 
    833     private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
    834         mAttachInfo.mHardwareAccelerated = false;
    835         mAttachInfo.mHardwareAccelerationRequested = false;
    836 
    837         // Don't enable hardware acceleration when the application is in compatibility mode
    838         if (mTranslator != null) return;
    839 
    840         // Try to enable hardware acceleration if requested
    841         final boolean hardwareAccelerated =
    842                 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
    843 
    844         if (hardwareAccelerated) {
    845             if (!ThreadedRenderer.isAvailable()) {
    846                 return;
    847             }
    848 
    849             // Persistent processes (including the system) should not do
    850             // accelerated rendering on low-end devices.  In that case,
    851             // sRendererDisabled will be set.  In addition, the system process
    852             // itself should never do accelerated rendering.  In that case, both
    853             // sRendererDisabled and sSystemRendererDisabled are set.  When
    854             // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
    855             // can be used by code on the system process to escape that and enable
    856             // HW accelerated drawing.  (This is basically for the lock screen.)
    857 
    858             final boolean fakeHwAccelerated = (attrs.privateFlags &
    859                     WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
    860             final boolean forceHwAccelerated = (attrs.privateFlags &
    861                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
    862 
    863             if (fakeHwAccelerated) {
    864                 // This is exclusively for the preview windows the window manager
    865                 // shows for launching applications, so they will look more like
    866                 // the app being launched.
    867                 mAttachInfo.mHardwareAccelerationRequested = true;
    868             } else if (!ThreadedRenderer.sRendererDisabled
    869                     || (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
    870                 if (mAttachInfo.mHardwareRenderer != null) {
    871                     mAttachInfo.mHardwareRenderer.destroy();
    872                 }
    873 
    874                 final Rect insets = attrs.surfaceInsets;
    875                 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
    876                         || insets.top != 0 || insets.bottom != 0;
    877                 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
    878                 mAttachInfo.mHardwareRenderer = ThreadedRenderer.create(mContext, translucent);
    879                 if (mAttachInfo.mHardwareRenderer != null) {
    880                     mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
    881                     mAttachInfo.mHardwareAccelerated =
    882                             mAttachInfo.mHardwareAccelerationRequested = true;
    883                 }
    884             }
    885         }
    886     }
    887 
    888     public View getView() {
    889         return mView;
    890     }
    891 
    892     final WindowLeaked getLocation() {
    893         return mLocation;
    894     }
    895 
    896     void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
    897         synchronized (this) {
    898             final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
    899             final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
    900             final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
    901             final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
    902             final int oldSoftInputMode = mWindowAttributes.softInputMode;
    903             final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
    904 
    905             if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
    906                     & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
    907                     && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
    908                 Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!");
    909             }
    910 
    911             // Keep track of the actual window flags supplied by the client.
    912             mClientWindowLayoutFlags = attrs.flags;
    913 
    914             // Preserve compatible window flag if exists.
    915             final int compatibleWindowFlag = mWindowAttributes.privateFlags
    916                     & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
    917 
    918             // Transfer over system UI visibility values as they carry current state.
    919             attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
    920             attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
    921 
    922             mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
    923             if ((mWindowAttributesChangesFlag
    924                     & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
    925                 // Recompute system ui visibility.
    926                 mAttachInfo.mRecomputeGlobalAttributes = true;
    927             }
    928             if ((mWindowAttributesChangesFlag
    929                     & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
    930                 // Request to update light center.
    931                 mAttachInfo.mNeedsUpdateLightCenter = true;
    932             }
    933             if (mWindowAttributes.packageName == null) {
    934                 mWindowAttributes.packageName = mBasePackageName;
    935             }
    936             mWindowAttributes.privateFlags |= compatibleWindowFlag;
    937 
    938             if (mWindowAttributes.preservePreviousSurfaceInsets) {
    939                 // Restore old surface insets.
    940                 mWindowAttributes.surfaceInsets.set(
    941                         oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
    942                 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
    943             } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft
    944                     || mWindowAttributes.surfaceInsets.top != oldInsetTop
    945                     || mWindowAttributes.surfaceInsets.right != oldInsetRight
    946                     || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) {
    947                 mNeedsHwRendererSetup = true;
    948             }
    949 
    950             applyKeepScreenOnFlag(mWindowAttributes);
    951 
    952             if (newView) {
    953                 mSoftInputMode = attrs.softInputMode;
    954                 requestLayout();
    955             }
    956 
    957             // Don't lose the mode we last auto-computed.
    958             if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
    959                     == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
    960                 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
    961                         & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
    962                         | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
    963             }
    964 
    965             mWindowAttributesChanged = true;
    966             scheduleTraversals();
    967         }
    968     }
    969 
    970     void handleAppVisibility(boolean visible) {
    971         if (mAppVisible != visible) {
    972             mAppVisible = visible;
    973             scheduleTraversals();
    974             if (!mAppVisible) {
    975                 WindowManagerGlobal.trimForeground();
    976             }
    977         }
    978     }
    979 
    980     void handleGetNewSurface() {
    981         mNewSurfaceNeeded = true;
    982         mFullRedrawNeeded = true;
    983         scheduleTraversals();
    984     }
    985 
    986     private final DisplayListener mDisplayListener = new DisplayListener() {
    987         @Override
    988         public void onDisplayChanged(int displayId) {
    989             if (mView != null && mDisplay.getDisplayId() == displayId) {
    990                 final int oldDisplayState = mAttachInfo.mDisplayState;
    991                 final int newDisplayState = mDisplay.getState();
    992                 if (oldDisplayState != newDisplayState) {
    993                     mAttachInfo.mDisplayState = newDisplayState;
    994                     pokeDrawLockIfNeeded();
    995                     if (oldDisplayState != Display.STATE_UNKNOWN) {
    996                         final int oldScreenState = toViewScreenState(oldDisplayState);
    997                         final int newScreenState = toViewScreenState(newDisplayState);
    998                         if (oldScreenState != newScreenState) {
    999                             mView.dispatchScreenStateChanged(newScreenState);
   1000                         }
   1001                         if (oldDisplayState == Display.STATE_OFF) {
   1002                             // Draw was suppressed so we need to for it to happen here.
   1003                             mFullRedrawNeeded = true;
   1004                             scheduleTraversals();
   1005                         }
   1006                     }
   1007                 }
   1008             }
   1009         }
   1010 
   1011         @Override
   1012         public void onDisplayRemoved(int displayId) {
   1013         }
   1014 
   1015         @Override
   1016         public void onDisplayAdded(int displayId) {
   1017         }
   1018 
   1019         private int toViewScreenState(int displayState) {
   1020             return displayState == Display.STATE_OFF ?
   1021                     View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
   1022         }
   1023     };
   1024 
   1025     void pokeDrawLockIfNeeded() {
   1026         final int displayState = mAttachInfo.mDisplayState;
   1027         if (mView != null && mAdded && mTraversalScheduled
   1028                 && (displayState == Display.STATE_DOZE
   1029                         || displayState == Display.STATE_DOZE_SUSPEND)) {
   1030             try {
   1031                 mWindowSession.pokeDrawLock(mWindow);
   1032             } catch (RemoteException ex) {
   1033                 // System server died, oh well.
   1034             }
   1035         }
   1036     }
   1037 
   1038     @Override
   1039     public void requestFitSystemWindows() {
   1040         checkThread();
   1041         mApplyInsetsRequested = true;
   1042         scheduleTraversals();
   1043     }
   1044 
   1045     @Override
   1046     public void requestLayout() {
   1047         if (!mHandlingLayoutInLayoutRequest) {
   1048             checkThread();
   1049             mLayoutRequested = true;
   1050             scheduleTraversals();
   1051         }
   1052     }
   1053 
   1054     @Override
   1055     public boolean isLayoutRequested() {
   1056         return mLayoutRequested;
   1057     }
   1058 
   1059     void invalidate() {
   1060         mDirty.set(0, 0, mWidth, mHeight);
   1061         if (!mWillDrawSoon) {
   1062             scheduleTraversals();
   1063         }
   1064     }
   1065 
   1066     void invalidateWorld(View view) {
   1067         view.invalidate();
   1068         if (view instanceof ViewGroup) {
   1069             ViewGroup parent = (ViewGroup) view;
   1070             for (int i = 0; i < parent.getChildCount(); i++) {
   1071                 invalidateWorld(parent.getChildAt(i));
   1072             }
   1073         }
   1074     }
   1075 
   1076     @Override
   1077     public void invalidateChild(View child, Rect dirty) {
   1078         invalidateChildInParent(null, dirty);
   1079     }
   1080 
   1081     @Override
   1082     public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
   1083         checkThread();
   1084         if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
   1085 
   1086         if (dirty == null) {
   1087             invalidate();
   1088             return null;
   1089         } else if (dirty.isEmpty() && !mIsAnimating) {
   1090             return null;
   1091         }
   1092 
   1093         if (mCurScrollY != 0 || mTranslator != null) {
   1094             mTempRect.set(dirty);
   1095             dirty = mTempRect;
   1096             if (mCurScrollY != 0) {
   1097                 dirty.offset(0, -mCurScrollY);
   1098             }
   1099             if (mTranslator != null) {
   1100                 mTranslator.translateRectInAppWindowToScreen(dirty);
   1101             }
   1102             if (mAttachInfo.mScalingRequired) {
   1103                 dirty.inset(-1, -1);
   1104             }
   1105         }
   1106 
   1107         invalidateRectOnScreen(dirty);
   1108 
   1109         return null;
   1110     }
   1111 
   1112     private void invalidateRectOnScreen(Rect dirty) {
   1113         final Rect localDirty = mDirty;
   1114         if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
   1115             mAttachInfo.mSetIgnoreDirtyState = true;
   1116             mAttachInfo.mIgnoreDirtyState = true;
   1117         }
   1118 
   1119         // Add the new dirty rect to the current one
   1120         localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
   1121         // Intersect with the bounds of the window to skip
   1122         // updates that lie outside of the visible region
   1123         final float appScale = mAttachInfo.mApplicationScale;
   1124         final boolean intersected = localDirty.intersect(0, 0,
   1125                 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
   1126         if (!intersected) {
   1127             localDirty.setEmpty();
   1128         }
   1129         if (!mWillDrawSoon && (intersected || mIsAnimating)) {
   1130             scheduleTraversals();
   1131         }
   1132     }
   1133 
   1134     public void setIsAmbientMode(boolean ambient) {
   1135         mIsAmbientMode = ambient;
   1136     }
   1137 
   1138     void setWindowStopped(boolean stopped) {
   1139         if (mStopped != stopped) {
   1140             mStopped = stopped;
   1141             final ThreadedRenderer renderer = mAttachInfo.mHardwareRenderer;
   1142             if (renderer != null) {
   1143                 if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
   1144                 renderer.setStopped(mStopped);
   1145             }
   1146             if (!mStopped) {
   1147                 scheduleTraversals();
   1148             } else {
   1149                 if (renderer != null) {
   1150                     renderer.destroyHardwareResources(mView);
   1151                 }
   1152             }
   1153         }
   1154     }
   1155 
   1156     /**
   1157      * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
   1158      * through to allow quick reversal of the Activity Transition.
   1159      *
   1160      * @param paused true to pause, false to resume.
   1161      */
   1162     public void setPausedForTransition(boolean paused) {
   1163         mPausedForTransition = paused;
   1164     }
   1165 
   1166     @Override
   1167     public ViewParent getParent() {
   1168         return null;
   1169     }
   1170 
   1171     @Override
   1172     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
   1173         if (child != mView) {
   1174             throw new RuntimeException("child is not mine, honest!");
   1175         }
   1176         // Note: don't apply scroll offset, because we want to know its
   1177         // visibility in the virtual canvas being given to the view hierarchy.
   1178         return r.intersect(0, 0, mWidth, mHeight);
   1179     }
   1180 
   1181     @Override
   1182     public void bringChildToFront(View child) {
   1183     }
   1184 
   1185     int getHostVisibility() {
   1186         return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE;
   1187     }
   1188 
   1189     /**
   1190      * Add LayoutTransition to the list of transitions to be started in the next traversal.
   1191      * This list will be cleared after the transitions on the list are start()'ed. These
   1192      * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
   1193      * happens during the layout phase of traversal, which we want to complete before any of the
   1194      * animations are started (because those animations may side-effect properties that layout
   1195      * depends upon, like the bounding rectangles of the affected views). So we add the transition
   1196      * to the list and it is started just prior to starting the drawing phase of traversal.
   1197      *
   1198      * @param transition The LayoutTransition to be started on the next traversal.
   1199      *
   1200      * @hide
   1201      */
   1202     public void requestTransitionStart(LayoutTransition transition) {
   1203         if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
   1204             if (mPendingTransitions == null) {
   1205                  mPendingTransitions = new ArrayList<LayoutTransition>();
   1206             }
   1207             mPendingTransitions.add(transition);
   1208         }
   1209     }
   1210 
   1211     /**
   1212      * Notifies the HardwareRenderer that a new frame will be coming soon.
   1213      * Currently only {@link ThreadedRenderer} cares about this, and uses
   1214      * this knowledge to adjust the scheduling of off-thread animations
   1215      */
   1216     void notifyRendererOfFramePending() {
   1217         if (mAttachInfo.mHardwareRenderer != null) {
   1218             mAttachInfo.mHardwareRenderer.notifyFramePending();
   1219         }
   1220     }
   1221 
   1222     void scheduleTraversals() {
   1223         if (!mTraversalScheduled) {
   1224             mTraversalScheduled = true;
   1225             mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
   1226             mChoreographer.postCallback(
   1227                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
   1228             if (!mUnbufferedInputDispatch) {
   1229                 scheduleConsumeBatchedInput();
   1230             }
   1231             notifyRendererOfFramePending();
   1232             pokeDrawLockIfNeeded();
   1233         }
   1234     }
   1235 
   1236     void unscheduleTraversals() {
   1237         if (mTraversalScheduled) {
   1238             mTraversalScheduled = false;
   1239             mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
   1240             mChoreographer.removeCallbacks(
   1241                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
   1242         }
   1243     }
   1244 
   1245     void doTraversal() {
   1246         if (mTraversalScheduled) {
   1247             mTraversalScheduled = false;
   1248             mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
   1249 
   1250             if (mProfile) {
   1251                 Debug.startMethodTracing("ViewAncestor");
   1252             }
   1253 
   1254             performTraversals();
   1255 
   1256             if (mProfile) {
   1257                 Debug.stopMethodTracing();
   1258                 mProfile = false;
   1259             }
   1260         }
   1261     }
   1262 
   1263     private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
   1264         // Update window's global keep screen on flag: if a view has requested
   1265         // that the screen be kept on, then it is always set; otherwise, it is
   1266         // set to whatever the client last requested for the global state.
   1267         if (mAttachInfo.mKeepScreenOn) {
   1268             params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
   1269         } else {
   1270             params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
   1271                     | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
   1272         }
   1273     }
   1274 
   1275     private boolean collectViewAttributes() {
   1276         if (mAttachInfo.mRecomputeGlobalAttributes) {
   1277             //Log.i(mTag, "Computing view hierarchy attributes!");
   1278             mAttachInfo.mRecomputeGlobalAttributes = false;
   1279             boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
   1280             mAttachInfo.mKeepScreenOn = false;
   1281             mAttachInfo.mSystemUiVisibility = 0;
   1282             mAttachInfo.mHasSystemUiListeners = false;
   1283             mView.dispatchCollectViewAttributes(mAttachInfo, 0);
   1284             mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
   1285             WindowManager.LayoutParams params = mWindowAttributes;
   1286             mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
   1287             if (mAttachInfo.mKeepScreenOn != oldScreenOn
   1288                     || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
   1289                     || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
   1290                 applyKeepScreenOnFlag(params);
   1291                 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
   1292                 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
   1293                 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
   1294                 return true;
   1295             }
   1296         }
   1297         return false;
   1298     }
   1299 
   1300     private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
   1301         int vis = 0;
   1302         // Translucent decor window flags imply stable system ui visibility.
   1303         if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
   1304             vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
   1305         }
   1306         if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
   1307             vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
   1308         }
   1309         return vis;
   1310     }
   1311 
   1312     private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
   1313             final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
   1314         int childWidthMeasureSpec;
   1315         int childHeightMeasureSpec;
   1316         boolean windowSizeMayChange = false;
   1317 
   1318         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
   1319                 "Measuring " + host + " in display " + desiredWindowWidth
   1320                 + "x" + desiredWindowHeight + "...");
   1321 
   1322         boolean goodMeasure = false;
   1323         if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
   1324             // On large screens, we don't want to allow dialogs to just
   1325             // stretch to fill the entire width of the screen to display
   1326             // one line of text.  First try doing the layout at a smaller
   1327             // size to see if it will fit.
   1328             final DisplayMetrics packageMetrics = res.getDisplayMetrics();
   1329             res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
   1330             int baseSize = 0;
   1331             if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
   1332                 baseSize = (int)mTmpValue.getDimension(packageMetrics);
   1333             }
   1334             if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
   1335                     + ", desiredWindowWidth=" + desiredWindowWidth);
   1336             if (baseSize != 0 && desiredWindowWidth > baseSize) {
   1337                 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
   1338                 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
   1339                 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   1340                 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
   1341                         + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
   1342                         + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
   1343                         + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
   1344                 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
   1345                     goodMeasure = true;
   1346                 } else {
   1347                     // Didn't fit in that size... try expanding a bit.
   1348                     baseSize = (baseSize+desiredWindowWidth)/2;
   1349                     if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
   1350                             + baseSize);
   1351                     childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
   1352                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   1353                     if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
   1354                             + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
   1355                     if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
   1356                         if (DEBUG_DIALOG) Log.v(mTag, "Good!");
   1357                         goodMeasure = true;
   1358                     }
   1359                 }
   1360             }
   1361         }
   1362 
   1363         if (!goodMeasure) {
   1364             childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
   1365             childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
   1366             performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   1367             if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
   1368                 windowSizeMayChange = true;
   1369             }
   1370         }
   1371 
   1372         if (DBG) {
   1373             System.out.println("======================================");
   1374             System.out.println("performTraversals -- after measure");
   1375             host.debug();
   1376         }
   1377 
   1378         return windowSizeMayChange;
   1379     }
   1380 
   1381     /**
   1382      * Modifies the input matrix such that it maps view-local coordinates to
   1383      * on-screen coordinates.
   1384      *
   1385      * @param m input matrix to modify
   1386      */
   1387     void transformMatrixToGlobal(Matrix m) {
   1388         m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
   1389     }
   1390 
   1391     /**
   1392      * Modifies the input matrix such that it maps on-screen coordinates to
   1393      * view-local coordinates.
   1394      *
   1395      * @param m input matrix to modify
   1396      */
   1397     void transformMatrixToLocal(Matrix m) {
   1398         m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
   1399     }
   1400 
   1401     /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
   1402         if (mLastWindowInsets == null || forceConstruct) {
   1403             mDispatchContentInsets.set(mAttachInfo.mContentInsets);
   1404             mDispatchStableInsets.set(mAttachInfo.mStableInsets);
   1405             Rect contentInsets = mDispatchContentInsets;
   1406             Rect stableInsets = mDispatchStableInsets;
   1407             // For dispatch we preserve old logic, but for direct requests from Views we allow to
   1408             // immediately use pending insets.
   1409             if (!forceConstruct
   1410                     && (!mPendingContentInsets.equals(contentInsets) ||
   1411                         !mPendingStableInsets.equals(stableInsets))) {
   1412                 contentInsets = mPendingContentInsets;
   1413                 stableInsets = mPendingStableInsets;
   1414             }
   1415             Rect outsets = mAttachInfo.mOutsets;
   1416             if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
   1417                 contentInsets = new Rect(contentInsets.left + outsets.left,
   1418                         contentInsets.top + outsets.top, contentInsets.right + outsets.right,
   1419                         contentInsets.bottom + outsets.bottom);
   1420             }
   1421             mLastWindowInsets = new WindowInsets(contentInsets,
   1422                     null /* windowDecorInsets */, stableInsets,
   1423                     mContext.getResources().getConfiguration().isScreenRound(),
   1424                     mAttachInfo.mAlwaysConsumeNavBar);
   1425         }
   1426         return mLastWindowInsets;
   1427     }
   1428 
   1429     void dispatchApplyInsets(View host) {
   1430         host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */));
   1431     }
   1432 
   1433     private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
   1434         return lp.type == TYPE_STATUS_BAR_PANEL
   1435                 || lp.type == TYPE_INPUT_METHOD
   1436                 || lp.type == TYPE_VOLUME_OVERLAY;
   1437     }
   1438 
   1439     private int dipToPx(int dip) {
   1440         final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
   1441         return (int) (displayMetrics.density * dip + 0.5f);
   1442     }
   1443 
   1444     private void performTraversals() {
   1445         // cache mView since it is used so much below...
   1446         final View host = mView;
   1447 
   1448         if (DBG) {
   1449             System.out.println("======================================");
   1450             System.out.println("performTraversals");
   1451             host.debug();
   1452         }
   1453 
   1454         if (host == null || !mAdded)
   1455             return;
   1456 
   1457         mIsInTraversal = true;
   1458         mWillDrawSoon = true;
   1459         boolean windowSizeMayChange = false;
   1460         boolean newSurface = false;
   1461         boolean surfaceChanged = false;
   1462         WindowManager.LayoutParams lp = mWindowAttributes;
   1463 
   1464         int desiredWindowWidth;
   1465         int desiredWindowHeight;
   1466 
   1467         final int viewVisibility = getHostVisibility();
   1468         final boolean viewVisibilityChanged = !mFirst
   1469                 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded);
   1470         final boolean viewUserVisibilityChanged = !mFirst &&
   1471                 ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
   1472 
   1473         WindowManager.LayoutParams params = null;
   1474         if (mWindowAttributesChanged) {
   1475             mWindowAttributesChanged = false;
   1476             surfaceChanged = true;
   1477             params = lp;
   1478         }
   1479         CompatibilityInfo compatibilityInfo =
   1480                 mDisplay.getDisplayAdjustments().getCompatibilityInfo();
   1481         if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
   1482             params = lp;
   1483             mFullRedrawNeeded = true;
   1484             mLayoutRequested = true;
   1485             if (mLastInCompatMode) {
   1486                 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
   1487                 mLastInCompatMode = false;
   1488             } else {
   1489                 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
   1490                 mLastInCompatMode = true;
   1491             }
   1492         }
   1493 
   1494         mWindowAttributesChangesFlag = 0;
   1495 
   1496         Rect frame = mWinFrame;
   1497         if (mFirst) {
   1498             mFullRedrawNeeded = true;
   1499             mLayoutRequested = true;
   1500 
   1501             if (shouldUseDisplaySize(lp)) {
   1502                 // NOTE -- system code, won't try to do compat mode.
   1503                 Point size = new Point();
   1504                 mDisplay.getRealSize(size);
   1505                 desiredWindowWidth = size.x;
   1506                 desiredWindowHeight = size.y;
   1507             } else {
   1508                 Configuration config = mContext.getResources().getConfiguration();
   1509                 desiredWindowWidth = dipToPx(config.screenWidthDp);
   1510                 desiredWindowHeight = dipToPx(config.screenHeightDp);
   1511             }
   1512 
   1513             // We used to use the following condition to choose 32 bits drawing caches:
   1514             // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
   1515             // However, windows are now always 32 bits by default, so choose 32 bits
   1516             mAttachInfo.mUse32BitDrawingCache = true;
   1517             mAttachInfo.mHasWindowFocus = false;
   1518             mAttachInfo.mWindowVisibility = viewVisibility;
   1519             mAttachInfo.mRecomputeGlobalAttributes = false;
   1520             mLastConfiguration.setTo(host.getResources().getConfiguration());
   1521             mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
   1522             // Set the layout direction if it has not been set before (inherit is the default)
   1523             if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
   1524                 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
   1525             }
   1526             host.dispatchAttachedToWindow(mAttachInfo, 0);
   1527             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
   1528             dispatchApplyInsets(host);
   1529             //Log.i(mTag, "Screen on initialized: " + attachInfo.mKeepScreenOn);
   1530 
   1531         } else {
   1532             desiredWindowWidth = frame.width();
   1533             desiredWindowHeight = frame.height();
   1534             if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
   1535                 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
   1536                 mFullRedrawNeeded = true;
   1537                 mLayoutRequested = true;
   1538                 windowSizeMayChange = true;
   1539             }
   1540         }
   1541 
   1542         if (viewVisibilityChanged) {
   1543             mAttachInfo.mWindowVisibility = viewVisibility;
   1544             host.dispatchWindowVisibilityChanged(viewVisibility);
   1545             if (viewUserVisibilityChanged) {
   1546                 host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
   1547             }
   1548             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
   1549                 endDragResizing();
   1550                 destroyHardwareResources();
   1551             }
   1552             if (viewVisibility == View.GONE) {
   1553                 // After making a window gone, we will count it as being
   1554                 // shown for the first time the next time it gets focus.
   1555                 mHasHadWindowFocus = false;
   1556             }
   1557         }
   1558 
   1559         // Non-visible windows can't hold accessibility focus.
   1560         if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
   1561             host.clearAccessibilityFocus();
   1562         }
   1563 
   1564         // Execute enqueued actions on every traversal in case a detached view enqueued an action
   1565         getRunQueue().executeActions(mAttachInfo.mHandler);
   1566 
   1567         boolean insetsChanged = false;
   1568 
   1569         boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
   1570         if (layoutRequested) {
   1571 
   1572             final Resources res = mView.getContext().getResources();
   1573 
   1574             if (mFirst) {
   1575                 // make sure touch mode code executes by setting cached value
   1576                 // to opposite of the added touch mode.
   1577                 mAttachInfo.mInTouchMode = !mAddedTouchMode;
   1578                 ensureTouchModeLocally(mAddedTouchMode);
   1579             } else {
   1580                 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
   1581                     insetsChanged = true;
   1582                 }
   1583                 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
   1584                     insetsChanged = true;
   1585                 }
   1586                 if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
   1587                     insetsChanged = true;
   1588                 }
   1589                 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
   1590                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
   1591                     if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
   1592                             + mAttachInfo.mVisibleInsets);
   1593                 }
   1594                 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
   1595                     insetsChanged = true;
   1596                 }
   1597                 if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) {
   1598                     insetsChanged = true;
   1599                 }
   1600                 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
   1601                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
   1602                     windowSizeMayChange = true;
   1603 
   1604                     if (shouldUseDisplaySize(lp)) {
   1605                         // NOTE -- system code, won't try to do compat mode.
   1606                         Point size = new Point();
   1607                         mDisplay.getRealSize(size);
   1608                         desiredWindowWidth = size.x;
   1609                         desiredWindowHeight = size.y;
   1610                     } else {
   1611                         Configuration config = res.getConfiguration();
   1612                         desiredWindowWidth = dipToPx(config.screenWidthDp);
   1613                         desiredWindowHeight = dipToPx(config.screenHeightDp);
   1614                     }
   1615                 }
   1616             }
   1617 
   1618             // Ask host how big it wants to be
   1619             windowSizeMayChange |= measureHierarchy(host, lp, res,
   1620                     desiredWindowWidth, desiredWindowHeight);
   1621         }
   1622 
   1623         if (collectViewAttributes()) {
   1624             params = lp;
   1625         }
   1626         if (mAttachInfo.mForceReportNewAttributes) {
   1627             mAttachInfo.mForceReportNewAttributes = false;
   1628             params = lp;
   1629         }
   1630 
   1631         if (mFirst || mAttachInfo.mViewVisibilityChanged) {
   1632             mAttachInfo.mViewVisibilityChanged = false;
   1633             int resizeMode = mSoftInputMode &
   1634                     WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
   1635             // If we are in auto resize mode, then we need to determine
   1636             // what mode to use now.
   1637             if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
   1638                 final int N = mAttachInfo.mScrollContainers.size();
   1639                 for (int i=0; i<N; i++) {
   1640                     if (mAttachInfo.mScrollContainers.get(i).isShown()) {
   1641                         resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
   1642                     }
   1643                 }
   1644                 if (resizeMode == 0) {
   1645                     resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
   1646                 }
   1647                 if ((lp.softInputMode &
   1648                         WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
   1649                     lp.softInputMode = (lp.softInputMode &
   1650                             ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
   1651                             resizeMode;
   1652                     params = lp;
   1653                 }
   1654             }
   1655         }
   1656 
   1657         if (params != null) {
   1658             if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
   1659                 if (!PixelFormat.formatHasAlpha(params.format)) {
   1660                     params.format = PixelFormat.TRANSLUCENT;
   1661                 }
   1662             }
   1663             mAttachInfo.mOverscanRequested = (params.flags
   1664                     & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
   1665         }
   1666 
   1667         if (mApplyInsetsRequested) {
   1668             mApplyInsetsRequested = false;
   1669             mLastOverscanRequested = mAttachInfo.mOverscanRequested;
   1670             dispatchApplyInsets(host);
   1671             if (mLayoutRequested) {
   1672                 // Short-circuit catching a new layout request here, so
   1673                 // we don't need to go through two layout passes when things
   1674                 // change due to fitting system windows, which can happen a lot.
   1675                 windowSizeMayChange |= measureHierarchy(host, lp,
   1676                         mView.getContext().getResources(),
   1677                         desiredWindowWidth, desiredWindowHeight);
   1678             }
   1679         }
   1680 
   1681         if (layoutRequested) {
   1682             // Clear this now, so that if anything requests a layout in the
   1683             // rest of this function we will catch it and re-run a full
   1684             // layout pass.
   1685             mLayoutRequested = false;
   1686         }
   1687 
   1688         boolean windowShouldResize = layoutRequested && windowSizeMayChange
   1689             && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
   1690                 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
   1691                         frame.width() < desiredWindowWidth && frame.width() != mWidth)
   1692                 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
   1693                         frame.height() < desiredWindowHeight && frame.height() != mHeight));
   1694         windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
   1695 
   1696         // If the activity was just relaunched, it might have unfrozen the task bounds (while
   1697         // relaunching), so we need to force a call into window manager to pick up the latest
   1698         // bounds.
   1699         windowShouldResize |= mActivityRelaunched;
   1700 
   1701         // Determine whether to compute insets.
   1702         // If there are no inset listeners remaining then we may still need to compute
   1703         // insets in case the old insets were non-empty and must be reset.
   1704         final boolean computesInternalInsets =
   1705                 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
   1706                 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
   1707 
   1708         boolean insetsPending = false;
   1709         int relayoutResult = 0;
   1710         boolean updatedConfiguration = false;
   1711 
   1712         final int surfaceGenerationId = mSurface.getGenerationId();
   1713 
   1714         final boolean isViewVisible = viewVisibility == View.VISIBLE;
   1715         if (mFirst || windowShouldResize || insetsChanged ||
   1716                 viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
   1717             mForceNextWindowRelayout = false;
   1718 
   1719             if (isViewVisible) {
   1720                 // If this window is giving internal insets to the window
   1721                 // manager, and it is being added or changing its visibility,
   1722                 // then we want to first give the window manager "fake"
   1723                 // insets to cause it to effectively ignore the content of
   1724                 // the window during layout.  This avoids it briefly causing
   1725                 // other windows to resize/move based on the raw frame of the
   1726                 // window, waiting until we can finish laying out this window
   1727                 // and get back to the window manager with the ultimately
   1728                 // computed insets.
   1729                 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
   1730             }
   1731 
   1732             if (mSurfaceHolder != null) {
   1733                 mSurfaceHolder.mSurfaceLock.lock();
   1734                 mDrawingAllowed = true;
   1735             }
   1736 
   1737             boolean hwInitialized = false;
   1738             boolean contentInsetsChanged = false;
   1739             boolean hadSurface = mSurface.isValid();
   1740 
   1741             try {
   1742                 if (DEBUG_LAYOUT) {
   1743                     Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
   1744                             host.getMeasuredHeight() + ", params=" + params);
   1745                 }
   1746 
   1747                 if (mAttachInfo.mHardwareRenderer != null) {
   1748                     // relayoutWindow may decide to destroy mSurface. As that decision
   1749                     // happens in WindowManager service, we need to be defensive here
   1750                     // and stop using the surface in case it gets destroyed.
   1751                     if (mAttachInfo.mHardwareRenderer.pauseSurface(mSurface)) {
   1752                         // Animations were running so we need to push a frame
   1753                         // to resume them
   1754                         mDirty.set(0, 0, mWidth, mHeight);
   1755                     }
   1756                     mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
   1757                 }
   1758                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
   1759 
   1760                 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
   1761                         + " overscan=" + mPendingOverscanInsets.toShortString()
   1762                         + " content=" + mPendingContentInsets.toShortString()
   1763                         + " visible=" + mPendingVisibleInsets.toShortString()
   1764                         + " visible=" + mPendingStableInsets.toShortString()
   1765                         + " outsets=" + mPendingOutsets.toShortString()
   1766                         + " surface=" + mSurface);
   1767 
   1768                 if (mPendingConfiguration.seq != 0) {
   1769                     if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
   1770                             + mPendingConfiguration);
   1771                     updateConfiguration(new Configuration(mPendingConfiguration), !mFirst);
   1772                     mPendingConfiguration.seq = 0;
   1773                     updatedConfiguration = true;
   1774                 }
   1775 
   1776                 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
   1777                         mAttachInfo.mOverscanInsets);
   1778                 contentInsetsChanged = !mPendingContentInsets.equals(
   1779                         mAttachInfo.mContentInsets);
   1780                 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
   1781                         mAttachInfo.mVisibleInsets);
   1782                 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
   1783                         mAttachInfo.mStableInsets);
   1784                 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
   1785                 final boolean surfaceSizeChanged = (relayoutResult
   1786                         & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
   1787                 final boolean alwaysConsumeNavBarChanged =
   1788                         mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar;
   1789                 if (contentInsetsChanged) {
   1790                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
   1791                     if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
   1792                             + mAttachInfo.mContentInsets);
   1793                 }
   1794                 if (overscanInsetsChanged) {
   1795                     mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
   1796                     if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
   1797                             + mAttachInfo.mOverscanInsets);
   1798                     // Need to relayout with content insets.
   1799                     contentInsetsChanged = true;
   1800                 }
   1801                 if (stableInsetsChanged) {
   1802                     mAttachInfo.mStableInsets.set(mPendingStableInsets);
   1803                     if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
   1804                             + mAttachInfo.mStableInsets);
   1805                     // Need to relayout with content insets.
   1806                     contentInsetsChanged = true;
   1807                 }
   1808                 if (alwaysConsumeNavBarChanged) {
   1809                     mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
   1810                     contentInsetsChanged = true;
   1811                 }
   1812                 if (contentInsetsChanged || mLastSystemUiVisibility !=
   1813                         mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
   1814                         || mLastOverscanRequested != mAttachInfo.mOverscanRequested
   1815                         || outsetsChanged) {
   1816                     mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
   1817                     mLastOverscanRequested = mAttachInfo.mOverscanRequested;
   1818                     mAttachInfo.mOutsets.set(mPendingOutsets);
   1819                     mApplyInsetsRequested = false;
   1820                     dispatchApplyInsets(host);
   1821                 }
   1822                 if (visibleInsetsChanged) {
   1823                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
   1824                     if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
   1825                             + mAttachInfo.mVisibleInsets);
   1826                 }
   1827 
   1828                 if (!hadSurface) {
   1829                     if (mSurface.isValid()) {
   1830                         // If we are creating a new surface, then we need to
   1831                         // completely redraw it.  Also, when we get to the
   1832                         // point of drawing it we will hold off and schedule
   1833                         // a new traversal instead.  This is so we can tell the
   1834                         // window manager about all of the windows being displayed
   1835                         // before actually drawing them, so it can display then
   1836                         // all at once.
   1837                         newSurface = true;
   1838                         mFullRedrawNeeded = true;
   1839                         mPreviousTransparentRegion.setEmpty();
   1840 
   1841                         // Only initialize up-front if transparent regions are not
   1842                         // requested, otherwise defer to see if the entire window
   1843                         // will be transparent
   1844                         if (mAttachInfo.mHardwareRenderer != null) {
   1845                             try {
   1846                                 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
   1847                                         mSurface);
   1848                                 if (hwInitialized && (host.mPrivateFlags
   1849                                         & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
   1850                                     // Don't pre-allocate if transparent regions
   1851                                     // are requested as they may not be needed
   1852                                     mSurface.allocateBuffers();
   1853                                 }
   1854                             } catch (OutOfResourcesException e) {
   1855                                 handleOutOfResourcesException(e);
   1856                                 return;
   1857                             }
   1858                         }
   1859                     }
   1860                 } else if (!mSurface.isValid()) {
   1861                     // If the surface has been removed, then reset the scroll
   1862                     // positions.
   1863                     if (mLastScrolledFocus != null) {
   1864                         mLastScrolledFocus.clear();
   1865                     }
   1866                     mScrollY = mCurScrollY = 0;
   1867                     if (mView instanceof RootViewSurfaceTaker) {
   1868                         ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
   1869                     }
   1870                     if (mScroller != null) {
   1871                         mScroller.abortAnimation();
   1872                     }
   1873                     // Our surface is gone
   1874                     if (mAttachInfo.mHardwareRenderer != null &&
   1875                             mAttachInfo.mHardwareRenderer.isEnabled()) {
   1876                         mAttachInfo.mHardwareRenderer.destroy();
   1877                     }
   1878                 } else if ((surfaceGenerationId != mSurface.getGenerationId()
   1879                         || surfaceSizeChanged)
   1880                         && mSurfaceHolder == null
   1881                         && mAttachInfo.mHardwareRenderer != null) {
   1882                     mFullRedrawNeeded = true;
   1883                     try {
   1884                         // Need to do updateSurface (which leads to CanvasContext::setSurface and
   1885                         // re-create the EGLSurface) if either the Surface changed (as indicated by
   1886                         // generation id), or WindowManager changed the surface size. The latter is
   1887                         // because on some chips, changing the consumer side's BufferQueue size may
   1888                         // not take effect immediately unless we create a new EGLSurface.
   1889                         // Note that frame size change doesn't always imply surface size change (eg.
   1890                         // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
   1891                         // flag from WindowManager.
   1892                         mAttachInfo.mHardwareRenderer.updateSurface(mSurface);
   1893                     } catch (OutOfResourcesException e) {
   1894                         handleOutOfResourcesException(e);
   1895                         return;
   1896                     }
   1897                 }
   1898 
   1899                 final boolean freeformResizing = (relayoutResult
   1900                         & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
   1901                 final boolean dockedResizing = (relayoutResult
   1902                         & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0;
   1903                 final boolean dragResizing = freeformResizing || dockedResizing;
   1904                 if (mDragResizing != dragResizing) {
   1905                     if (dragResizing) {
   1906                         mResizeMode = freeformResizing
   1907                                 ? RESIZE_MODE_FREEFORM
   1908                                 : RESIZE_MODE_DOCKED_DIVIDER;
   1909                         startDragResizing(mPendingBackDropFrame,
   1910                                 mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
   1911                                 mPendingStableInsets, mResizeMode);
   1912                     } else {
   1913                         // We shouldn't come here, but if we come we should end the resize.
   1914                         endDragResizing();
   1915                     }
   1916                 }
   1917                 if (!USE_MT_RENDERER) {
   1918                     if (dragResizing) {
   1919                         mCanvasOffsetX = mWinFrame.left;
   1920                         mCanvasOffsetY = mWinFrame.top;
   1921                     } else {
   1922                         mCanvasOffsetX = mCanvasOffsetY = 0;
   1923                     }
   1924                 }
   1925             } catch (RemoteException e) {
   1926             }
   1927 
   1928             if (DEBUG_ORIENTATION) Log.v(
   1929                     TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
   1930 
   1931             mAttachInfo.mWindowLeft = frame.left;
   1932             mAttachInfo.mWindowTop = frame.top;
   1933 
   1934             // !!FIXME!! This next section handles the case where we did not get the
   1935             // window size we asked for. We should avoid this by getting a maximum size from
   1936             // the window session beforehand.
   1937             if (mWidth != frame.width() || mHeight != frame.height()) {
   1938                 mWidth = frame.width();
   1939                 mHeight = frame.height();
   1940             }
   1941 
   1942             if (mSurfaceHolder != null) {
   1943                 // The app owns the surface; tell it about what is going on.
   1944                 if (mSurface.isValid()) {
   1945                     // XXX .copyFrom() doesn't work!
   1946                     //mSurfaceHolder.mSurface.copyFrom(mSurface);
   1947                     mSurfaceHolder.mSurface = mSurface;
   1948                 }
   1949                 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
   1950                 mSurfaceHolder.mSurfaceLock.unlock();
   1951                 if (mSurface.isValid()) {
   1952                     if (!hadSurface) {
   1953                         mSurfaceHolder.ungetCallbacks();
   1954 
   1955                         mIsCreating = true;
   1956                         mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
   1957                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   1958                         if (callbacks != null) {
   1959                             for (SurfaceHolder.Callback c : callbacks) {
   1960                                 c.surfaceCreated(mSurfaceHolder);
   1961                             }
   1962                         }
   1963                         surfaceChanged = true;
   1964                     }
   1965                     if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
   1966                         mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
   1967                                 lp.format, mWidth, mHeight);
   1968                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   1969                         if (callbacks != null) {
   1970                             for (SurfaceHolder.Callback c : callbacks) {
   1971                                 c.surfaceChanged(mSurfaceHolder, lp.format,
   1972                                         mWidth, mHeight);
   1973                             }
   1974                         }
   1975                     }
   1976                     mIsCreating = false;
   1977                 } else if (hadSurface) {
   1978                     mSurfaceHolder.ungetCallbacks();
   1979                     SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   1980                     mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
   1981                     if (callbacks != null) {
   1982                         for (SurfaceHolder.Callback c : callbacks) {
   1983                             c.surfaceDestroyed(mSurfaceHolder);
   1984                         }
   1985                     }
   1986                     mSurfaceHolder.mSurfaceLock.lock();
   1987                     try {
   1988                         mSurfaceHolder.mSurface = new Surface();
   1989                     } finally {
   1990                         mSurfaceHolder.mSurfaceLock.unlock();
   1991                     }
   1992                 }
   1993             }
   1994 
   1995             final ThreadedRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
   1996             if (hardwareRenderer != null && hardwareRenderer.isEnabled()) {
   1997                 if (hwInitialized
   1998                         || mWidth != hardwareRenderer.getWidth()
   1999                         || mHeight != hardwareRenderer.getHeight()
   2000                         || mNeedsHwRendererSetup) {
   2001                     hardwareRenderer.setup(mWidth, mHeight, mAttachInfo,
   2002                             mWindowAttributes.surfaceInsets);
   2003                     mNeedsHwRendererSetup = false;
   2004                 }
   2005             }
   2006 
   2007             if (!mStopped || mReportNextDraw) {
   2008                 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
   2009                         (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
   2010                 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
   2011                         || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
   2012                         updatedConfiguration) {
   2013                     int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
   2014                     int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
   2015 
   2016                     if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed!  mWidth="
   2017                             + mWidth + " measuredWidth=" + host.getMeasuredWidth()
   2018                             + " mHeight=" + mHeight
   2019                             + " measuredHeight=" + host.getMeasuredHeight()
   2020                             + " coveredInsetsChanged=" + contentInsetsChanged);
   2021 
   2022                      // Ask host how big it wants to be
   2023                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   2024 
   2025                     // Implementation of weights from WindowManager.LayoutParams
   2026                     // We just grow the dimensions as needed and re-measure if
   2027                     // needs be
   2028                     int width = host.getMeasuredWidth();
   2029                     int height = host.getMeasuredHeight();
   2030                     boolean measureAgain = false;
   2031 
   2032                     if (lp.horizontalWeight > 0.0f) {
   2033                         width += (int) ((mWidth - width) * lp.horizontalWeight);
   2034                         childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
   2035                                 MeasureSpec.EXACTLY);
   2036                         measureAgain = true;
   2037                     }
   2038                     if (lp.verticalWeight > 0.0f) {
   2039                         height += (int) ((mHeight - height) * lp.verticalWeight);
   2040                         childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
   2041                                 MeasureSpec.EXACTLY);
   2042                         measureAgain = true;
   2043                     }
   2044 
   2045                     if (measureAgain) {
   2046                         if (DEBUG_LAYOUT) Log.v(mTag,
   2047                                 "And hey let's measure once more: width=" + width
   2048                                 + " height=" + height);
   2049                         performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   2050                     }
   2051 
   2052                     layoutRequested = true;
   2053                 }
   2054             }
   2055         } else {
   2056             // Not the first pass and no window/insets/visibility change but the window
   2057             // may have moved and we need check that and if so to update the left and right
   2058             // in the attach info. We translate only the window frame since on window move
   2059             // the window manager tells us only for the new frame but the insets are the
   2060             // same and we do not want to translate them more than once.
   2061             maybeHandleWindowMove(frame);
   2062         }
   2063 
   2064         final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
   2065         boolean triggerGlobalLayoutListener = didLayout
   2066                 || mAttachInfo.mRecomputeGlobalAttributes;
   2067         if (didLayout) {
   2068             performLayout(lp, mWidth, mHeight);
   2069 
   2070             // By this point all views have been sized and positioned
   2071             // We can compute the transparent area
   2072 
   2073             if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
   2074                 // start out transparent
   2075                 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
   2076                 host.getLocationInWindow(mTmpLocation);
   2077                 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
   2078                         mTmpLocation[0] + host.mRight - host.mLeft,
   2079                         mTmpLocation[1] + host.mBottom - host.mTop);
   2080 
   2081                 host.gatherTransparentRegion(mTransparentRegion);
   2082                 if (mTranslator != null) {
   2083                     mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
   2084                 }
   2085 
   2086                 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
   2087                     mPreviousTransparentRegion.set(mTransparentRegion);
   2088                     mFullRedrawNeeded = true;
   2089                     // reconfigure window manager
   2090                     try {
   2091                         mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
   2092                     } catch (RemoteException e) {
   2093                     }
   2094                 }
   2095             }
   2096 
   2097             if (DBG) {
   2098                 System.out.println("======================================");
   2099                 System.out.println("performTraversals -- after setFrame");
   2100                 host.debug();
   2101             }
   2102         }
   2103 
   2104         if (triggerGlobalLayoutListener) {
   2105             mAttachInfo.mRecomputeGlobalAttributes = false;
   2106             mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
   2107         }
   2108 
   2109         if (computesInternalInsets) {
   2110             // Clear the original insets.
   2111             final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
   2112             insets.reset();
   2113 
   2114             // Compute new insets in place.
   2115             mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
   2116             mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
   2117 
   2118             // Tell the window manager.
   2119             if (insetsPending || !mLastGivenInsets.equals(insets)) {
   2120                 mLastGivenInsets.set(insets);
   2121 
   2122                 // Translate insets to screen coordinates if needed.
   2123                 final Rect contentInsets;
   2124                 final Rect visibleInsets;
   2125                 final Region touchableRegion;
   2126                 if (mTranslator != null) {
   2127                     contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
   2128                     visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
   2129                     touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
   2130                 } else {
   2131                     contentInsets = insets.contentInsets;
   2132                     visibleInsets = insets.visibleInsets;
   2133                     touchableRegion = insets.touchableRegion;
   2134                 }
   2135 
   2136                 try {
   2137                     mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
   2138                             contentInsets, visibleInsets, touchableRegion);
   2139                 } catch (RemoteException e) {
   2140                 }
   2141             }
   2142         }
   2143 
   2144         if (mFirst) {
   2145             // handle first focus request
   2146             if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: mView.hasFocus()="
   2147                     + mView.hasFocus());
   2148             if (mView != null) {
   2149                 if (!mView.hasFocus()) {
   2150                     mView.requestFocus(View.FOCUS_FORWARD);
   2151                     if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: requested focused view="
   2152                             + mView.findFocus());
   2153                 } else {
   2154                     if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: existing focused view="
   2155                             + mView.findFocus());
   2156                 }
   2157             }
   2158         }
   2159 
   2160         final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
   2161         final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
   2162         final boolean regainedFocus = hasWindowFocus && mLostWindowFocus;
   2163         if (regainedFocus) {
   2164             mLostWindowFocus = false;
   2165         } else if (!hasWindowFocus && mHadWindowFocus) {
   2166             mLostWindowFocus = true;
   2167         }
   2168 
   2169         if (changedVisibility || regainedFocus) {
   2170             host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
   2171         }
   2172 
   2173         mFirst = false;
   2174         mWillDrawSoon = false;
   2175         mNewSurfaceNeeded = false;
   2176         mActivityRelaunched = false;
   2177         mViewVisibility = viewVisibility;
   2178         mHadWindowFocus = hasWindowFocus;
   2179 
   2180         if (hasWindowFocus && !isInLocalFocusMode()) {
   2181             final boolean imTarget = WindowManager.LayoutParams
   2182                     .mayUseInputMethod(mWindowAttributes.flags);
   2183             if (imTarget != mLastWasImTarget) {
   2184                 mLastWasImTarget = imTarget;
   2185                 InputMethodManager imm = InputMethodManager.peekInstance();
   2186                 if (imm != null && imTarget) {
   2187                     imm.onPreWindowFocus(mView, hasWindowFocus);
   2188                     imm.onPostWindowFocus(mView, mView.findFocus(),
   2189                             mWindowAttributes.softInputMode,
   2190                             !mHasHadWindowFocus, mWindowAttributes.flags);
   2191                 }
   2192             }
   2193         }
   2194 
   2195         // Remember if we must report the next draw.
   2196         if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
   2197             mReportNextDraw = true;
   2198         }
   2199 
   2200         boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
   2201 
   2202         if (!cancelDraw && !newSurface) {
   2203             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
   2204                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
   2205                     mPendingTransitions.get(i).startChangingAnimations();
   2206                 }
   2207                 mPendingTransitions.clear();
   2208             }
   2209 
   2210             performDraw();
   2211         } else {
   2212             if (isViewVisible) {
   2213                 // Try again
   2214                 scheduleTraversals();
   2215             } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
   2216                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
   2217                     mPendingTransitions.get(i).endChangingAnimations();
   2218                 }
   2219                 mPendingTransitions.clear();
   2220             }
   2221         }
   2222 
   2223         mIsInTraversal = false;
   2224     }
   2225 
   2226     private void maybeHandleWindowMove(Rect frame) {
   2227 
   2228         // TODO: Well, we are checking whether the frame has changed similarly
   2229         // to how this is done for the insets. This is however incorrect since
   2230         // the insets and the frame are translated. For example, the old frame
   2231         // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
   2232         // reported frame is (2, 2 - 2, 2) which implies no change but this is not
   2233         // true since we are comparing a not translated value to a translated one.
   2234         // This scenario is rare but we may want to fix that.
   2235 
   2236         final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left
   2237                 || mAttachInfo.mWindowTop != frame.top;
   2238         if (windowMoved) {
   2239             if (mTranslator != null) {
   2240                 mTranslator.translateRectInScreenToAppWinFrame(frame);
   2241             }
   2242             mAttachInfo.mWindowLeft = frame.left;
   2243             mAttachInfo.mWindowTop = frame.top;
   2244         }
   2245         if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) {
   2246             // Update the light position for the new offsets.
   2247             if (mAttachInfo.mHardwareRenderer != null) {
   2248                 mAttachInfo.mHardwareRenderer.setLightCenter(mAttachInfo);
   2249             }
   2250             mAttachInfo.mNeedsUpdateLightCenter = false;
   2251         }
   2252     }
   2253 
   2254     private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
   2255         Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
   2256         try {
   2257             if (!mWindowSession.outOfMemory(mWindow) &&
   2258                     Process.myUid() != Process.SYSTEM_UID) {
   2259                 Slog.w(mTag, "No processes killed for memory; killing self");
   2260                 Process.killProcess(Process.myPid());
   2261             }
   2262         } catch (RemoteException ex) {
   2263         }
   2264         mLayoutRequested = true;    // ask wm for a new surface next time.
   2265     }
   2266 
   2267     private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
   2268         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
   2269         try {
   2270             mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   2271         } finally {
   2272             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   2273         }
   2274     }
   2275 
   2276     /**
   2277      * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
   2278      * is currently undergoing a layout pass.
   2279      *
   2280      * @return whether the view hierarchy is currently undergoing a layout pass
   2281      */
   2282     boolean isInLayout() {
   2283         return mInLayout;
   2284     }
   2285 
   2286     /**
   2287      * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
   2288      * undergoing a layout pass. requestLayout() should not generally be called during layout,
   2289      * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
   2290      * all children in that container hierarchy are measured and laid out at the end of the layout
   2291      * pass for that container). If requestLayout() is called anyway, we handle it correctly
   2292      * by registering all requesters during a frame as it proceeds. At the end of the frame,
   2293      * we check all of those views to see if any still have pending layout requests, which
   2294      * indicates that they were not correctly handled by their container hierarchy. If that is
   2295      * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
   2296      * to blank containers, and force a second request/measure/layout pass in this frame. If
   2297      * more requestLayout() calls are received during that second layout pass, we post those
   2298      * requests to the next frame to avoid possible infinite loops.
   2299      *
   2300      * <p>The return value from this method indicates whether the request should proceed
   2301      * (if it is a request during the first layout pass) or should be skipped and posted to the
   2302      * next frame (if it is a request during the second layout pass).</p>
   2303      *
   2304      * @param view the view that requested the layout.
   2305      *
   2306      * @return true if request should proceed, false otherwise.
   2307      */
   2308     boolean requestLayoutDuringLayout(final View view) {
   2309         if (view.mParent == null || view.mAttachInfo == null) {
   2310             // Would not normally trigger another layout, so just let it pass through as usual
   2311             return true;
   2312         }
   2313         if (!mLayoutRequesters.contains(view)) {
   2314             mLayoutRequesters.add(view);
   2315         }
   2316         if (!mHandlingLayoutInLayoutRequest) {
   2317             // Let the request proceed normally; it will be processed in a second layout pass
   2318             // if necessary
   2319             return true;
   2320         } else {
   2321             // Don't let the request proceed during the second layout pass.
   2322             // It will post to the next frame instead.
   2323             return false;
   2324         }
   2325     }
   2326 
   2327     private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
   2328             int desiredWindowHeight) {
   2329         mLayoutRequested = false;
   2330         mScrollMayChange = true;
   2331         mInLayout = true;
   2332 
   2333         final View host = mView;
   2334         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
   2335             Log.v(mTag, "Laying out " + host + " to (" +
   2336                     host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
   2337         }
   2338 
   2339         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
   2340         try {
   2341             host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
   2342 
   2343             mInLayout = false;
   2344             int numViewsRequestingLayout = mLayoutRequesters.size();
   2345             if (numViewsRequestingLayout > 0) {
   2346                 // requestLayout() was called during layout.
   2347                 // If no layout-request flags are set on the requesting views, there is no problem.
   2348                 // If some requests are still pending, then we need to clear those flags and do
   2349                 // a full request/measure/layout pass to handle this situation.
   2350                 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
   2351                         false);
   2352                 if (validLayoutRequesters != null) {
   2353                     // Set this flag to indicate that any further requests are happening during
   2354                     // the second pass, which may result in posting those requests to the next
   2355                     // frame instead
   2356                     mHandlingLayoutInLayoutRequest = true;
   2357 
   2358                     // Process fresh layout requests, then measure and layout
   2359                     int numValidRequests = validLayoutRequesters.size();
   2360                     for (int i = 0; i < numValidRequests; ++i) {
   2361                         final View view = validLayoutRequesters.get(i);
   2362                         Log.w("View", "requestLayout() improperly called by " + view +
   2363                                 " during layout: running second layout pass");
   2364                         view.requestLayout();
   2365                     }
   2366                     measureHierarchy(host, lp, mView.getContext().getResources(),
   2367                             desiredWindowWidth, desiredWindowHeight);
   2368                     mInLayout = true;
   2369                     host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
   2370 
   2371                     mHandlingLayoutInLayoutRequest = false;
   2372 
   2373                     // Check the valid requests again, this time without checking/clearing the
   2374                     // layout flags, since requests happening during the second pass get noop'd
   2375                     validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
   2376                     if (validLayoutRequesters != null) {
   2377                         final ArrayList<View> finalRequesters = validLayoutRequesters;
   2378                         // Post second-pass requests to the next frame
   2379                         getRunQueue().post(new Runnable() {
   2380                             @Override
   2381                             public void run() {
   2382                                 int numValidRequests = finalRequesters.size();
   2383                                 for (int i = 0; i < numValidRequests; ++i) {
   2384                                     final View view = finalRequesters.get(i);
   2385                                     Log.w("View", "requestLayout() improperly called by " + view +
   2386                                             " during second layout pass: posting in next frame");
   2387                                     view.requestLayout();
   2388                                 }
   2389                             }
   2390                         });
   2391                     }
   2392                 }
   2393 
   2394             }
   2395         } finally {
   2396             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   2397         }
   2398         mInLayout = false;
   2399     }
   2400 
   2401     /**
   2402      * This method is called during layout when there have been calls to requestLayout() during
   2403      * layout. It walks through the list of views that requested layout to determine which ones
   2404      * still need it, based on visibility in the hierarchy and whether they have already been
   2405      * handled (as is usually the case with ListView children).
   2406      *
   2407      * @param layoutRequesters The list of views that requested layout during layout
   2408      * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
   2409      * If so, the FORCE_LAYOUT flag was not set on requesters.
   2410      * @return A list of the actual views that still need to be laid out.
   2411      */
   2412     private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
   2413             boolean secondLayoutRequests) {
   2414 
   2415         int numViewsRequestingLayout = layoutRequesters.size();
   2416         ArrayList<View> validLayoutRequesters = null;
   2417         for (int i = 0; i < numViewsRequestingLayout; ++i) {
   2418             View view = layoutRequesters.get(i);
   2419             if (view != null && view.mAttachInfo != null && view.mParent != null &&
   2420                     (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
   2421                             View.PFLAG_FORCE_LAYOUT)) {
   2422                 boolean gone = false;
   2423                 View parent = view;
   2424                 // Only trigger new requests for views in a non-GONE hierarchy
   2425                 while (parent != null) {
   2426                     if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
   2427                         gone = true;
   2428                         break;
   2429                     }
   2430                     if (parent.mParent instanceof View) {
   2431                         parent = (View) parent.mParent;
   2432                     } else {
   2433                         parent = null;
   2434                     }
   2435                 }
   2436                 if (!gone) {
   2437                     if (validLayoutRequesters == null) {
   2438                         validLayoutRequesters = new ArrayList<View>();
   2439                     }
   2440                     validLayoutRequesters.add(view);
   2441                 }
   2442             }
   2443         }
   2444         if (!secondLayoutRequests) {
   2445             // If we're checking the layout flags, then we need to clean them up also
   2446             for (int i = 0; i < numViewsRequestingLayout; ++i) {
   2447                 View view = layoutRequesters.get(i);
   2448                 while (view != null &&
   2449                         (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
   2450                     view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
   2451                     if (view.mParent instanceof View) {
   2452                         view = (View) view.mParent;
   2453                     } else {
   2454                         view = null;
   2455                     }
   2456                 }
   2457             }
   2458         }
   2459         layoutRequesters.clear();
   2460         return validLayoutRequesters;
   2461     }
   2462 
   2463     @Override
   2464     public void requestTransparentRegion(View child) {
   2465         // the test below should not fail unless someone is messing with us
   2466         checkThread();
   2467         if (mView == child) {
   2468             mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
   2469             // Need to make sure we re-evaluate the window attributes next
   2470             // time around, to ensure the window has the correct format.
   2471             mWindowAttributesChanged = true;
   2472             mWindowAttributesChangesFlag = 0;
   2473             requestLayout();
   2474         }
   2475     }
   2476 
   2477     /**
   2478      * Figures out the measure spec for the root view in a window based on it's
   2479      * layout params.
   2480      *
   2481      * @param windowSize
   2482      *            The available width or height of the window
   2483      *
   2484      * @param rootDimension
   2485      *            The layout params for one dimension (width or height) of the
   2486      *            window.
   2487      *
   2488      * @return The measure spec to use to measure the root view.
   2489      */
   2490     private static int getRootMeasureSpec(int windowSize, int rootDimension) {
   2491         int measureSpec;
   2492         switch (rootDimension) {
   2493 
   2494         case ViewGroup.LayoutParams.MATCH_PARENT:
   2495             // Window can't resize. Force root view to be windowSize.
   2496             measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
   2497             break;
   2498         case ViewGroup.LayoutParams.WRAP_CONTENT:
   2499             // Window can resize. Set max size for root view.
   2500             measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
   2501             break;
   2502         default:
   2503             // Window wants to be an exact size. Force root view to be that size.
   2504             measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
   2505             break;
   2506         }
   2507         return measureSpec;
   2508     }
   2509 
   2510     int mHardwareXOffset;
   2511     int mHardwareYOffset;
   2512 
   2513     @Override
   2514     public void onHardwarePreDraw(DisplayListCanvas canvas) {
   2515         canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
   2516     }
   2517 
   2518     @Override
   2519     public void onHardwarePostDraw(DisplayListCanvas canvas) {
   2520         drawAccessibilityFocusedDrawableIfNeeded(canvas);
   2521         for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
   2522             mWindowCallbacks.get(i).onPostDraw(canvas);
   2523         }
   2524     }
   2525 
   2526     /**
   2527      * @hide
   2528      */
   2529     void outputDisplayList(View view) {
   2530         view.mRenderNode.output();
   2531         if (mAttachInfo.mHardwareRenderer != null) {
   2532             ((ThreadedRenderer)mAttachInfo.mHardwareRenderer).serializeDisplayListTree();
   2533         }
   2534     }
   2535 
   2536     /**
   2537      * @see #PROPERTY_PROFILE_RENDERING
   2538      */
   2539     private void profileRendering(boolean enabled) {
   2540         if (mProfileRendering) {
   2541             mRenderProfilingEnabled = enabled;
   2542 
   2543             if (mRenderProfiler != null) {
   2544                 mChoreographer.removeFrameCallback(mRenderProfiler);
   2545             }
   2546             if (mRenderProfilingEnabled) {
   2547                 if (mRenderProfiler == null) {
   2548                     mRenderProfiler = new Choreographer.FrameCallback() {
   2549                         @Override
   2550                         public void doFrame(long frameTimeNanos) {
   2551                             mDirty.set(0, 0, mWidth, mHeight);
   2552                             scheduleTraversals();
   2553                             if (mRenderProfilingEnabled) {
   2554                                 mChoreographer.postFrameCallback(mRenderProfiler);
   2555                             }
   2556                         }
   2557                     };
   2558                 }
   2559                 mChoreographer.postFrameCallback(mRenderProfiler);
   2560             } else {
   2561                 mRenderProfiler = null;
   2562             }
   2563         }
   2564     }
   2565 
   2566     /**
   2567      * Called from draw() when DEBUG_FPS is enabled
   2568      */
   2569     private void trackFPS() {
   2570         // Tracks frames per second drawn. First value in a series of draws may be bogus
   2571         // because it down not account for the intervening idle time
   2572         long nowTime = System.currentTimeMillis();
   2573         if (mFpsStartTime < 0) {
   2574             mFpsStartTime = mFpsPrevTime = nowTime;
   2575             mFpsNumFrames = 0;
   2576         } else {
   2577             ++mFpsNumFrames;
   2578             String thisHash = Integer.toHexString(System.identityHashCode(this));
   2579             long frameTime = nowTime - mFpsPrevTime;
   2580             long totalTime = nowTime - mFpsStartTime;
   2581             Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
   2582             mFpsPrevTime = nowTime;
   2583             if (totalTime > 1000) {
   2584                 float fps = (float) mFpsNumFrames * 1000 / totalTime;
   2585                 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
   2586                 mFpsStartTime = nowTime;
   2587                 mFpsNumFrames = 0;
   2588             }
   2589         }
   2590     }
   2591 
   2592     private void performDraw() {
   2593         if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
   2594             return;
   2595         }
   2596 
   2597         final boolean fullRedrawNeeded = mFullRedrawNeeded;
   2598         mFullRedrawNeeded = false;
   2599 
   2600         mIsDrawing = true;
   2601         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
   2602         try {
   2603             draw(fullRedrawNeeded);
   2604         } finally {
   2605             mIsDrawing = false;
   2606             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
   2607         }
   2608 
   2609         // For whatever reason we didn't create a HardwareRenderer, end any
   2610         // hardware animations that are now dangling
   2611         if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
   2612             final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
   2613             for (int i = 0; i < count; i++) {
   2614                 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
   2615             }
   2616             mAttachInfo.mPendingAnimatingRenderNodes.clear();
   2617         }
   2618 
   2619         if (mReportNextDraw) {
   2620             mReportNextDraw = false;
   2621 
   2622             // if we're using multi-thread renderer, wait for the window frame draws
   2623             if (mWindowDrawCountDown != null) {
   2624                 try {
   2625                     mWindowDrawCountDown.await();
   2626                 } catch (InterruptedException e) {
   2627                     Log.e(mTag, "Window redraw count down interruped!");
   2628                 }
   2629                 mWindowDrawCountDown = null;
   2630             }
   2631 
   2632             if (mAttachInfo.mHardwareRenderer != null) {
   2633                 mAttachInfo.mHardwareRenderer.fence();
   2634                 mAttachInfo.mHardwareRenderer.setStopped(mStopped);
   2635             }
   2636 
   2637             if (LOCAL_LOGV) {
   2638                 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
   2639             }
   2640             if (mSurfaceHolder != null && mSurface.isValid()) {
   2641                 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
   2642                 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
   2643                 if (callbacks != null) {
   2644                     for (SurfaceHolder.Callback c : callbacks) {
   2645                         if (c instanceof SurfaceHolder.Callback2) {
   2646                             ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(mSurfaceHolder);
   2647                         }
   2648                     }
   2649                 }
   2650             }
   2651             try {
   2652                 mWindowSession.finishDrawing(mWindow);
   2653             } catch (RemoteException e) {
   2654             }
   2655         }
   2656     }
   2657 
   2658     private void draw(boolean fullRedrawNeeded) {
   2659         Surface surface = mSurface;
   2660         if (!surface.isValid()) {
   2661             return;
   2662         }
   2663 
   2664         if (DEBUG_FPS) {
   2665             trackFPS();
   2666         }
   2667 
   2668         if (!sFirstDrawComplete) {
   2669             synchronized (sFirstDrawHandlers) {
   2670                 sFirstDrawComplete = true;
   2671                 final int count = sFirstDrawHandlers.size();
   2672                 for (int i = 0; i< count; i++) {
   2673                     mHandler.post(sFirstDrawHandlers.get(i));
   2674                 }
   2675             }
   2676         }
   2677 
   2678         scrollToRectOrFocus(null, false);
   2679 
   2680         if (mAttachInfo.mViewScrollChanged) {
   2681             mAttachInfo.mViewScrollChanged = false;
   2682             mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
   2683         }
   2684 
   2685         boolean animating = mScroller != null && mScroller.computeScrollOffset();
   2686         final int curScrollY;
   2687         if (animating) {
   2688             curScrollY = mScroller.getCurrY();
   2689         } else {
   2690             curScrollY = mScrollY;
   2691         }
   2692         if (mCurScrollY != curScrollY) {
   2693             mCurScrollY = curScrollY;
   2694             fullRedrawNeeded = true;
   2695             if (mView instanceof RootViewSurfaceTaker) {
   2696                 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
   2697             }
   2698         }
   2699 
   2700         final float appScale = mAttachInfo.mApplicationScale;
   2701         final boolean scalingRequired = mAttachInfo.mScalingRequired;
   2702 
   2703         int resizeAlpha = 0;
   2704 
   2705         final Rect dirty = mDirty;
   2706         if (mSurfaceHolder != null) {
   2707             // The app owns the surface, we won't draw.
   2708             dirty.setEmpty();
   2709             if (animating && mScroller != null) {
   2710                 mScroller.abortAnimation();
   2711             }
   2712             return;
   2713         }
   2714 
   2715         if (fullRedrawNeeded) {
   2716             mAttachInfo.mIgnoreDirtyState = true;
   2717             dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
   2718         }
   2719 
   2720         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
   2721             Log.v(mTag, "Draw " + mView + "/"
   2722                     + mWindowAttributes.getTitle()
   2723                     + ": dirty={" + dirty.left + "," + dirty.top
   2724                     + "," + dirty.right + "," + dirty.bottom + "} surface="
   2725                     + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
   2726                     appScale + ", width=" + mWidth + ", height=" + mHeight);
   2727         }
   2728 
   2729         mAttachInfo.mTreeObserver.dispatchOnDraw();
   2730 
   2731         int xOffset = -mCanvasOffsetX;
   2732         int yOffset = -mCanvasOffsetY + curScrollY;
   2733         final WindowManager.LayoutParams params = mWindowAttributes;
   2734         final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
   2735         if (surfaceInsets != null) {
   2736             xOffset -= surfaceInsets.left;
   2737             yOffset -= surfaceInsets.top;
   2738 
   2739             // Offset dirty rect for surface insets.
   2740             dirty.offset(surfaceInsets.left, surfaceInsets.right);
   2741         }
   2742 
   2743         boolean accessibilityFocusDirty = false;
   2744         final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
   2745         if (drawable != null) {
   2746             final Rect bounds = mAttachInfo.mTmpInvalRect;
   2747             final boolean hasFocus = getAccessibilityFocusedRect(bounds);
   2748             if (!hasFocus) {
   2749                 bounds.setEmpty();
   2750             }
   2751             if (!bounds.equals(drawable.getBounds())) {
   2752                 accessibilityFocusDirty = true;
   2753             }
   2754         }
   2755 
   2756         mAttachInfo.mDrawingTime =
   2757                 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
   2758 
   2759         if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
   2760             if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
   2761                 // If accessibility focus moved, always invalidate the root.
   2762                 boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
   2763                 mInvalidateRootRequested = false;
   2764 
   2765                 // Draw with hardware renderer.
   2766                 mIsAnimating = false;
   2767 
   2768                 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
   2769                     mHardwareYOffset = yOffset;
   2770                     mHardwareXOffset = xOffset;
   2771                     invalidateRoot = true;
   2772                 }
   2773 
   2774                 if (invalidateRoot) {
   2775                     mAttachInfo.mHardwareRenderer.invalidateRoot();
   2776                 }
   2777 
   2778                 dirty.setEmpty();
   2779 
   2780                 // Stage the content drawn size now. It will be transferred to the renderer
   2781                 // shortly before the draw commands get send to the renderer.
   2782                 final boolean updated = updateContentDrawBounds();
   2783 
   2784                 if (mReportNextDraw) {
   2785                     // report next draw overrides setStopped()
   2786                     // This value is re-sync'd to the value of mStopped
   2787                     // in the handling of mReportNextDraw post-draw.
   2788                     mAttachInfo.mHardwareRenderer.setStopped(false);
   2789                 }
   2790 
   2791                 if (updated) {
   2792                     requestDrawWindow();
   2793                 }
   2794 
   2795                 mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
   2796             } else {
   2797                 // If we get here with a disabled & requested hardware renderer, something went
   2798                 // wrong (an invalidate posted right before we destroyed the hardware surface
   2799                 // for instance) so we should just bail out. Locking the surface with software
   2800                 // rendering at this point would lock it forever and prevent hardware renderer
   2801                 // from doing its job when it comes back.
   2802                 // Before we request a new frame we must however attempt to reinitiliaze the
   2803                 // hardware renderer if it's in requested state. This would happen after an
   2804                 // eglTerminate() for instance.
   2805                 if (mAttachInfo.mHardwareRenderer != null &&
   2806                         !mAttachInfo.mHardwareRenderer.isEnabled() &&
   2807                         mAttachInfo.mHardwareRenderer.isRequested()) {
   2808 
   2809                     try {
   2810                         mAttachInfo.mHardwareRenderer.initializeIfNeeded(
   2811                                 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
   2812                     } catch (OutOfResourcesException e) {
   2813                         handleOutOfResourcesException(e);
   2814                         return;
   2815                     }
   2816 
   2817                     mFullRedrawNeeded = true;
   2818                     scheduleTraversals();
   2819                     return;
   2820                 }
   2821 
   2822                 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
   2823                     return;
   2824                 }
   2825             }
   2826         }
   2827 
   2828         if (animating) {
   2829             mFullRedrawNeeded = true;
   2830             scheduleTraversals();
   2831         }
   2832     }
   2833 
   2834     /**
   2835      * @return true if drawing was successful, false if an error occurred
   2836      */
   2837     private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
   2838             boolean scalingRequired, Rect dirty) {
   2839 
   2840         // Draw with software renderer.
   2841         final Canvas canvas;
   2842         try {
   2843             final int left = dirty.left;
   2844             final int top = dirty.top;
   2845             final int right = dirty.right;
   2846             final int bottom = dirty.bottom;
   2847 
   2848             canvas = mSurface.lockCanvas(dirty);
   2849 
   2850             // The dirty rectangle can be modified by Surface.lockCanvas()
   2851             //noinspection ConstantConditions
   2852             if (left != dirty.left || top != dirty.top || right != dirty.right
   2853                     || bottom != dirty.bottom) {
   2854                 attachInfo.mIgnoreDirtyState = true;
   2855             }
   2856 
   2857             // TODO: Do this in native
   2858             canvas.setDensity(mDensity);
   2859         } catch (Surface.OutOfResourcesException e) {
   2860             handleOutOfResourcesException(e);
   2861             return false;
   2862         } catch (IllegalArgumentException e) {
   2863             Log.e(mTag, "Could not lock surface", e);
   2864             // Don't assume this is due to out of memory, it could be
   2865             // something else, and if it is something else then we could
   2866             // kill stuff (or ourself) for no reason.
   2867             mLayoutRequested = true;    // ask wm for a new surface next time.
   2868             return false;
   2869         }
   2870 
   2871         try {
   2872             if (DEBUG_ORIENTATION || DEBUG_DRAW) {
   2873                 Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
   2874                         + canvas.getWidth() + ", h=" + canvas.getHeight());
   2875                 //canvas.drawARGB(255, 255, 0, 0);
   2876             }
   2877 
   2878             // If this bitmap's format includes an alpha channel, we
   2879             // need to clear it before drawing so that the child will
   2880             // properly re-composite its drawing on a transparent
   2881             // background. This automatically respects the clip/dirty region
   2882             // or
   2883             // If we are applying an offset, we need to clear the area
   2884             // where the offset doesn't appear to avoid having garbage
   2885             // left in the blank areas.
   2886             if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
   2887                 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
   2888             }
   2889 
   2890             dirty.setEmpty();
   2891             mIsAnimating = false;
   2892             mView.mPrivateFlags |= View.PFLAG_DRAWN;
   2893 
   2894             if (DEBUG_DRAW) {
   2895                 Context cxt = mView.getContext();
   2896                 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
   2897                         ", metrics=" + cxt.getResources().getDisplayMetrics() +
   2898                         ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
   2899             }
   2900             try {
   2901                 canvas.translate(-xoff, -yoff);
   2902                 if (mTranslator != null) {
   2903                     mTranslator.translateCanvas(canvas);
   2904                 }
   2905                 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
   2906                 attachInfo.mSetIgnoreDirtyState = false;
   2907 
   2908                 mView.draw(canvas);
   2909 
   2910                 drawAccessibilityFocusedDrawableIfNeeded(canvas);
   2911             } finally {
   2912                 if (!attachInfo.mSetIgnoreDirtyState) {
   2913                     // Only clear the flag if it was not set during the mView.draw() call
   2914                     attachInfo.mIgnoreDirtyState = false;
   2915                 }
   2916             }
   2917         } finally {
   2918             try {
   2919                 surface.unlockCanvasAndPost(canvas);
   2920             } catch (IllegalArgumentException e) {
   2921                 Log.e(mTag, "Could not unlock surface", e);
   2922                 mLayoutRequested = true;    // ask wm for a new surface next time.
   2923                 //noinspection ReturnInsideFinallyBlock
   2924                 return false;
   2925             }
   2926 
   2927             if (LOCAL_LOGV) {
   2928                 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
   2929             }
   2930         }
   2931         return true;
   2932     }
   2933 
   2934     /**
   2935      * We want to draw a highlight around the current accessibility focused.
   2936      * Since adding a style for all possible view is not a viable option we
   2937      * have this specialized drawing method.
   2938      *
   2939      * Note: We are doing this here to be able to draw the highlight for
   2940      *       virtual views in addition to real ones.
   2941      *
   2942      * @param canvas The canvas on which to draw.
   2943      */
   2944     private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
   2945         final Rect bounds = mAttachInfo.mTmpInvalRect;
   2946         if (getAccessibilityFocusedRect(bounds)) {
   2947             final Drawable drawable = getAccessibilityFocusedDrawable();
   2948             if (drawable != null) {
   2949                 drawable.setBounds(bounds);
   2950                 drawable.draw(canvas);
   2951             }
   2952         } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
   2953             mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
   2954         }
   2955     }
   2956 
   2957     private boolean getAccessibilityFocusedRect(Rect bounds) {
   2958         final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
   2959         if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
   2960             return false;
   2961         }
   2962 
   2963         final View host = mAccessibilityFocusedHost;
   2964         if (host == null || host.mAttachInfo == null) {
   2965             return false;
   2966         }
   2967 
   2968         final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
   2969         if (provider == null) {
   2970             host.getBoundsOnScreen(bounds, true);
   2971         } else if (mAccessibilityFocusedVirtualView != null) {
   2972             mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
   2973         } else {
   2974             return false;
   2975         }
   2976 
   2977         // Transform the rect into window-relative coordinates.
   2978         final AttachInfo attachInfo = mAttachInfo;
   2979         bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
   2980         bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
   2981         if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
   2982                 attachInfo.mViewRootImpl.mHeight)) {
   2983             // If no intersection, set bounds to empty.
   2984             bounds.setEmpty();
   2985         }
   2986         return !bounds.isEmpty();
   2987     }
   2988 
   2989     private Drawable getAccessibilityFocusedDrawable() {
   2990         // Lazily load the accessibility focus drawable.
   2991         if (mAttachInfo.mAccessibilityFocusDrawable == null) {
   2992             final TypedValue value = new TypedValue();
   2993             final boolean resolved = mView.mContext.getTheme().resolveAttribute(
   2994                     R.attr.accessibilityFocusedDrawable, value, true);
   2995             if (resolved) {
   2996                 mAttachInfo.mAccessibilityFocusDrawable =
   2997                         mView.mContext.getDrawable(value.resourceId);
   2998             }
   2999         }
   3000         return mAttachInfo.mAccessibilityFocusDrawable;
   3001     }
   3002 
   3003     /**
   3004      * Requests that the root render node is invalidated next time we perform a draw, such that
   3005      * {@link WindowCallbacks#onPostDraw} gets called.
   3006      */
   3007     public void requestInvalidateRootRenderNode() {
   3008         mInvalidateRootRequested = true;
   3009     }
   3010 
   3011     boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
   3012         final Rect ci = mAttachInfo.mContentInsets;
   3013         final Rect vi = mAttachInfo.mVisibleInsets;
   3014         int scrollY = 0;
   3015         boolean handled = false;
   3016 
   3017         if (vi.left > ci.left || vi.top > ci.top
   3018                 || vi.right > ci.right || vi.bottom > ci.bottom) {
   3019             // We'll assume that we aren't going to change the scroll
   3020             // offset, since we want to avoid that unless it is actually
   3021             // going to make the focus visible...  otherwise we scroll
   3022             // all over the place.
   3023             scrollY = mScrollY;
   3024             // We can be called for two different situations: during a draw,
   3025             // to update the scroll position if the focus has changed (in which
   3026             // case 'rectangle' is null), or in response to a
   3027             // requestChildRectangleOnScreen() call (in which case 'rectangle'
   3028             // is non-null and we just want to scroll to whatever that
   3029             // rectangle is).
   3030             final View focus = mView.findFocus();
   3031             if (focus == null) {
   3032                 return false;
   3033             }
   3034             View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
   3035             if (focus != lastScrolledFocus) {
   3036                 // If the focus has changed, then ignore any requests to scroll
   3037                 // to a rectangle; first we want to make sure the entire focus
   3038                 // view is visible.
   3039                 rectangle = null;
   3040             }
   3041             if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
   3042                     + " rectangle=" + rectangle + " ci=" + ci
   3043                     + " vi=" + vi);
   3044             if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
   3045                 // Optimization: if the focus hasn't changed since last
   3046                 // time, and no layout has happened, then just leave things
   3047                 // as they are.
   3048                 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
   3049                         + mScrollY + " vi=" + vi.toShortString());
   3050             } else {
   3051                 // We need to determine if the currently focused view is
   3052                 // within the visible part of the window and, if not, apply
   3053                 // a pan so it can be seen.
   3054                 mLastScrolledFocus = new WeakReference<View>(focus);
   3055                 mScrollMayChange = false;
   3056                 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
   3057                 // Try to find the rectangle from the focus view.
   3058                 if (focus.getGlobalVisibleRect(mVisRect, null)) {
   3059                     if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
   3060                             + mView.getWidth() + " h=" + mView.getHeight()
   3061                             + " ci=" + ci.toShortString()
   3062                             + " vi=" + vi.toShortString());
   3063                     if (rectangle == null) {
   3064                         focus.getFocusedRect(mTempRect);
   3065                         if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
   3066                                 + ": focusRect=" + mTempRect.toShortString());
   3067                         if (mView instanceof ViewGroup) {
   3068                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
   3069                                     focus, mTempRect);
   3070                         }
   3071                         if (DEBUG_INPUT_RESIZE) Log.v(mTag,
   3072                                 "Focus in window: focusRect="
   3073                                 + mTempRect.toShortString()
   3074                                 + " visRect=" + mVisRect.toShortString());
   3075                     } else {
   3076                         mTempRect.set(rectangle);
   3077                         if (DEBUG_INPUT_RESIZE) Log.v(mTag,
   3078                                 "Request scroll to rect: "
   3079                                 + mTempRect.toShortString()
   3080                                 + " visRect=" + mVisRect.toShortString());
   3081                     }
   3082                     if (mTempRect.intersect(mVisRect)) {
   3083                         if (DEBUG_INPUT_RESIZE) Log.v(mTag,
   3084                                 "Focus window visible rect: "
   3085                                 + mTempRect.toShortString());
   3086                         if (mTempRect.height() >
   3087                                 (mView.getHeight()-vi.top-vi.bottom)) {
   3088                             // If the focus simply is not going to fit, then
   3089                             // best is probably just to leave things as-is.
   3090                             if (DEBUG_INPUT_RESIZE) Log.v(mTag,
   3091                                     "Too tall; leaving scrollY=" + scrollY);
   3092                         }
   3093                         // Next, check whether top or bottom is covered based on the non-scrolled
   3094                         // position, and calculate new scrollY (or set it to 0).
   3095                         // We can't keep using mScrollY here. For example mScrollY is non-zero
   3096                         // due to IME, then IME goes away. The current value of mScrollY leaves top
   3097                         // and bottom both visible, but we still need to scroll it back to 0.
   3098                         else if (mTempRect.top < vi.top) {
   3099                             scrollY = mTempRect.top - vi.top;
   3100                             if (DEBUG_INPUT_RESIZE) Log.v(mTag,
   3101                                     "Top covered; scrollY=" + scrollY);
   3102                         } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) {
   3103                             scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom);
   3104                             if (DEBUG_INPUT_RESIZE) Log.v(mTag,
   3105                                     "Bottom covered; scrollY=" + scrollY);
   3106                         } else {
   3107                             scrollY = 0;
   3108                         }
   3109                         handled = true;
   3110                     }
   3111                 }
   3112             }
   3113         }
   3114 
   3115         if (scrollY != mScrollY) {
   3116             if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
   3117                     + mScrollY + " , new=" + scrollY);
   3118             if (!immediate) {
   3119                 if (mScroller == null) {
   3120                     mScroller = new Scroller(mView.getContext());
   3121                 }
   3122                 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
   3123             } else if (mScroller != null) {
   3124                 mScroller.abortAnimation();
   3125             }
   3126             mScrollY = scrollY;
   3127         }
   3128 
   3129         return handled;
   3130     }
   3131 
   3132     /**
   3133      * @hide
   3134      */
   3135     public View getAccessibilityFocusedHost() {
   3136         return mAccessibilityFocusedHost;
   3137     }
   3138 
   3139     /**
   3140      * @hide
   3141      */
   3142     public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
   3143         return mAccessibilityFocusedVirtualView;
   3144     }
   3145 
   3146     void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
   3147         // If we have a virtual view with accessibility focus we need
   3148         // to clear the focus and invalidate the virtual view bounds.
   3149         if (mAccessibilityFocusedVirtualView != null) {
   3150 
   3151             AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
   3152             View focusHost = mAccessibilityFocusedHost;
   3153 
   3154             // Wipe the state of the current accessibility focus since
   3155             // the call into the provider to clear accessibility focus
   3156             // will fire an accessibility event which will end up calling
   3157             // this method and we want to have clean state when this
   3158             // invocation happens.
   3159             mAccessibilityFocusedHost = null;
   3160             mAccessibilityFocusedVirtualView = null;
   3161 
   3162             // Clear accessibility focus on the host after clearing state since
   3163             // this method may be reentrant.
   3164             focusHost.clearAccessibilityFocusNoCallbacks(
   3165                     AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
   3166 
   3167             AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
   3168             if (provider != null) {
   3169                 // Invalidate the area of the cleared accessibility focus.
   3170                 focusNode.getBoundsInParent(mTempRect);
   3171                 focusHost.invalidate(mTempRect);
   3172                 // Clear accessibility focus in the virtual node.
   3173                 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
   3174                         focusNode.getSourceNodeId());
   3175                 provider.performAction(virtualNodeId,
   3176                         AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
   3177             }
   3178             focusNode.recycle();
   3179         }
   3180         if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view))  {
   3181             // Clear accessibility focus in the view.
   3182             mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(
   3183                     AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
   3184         }
   3185 
   3186         // Set the new focus host and node.
   3187         mAccessibilityFocusedHost = view;
   3188         mAccessibilityFocusedVirtualView = node;
   3189 
   3190         if (mAttachInfo.mHardwareRenderer != null) {
   3191             mAttachInfo.mHardwareRenderer.invalidateRoot();
   3192         }
   3193     }
   3194 
   3195     @Override
   3196     public void requestChildFocus(View child, View focused) {
   3197         if (DEBUG_INPUT_RESIZE) {
   3198             Log.v(mTag, "Request child focus: focus now " + focused);
   3199         }
   3200         checkThread();
   3201         scheduleTraversals();
   3202     }
   3203 
   3204     @Override
   3205     public void clearChildFocus(View child) {
   3206         if (DEBUG_INPUT_RESIZE) {
   3207             Log.v(mTag, "Clearing child focus");
   3208         }
   3209         checkThread();
   3210         scheduleTraversals();
   3211     }
   3212 
   3213     @Override
   3214     public ViewParent getParentForAccessibility() {
   3215         return null;
   3216     }
   3217 
   3218     @Override
   3219     public void focusableViewAvailable(View v) {
   3220         checkThread();
   3221         if (mView != null) {
   3222             if (!mView.hasFocus()) {
   3223                 v.requestFocus();
   3224             } else {
   3225                 // the one case where will transfer focus away from the current one
   3226                 // is if the current view is a view group that prefers to give focus
   3227                 // to its children first AND the view is a descendant of it.
   3228                 View focused = mView.findFocus();
   3229                 if (focused instanceof ViewGroup) {
   3230                     ViewGroup group = (ViewGroup) focused;
   3231                     if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
   3232                             && isViewDescendantOf(v, focused)) {
   3233                         v.requestFocus();
   3234                     }
   3235                 }
   3236             }
   3237         }
   3238     }
   3239 
   3240     @Override
   3241     public void recomputeViewAttributes(View child) {
   3242         checkThread();
   3243         if (mView == child) {
   3244             mAttachInfo.mRecomputeGlobalAttributes = true;
   3245             if (!mWillDrawSoon) {
   3246                 scheduleTraversals();
   3247             }
   3248         }
   3249     }
   3250 
   3251     void dispatchDetachedFromWindow() {
   3252         if (mView != null && mView.mAttachInfo != null) {
   3253             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
   3254             mView.dispatchDetachedFromWindow();
   3255         }
   3256 
   3257         mAccessibilityInteractionConnectionManager.ensureNoConnection();
   3258         mAccessibilityManager.removeAccessibilityStateChangeListener(
   3259                 mAccessibilityInteractionConnectionManager);
   3260         mAccessibilityManager.removeHighTextContrastStateChangeListener(
   3261                 mHighContrastTextManager);
   3262         removeSendWindowContentChangedCallback();
   3263 
   3264         destroyHardwareRenderer();
   3265 
   3266         setAccessibilityFocus(null, null);
   3267 
   3268         mView.assignParent(null);
   3269         mView = null;
   3270         mAttachInfo.mRootView = null;
   3271 
   3272         mSurface.release();
   3273 
   3274         if (mInputQueueCallback != null && mInputQueue != null) {
   3275             mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
   3276             mInputQueue.dispose();
   3277             mInputQueueCallback = null;
   3278             mInputQueue = null;
   3279         }
   3280         if (mInputEventReceiver != null) {
   3281             mInputEventReceiver.dispose();
   3282             mInputEventReceiver = null;
   3283         }
   3284         try {
   3285             mWindowSession.remove(mWindow);
   3286         } catch (RemoteException e) {
   3287         }
   3288 
   3289         // Dispose the input channel after removing the window so the Window Manager
   3290         // doesn't interpret the input channel being closed as an abnormal termination.
   3291         if (mInputChannel != null) {
   3292             mInputChannel.dispose();
   3293             mInputChannel = null;
   3294         }
   3295 
   3296         mDisplayManager.unregisterDisplayListener(mDisplayListener);
   3297 
   3298         unscheduleTraversals();
   3299     }
   3300 
   3301     void updateConfiguration(Configuration config, boolean force) {
   3302         if (DEBUG_CONFIGURATION) Log.v(mTag,
   3303                 "Applying new config to window "
   3304                 + mWindowAttributes.getTitle()
   3305                 + ": " + config);
   3306 
   3307         CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
   3308         if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
   3309             config = new Configuration(config);
   3310             ci.applyToConfiguration(mNoncompatDensity, config);
   3311         }
   3312 
   3313         synchronized (sConfigCallbacks) {
   3314             for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
   3315                 sConfigCallbacks.get(i).onConfigurationChanged(config);
   3316             }
   3317         }
   3318         if (mView != null) {
   3319             // At this point the resources have been updated to
   3320             // have the most recent config, whatever that is.  Use
   3321             // the one in them which may be newer.
   3322             final Resources localResources = mView.getResources();
   3323             config = localResources.getConfiguration();
   3324             if (force || mLastConfiguration.diff(config) != 0) {
   3325                 // Update the display with new DisplayAdjustments.
   3326                 mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
   3327                         mDisplay.getDisplayId(), localResources.getDisplayAdjustments());
   3328 
   3329                 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
   3330                 final int currentLayoutDirection = config.getLayoutDirection();
   3331                 mLastConfiguration.setTo(config);
   3332                 if (lastLayoutDirection != currentLayoutDirection &&
   3333                         mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
   3334                     mView.setLayoutDirection(currentLayoutDirection);
   3335                 }
   3336                 mView.dispatchConfigurationChanged(config);
   3337             }
   3338         }
   3339     }
   3340 
   3341     /**
   3342      * Return true if child is an ancestor of parent, (or equal to the parent).
   3343      */
   3344     public static boolean isViewDescendantOf(View child, View parent) {
   3345         if (child == parent) {
   3346             return true;
   3347         }
   3348 
   3349         final ViewParent theParent = child.getParent();
   3350         return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
   3351     }
   3352 
   3353     private static void forceLayout(View view) {
   3354         view.forceLayout();
   3355         if (view instanceof ViewGroup) {
   3356             ViewGroup group = (ViewGroup) view;
   3357             final int count = group.getChildCount();
   3358             for (int i = 0; i < count; i++) {
   3359                 forceLayout(group.getChildAt(i));
   3360             }
   3361         }
   3362     }
   3363 
   3364     private final static int MSG_INVALIDATE = 1;
   3365     private final static int MSG_INVALIDATE_RECT = 2;
   3366     private final static int MSG_DIE = 3;
   3367     private final static int MSG_RESIZED = 4;
   3368     private final static int MSG_RESIZED_REPORT = 5;
   3369     private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
   3370     private final static int MSG_DISPATCH_INPUT_EVENT = 7;
   3371     private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
   3372     private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
   3373     private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
   3374     private final static int MSG_CHECK_FOCUS = 13;
   3375     private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
   3376     private final static int MSG_DISPATCH_DRAG_EVENT = 15;
   3377     private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
   3378     private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
   3379     private final static int MSG_UPDATE_CONFIGURATION = 18;
   3380     private final static int MSG_PROCESS_INPUT_EVENTS = 19;
   3381     private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
   3382     private final static int MSG_INVALIDATE_WORLD = 22;
   3383     private final static int MSG_WINDOW_MOVED = 23;
   3384     private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
   3385     private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
   3386     private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
   3387     private final static int MSG_UPDATE_POINTER_ICON = 27;
   3388 
   3389     final class ViewRootHandler extends Handler {
   3390         @Override
   3391         public String getMessageName(Message message) {
   3392             switch (message.what) {
   3393                 case MSG_INVALIDATE:
   3394                     return "MSG_INVALIDATE";
   3395                 case MSG_INVALIDATE_RECT:
   3396                     return "MSG_INVALIDATE_RECT";
   3397                 case MSG_DIE:
   3398                     return "MSG_DIE";
   3399                 case MSG_RESIZED:
   3400                     return "MSG_RESIZED";
   3401                 case MSG_RESIZED_REPORT:
   3402                     return "MSG_RESIZED_REPORT";
   3403                 case MSG_WINDOW_FOCUS_CHANGED:
   3404                     return "MSG_WINDOW_FOCUS_CHANGED";
   3405                 case MSG_DISPATCH_INPUT_EVENT:
   3406                     return "MSG_DISPATCH_INPUT_EVENT";
   3407                 case MSG_DISPATCH_APP_VISIBILITY:
   3408                     return "MSG_DISPATCH_APP_VISIBILITY";
   3409                 case MSG_DISPATCH_GET_NEW_SURFACE:
   3410                     return "MSG_DISPATCH_GET_NEW_SURFACE";
   3411                 case MSG_DISPATCH_KEY_FROM_IME:
   3412                     return "MSG_DISPATCH_KEY_FROM_IME";
   3413                 case MSG_CHECK_FOCUS:
   3414                     return "MSG_CHECK_FOCUS";
   3415                 case MSG_CLOSE_SYSTEM_DIALOGS:
   3416                     return "MSG_CLOSE_SYSTEM_DIALOGS";
   3417                 case MSG_DISPATCH_DRAG_EVENT:
   3418                     return "MSG_DISPATCH_DRAG_EVENT";
   3419                 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
   3420                     return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
   3421                 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
   3422                     return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
   3423                 case MSG_UPDATE_CONFIGURATION:
   3424                     return "MSG_UPDATE_CONFIGURATION";
   3425                 case MSG_PROCESS_INPUT_EVENTS:
   3426                     return "MSG_PROCESS_INPUT_EVENTS";
   3427                 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
   3428                     return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
   3429                 case MSG_WINDOW_MOVED:
   3430                     return "MSG_WINDOW_MOVED";
   3431                 case MSG_SYNTHESIZE_INPUT_EVENT:
   3432                     return "MSG_SYNTHESIZE_INPUT_EVENT";
   3433                 case MSG_DISPATCH_WINDOW_SHOWN:
   3434                     return "MSG_DISPATCH_WINDOW_SHOWN";
   3435                 case MSG_UPDATE_POINTER_ICON:
   3436                     return "MSG_UPDATE_POINTER_ICON";
   3437             }
   3438             return super.getMessageName(message);
   3439         }
   3440 
   3441         @Override
   3442         public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
   3443             if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
   3444                 // Debugging for b/27963013
   3445                 throw new NullPointerException(
   3446                         "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
   3447             }
   3448             return super.sendMessageAtTime(msg, uptimeMillis);
   3449         }
   3450 
   3451         @Override
   3452         public void handleMessage(Message msg) {
   3453             switch (msg.what) {
   3454             case MSG_INVALIDATE:
   3455                 ((View) msg.obj).invalidate();
   3456                 break;
   3457             case MSG_INVALIDATE_RECT:
   3458                 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
   3459                 info.target.invalidate(info.left, info.top, info.right, info.bottom);
   3460                 info.recycle();
   3461                 break;
   3462             case MSG_PROCESS_INPUT_EVENTS:
   3463                 mProcessInputEventsScheduled = false;
   3464                 doProcessInputEvents();
   3465                 break;
   3466             case MSG_DISPATCH_APP_VISIBILITY:
   3467                 handleAppVisibility(msg.arg1 != 0);
   3468                 break;
   3469             case MSG_DISPATCH_GET_NEW_SURFACE:
   3470                 handleGetNewSurface();
   3471                 break;
   3472             case MSG_RESIZED: {
   3473                 // Recycled in the fall through...
   3474                 SomeArgs args = (SomeArgs) msg.obj;
   3475                 if (mWinFrame.equals(args.arg1)
   3476                         && mPendingOverscanInsets.equals(args.arg5)
   3477                         && mPendingContentInsets.equals(args.arg2)
   3478                         && mPendingStableInsets.equals(args.arg6)
   3479                         && mPendingVisibleInsets.equals(args.arg3)
   3480                         && mPendingOutsets.equals(args.arg7)
   3481                         && mPendingBackDropFrame.equals(args.arg8)
   3482                         && args.arg4 == null
   3483                         && args.argi1 == 0) {
   3484                     break;
   3485                 }
   3486                 } // fall through...
   3487             case MSG_RESIZED_REPORT:
   3488                 if (mAdded) {
   3489                     SomeArgs args = (SomeArgs) msg.obj;
   3490 
   3491                     Configuration config = (Configuration) args.arg4;
   3492                     if (config != null) {
   3493                         updateConfiguration(config, false);
   3494                     }
   3495 
   3496                     final boolean framesChanged = !mWinFrame.equals(args.arg1)
   3497                             || !mPendingOverscanInsets.equals(args.arg5)
   3498                             || !mPendingContentInsets.equals(args.arg2)
   3499                             || !mPendingStableInsets.equals(args.arg6)
   3500                             || !mPendingVisibleInsets.equals(args.arg3)
   3501                             || !mPendingOutsets.equals(args.arg7);
   3502 
   3503                     mWinFrame.set((Rect) args.arg1);
   3504                     mPendingOverscanInsets.set((Rect) args.arg5);
   3505                     mPendingContentInsets.set((Rect) args.arg2);
   3506                     mPendingStableInsets.set((Rect) args.arg6);
   3507                     mPendingVisibleInsets.set((Rect) args.arg3);
   3508                     mPendingOutsets.set((Rect) args.arg7);
   3509                     mPendingBackDropFrame.set((Rect) args.arg8);
   3510                     mForceNextWindowRelayout = args.argi1 != 0;
   3511                     mPendingAlwaysConsumeNavBar = args.argi2 != 0;
   3512 
   3513                     args.recycle();
   3514 
   3515                     if (msg.what == MSG_RESIZED_REPORT) {
   3516                         mReportNextDraw = true;
   3517                     }
   3518 
   3519                     if (mView != null && framesChanged) {
   3520                         forceLayout(mView);
   3521                     }
   3522 
   3523                     requestLayout();
   3524                 }
   3525                 break;
   3526             case MSG_WINDOW_MOVED:
   3527                 if (mAdded) {
   3528                     final int w = mWinFrame.width();
   3529                     final int h = mWinFrame.height();
   3530                     final int l = msg.arg1;
   3531                     final int t = msg.arg2;
   3532                     mWinFrame.left = l;
   3533                     mWinFrame.right = l + w;
   3534                     mWinFrame.top = t;
   3535                     mWinFrame.bottom = t + h;
   3536 
   3537                     mPendingBackDropFrame.set(mWinFrame);
   3538 
   3539                     // Suppress layouts during resizing - a correct layout will happen when resizing
   3540                     // is done, and this just increases system load.
   3541                     boolean isDockedDivider = mWindowAttributes.type == TYPE_DOCK_DIVIDER;
   3542                     boolean suppress = (mDragResizing && mResizeMode == RESIZE_MODE_DOCKED_DIVIDER)
   3543                             || isDockedDivider;
   3544                     if (!suppress) {
   3545                         if (mView != null) {
   3546                             forceLayout(mView);
   3547                         }
   3548                         requestLayout();
   3549                     } else {
   3550                         maybeHandleWindowMove(mWinFrame);
   3551                     }
   3552                 }
   3553                 break;
   3554             case MSG_WINDOW_FOCUS_CHANGED: {
   3555                 if (mAdded) {
   3556                     boolean hasWindowFocus = msg.arg1 != 0;
   3557                     mAttachInfo.mHasWindowFocus = hasWindowFocus;
   3558 
   3559                     profileRendering(hasWindowFocus);
   3560 
   3561                     if (hasWindowFocus) {
   3562                         boolean inTouchMode = msg.arg2 != 0;
   3563                         ensureTouchModeLocally(inTouchMode);
   3564 
   3565                         if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
   3566                             mFullRedrawNeeded = true;
   3567                             try {
   3568                                 final WindowManager.LayoutParams lp = mWindowAttributes;
   3569                                 final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
   3570                                 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
   3571                                         mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
   3572                             } catch (OutOfResourcesException e) {
   3573                                 Log.e(mTag, "OutOfResourcesException locking surface", e);
   3574                                 try {
   3575                                     if (!mWindowSession.outOfMemory(mWindow)) {
   3576                                         Slog.w(mTag, "No processes killed for memory; killing self");
   3577                                         Process.killProcess(Process.myPid());
   3578                                     }
   3579                                 } catch (RemoteException ex) {
   3580                                 }
   3581                                 // Retry in a bit.
   3582                                 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
   3583                                 return;
   3584                             }
   3585                         }
   3586                     }
   3587 
   3588                     mLastWasImTarget = WindowManager.LayoutParams
   3589                             .mayUseInputMethod(mWindowAttributes.flags);
   3590 
   3591                     InputMethodManager imm = InputMethodManager.peekInstance();
   3592                     if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
   3593                         imm.onPreWindowFocus(mView, hasWindowFocus);
   3594                     }
   3595                     if (mView != null) {
   3596                         mAttachInfo.mKeyDispatchState.reset();
   3597                         mView.dispatchWindowFocusChanged(hasWindowFocus);
   3598                         mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
   3599                     }
   3600 
   3601                     // Note: must be done after the focus change callbacks,
   3602                     // so all of the view state is set up correctly.
   3603                     if (hasWindowFocus) {
   3604                         if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
   3605                             imm.onPostWindowFocus(mView, mView.findFocus(),
   3606                                     mWindowAttributes.softInputMode,
   3607                                     !mHasHadWindowFocus, mWindowAttributes.flags);
   3608                         }
   3609                         // Clear the forward bit.  We can just do this directly, since
   3610                         // the window manager doesn't care about it.
   3611                         mWindowAttributes.softInputMode &=
   3612                                 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
   3613                         ((WindowManager.LayoutParams)mView.getLayoutParams())
   3614                                 .softInputMode &=
   3615                                     ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
   3616                         mHasHadWindowFocus = true;
   3617                     }
   3618                 }
   3619             } break;
   3620             case MSG_DIE:
   3621                 doDie();
   3622                 break;
   3623             case MSG_DISPATCH_INPUT_EVENT: {
   3624                 SomeArgs args = (SomeArgs)msg.obj;
   3625                 InputEvent event = (InputEvent)args.arg1;
   3626                 InputEventReceiver receiver = (InputEventReceiver)args.arg2;
   3627                 enqueueInputEvent(event, receiver, 0, true);
   3628                 args.recycle();
   3629             } break;
   3630             case MSG_SYNTHESIZE_INPUT_EVENT: {
   3631                 InputEvent event = (InputEvent)msg.obj;
   3632                 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
   3633             } break;
   3634             case MSG_DISPATCH_KEY_FROM_IME: {
   3635                 if (LOCAL_LOGV) Log.v(
   3636                     TAG, "Dispatching key "
   3637                     + msg.obj + " from IME to " + mView);
   3638                 KeyEvent event = (KeyEvent)msg.obj;
   3639                 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
   3640                     // The IME is trying to say this event is from the
   3641                     // system!  Bad bad bad!
   3642                     //noinspection UnusedAssignment
   3643                     event = KeyEvent.changeFlags(event, event.getFlags() &
   3644                             ~KeyEvent.FLAG_FROM_SYSTEM);
   3645                 }
   3646                 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
   3647             } break;
   3648             case MSG_CHECK_FOCUS: {
   3649                 InputMethodManager imm = InputMethodManager.peekInstance();
   3650                 if (imm != null) {
   3651                     imm.checkFocus();
   3652                 }
   3653             } break;
   3654             case MSG_CLOSE_SYSTEM_DIALOGS: {
   3655                 if (mView != null) {
   3656                     mView.onCloseSystemDialogs((String)msg.obj);
   3657                 }
   3658             } break;
   3659             case MSG_DISPATCH_DRAG_EVENT:
   3660             case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
   3661                 DragEvent event = (DragEvent)msg.obj;
   3662                 event.mLocalState = mLocalDragState;    // only present when this app called startDrag()
   3663                 handleDragEvent(event);
   3664             } break;
   3665             case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
   3666                 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
   3667             } break;
   3668             case MSG_UPDATE_CONFIGURATION: {
   3669                 Configuration config = (Configuration)msg.obj;
   3670                 if (config.isOtherSeqNewer(mLastConfiguration)) {
   3671                     config = mLastConfiguration;
   3672                 }
   3673                 updateConfiguration(config, false);
   3674             } break;
   3675             case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
   3676                 setAccessibilityFocus(null, null);
   3677             } break;
   3678             case MSG_INVALIDATE_WORLD: {
   3679                 if (mView != null) {
   3680                     invalidateWorld(mView);
   3681                 }
   3682             } break;
   3683             case MSG_DISPATCH_WINDOW_SHOWN: {
   3684                 handleDispatchWindowShown();
   3685             } break;
   3686             case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
   3687                 final IResultReceiver receiver = (IResultReceiver) msg.obj;
   3688                 final int deviceId = msg.arg1;
   3689                 handleRequestKeyboardShortcuts(receiver, deviceId);
   3690             } break;
   3691             case MSG_UPDATE_POINTER_ICON: {
   3692                 MotionEvent event = (MotionEvent) msg.obj;
   3693                 resetPointerIcon(event);
   3694             } break;
   3695             }
   3696         }
   3697     }
   3698 
   3699     final ViewRootHandler mHandler = new ViewRootHandler();
   3700 
   3701     /**
   3702      * Something in the current window tells us we need to change the touch mode.  For
   3703      * example, we are not in touch mode, and the user touches the screen.
   3704      *
   3705      * If the touch mode has changed, tell the window manager, and handle it locally.
   3706      *
   3707      * @param inTouchMode Whether we want to be in touch mode.
   3708      * @return True if the touch mode changed and focus changed was changed as a result
   3709      */
   3710     boolean ensureTouchMode(boolean inTouchMode) {
   3711         if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
   3712                 + "touch mode is " + mAttachInfo.mInTouchMode);
   3713         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
   3714 
   3715         // tell the window manager
   3716         try {
   3717             mWindowSession.setInTouchMode(inTouchMode);
   3718         } catch (RemoteException e) {
   3719             throw new RuntimeException(e);
   3720         }
   3721 
   3722         // handle the change
   3723         return ensureTouchModeLocally(inTouchMode);
   3724     }
   3725 
   3726     /**
   3727      * Ensure that the touch mode for this window is set, and if it is changing,
   3728      * take the appropriate action.
   3729      * @param inTouchMode Whether we want to be in touch mode.
   3730      * @return True if the touch mode changed and focus changed was changed as a result
   3731      */
   3732     private boolean ensureTouchModeLocally(boolean inTouchMode) {
   3733         if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
   3734                 + "touch mode is " + mAttachInfo.mInTouchMode);
   3735 
   3736         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
   3737 
   3738         mAttachInfo.mInTouchMode = inTouchMode;
   3739         mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
   3740 
   3741         return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
   3742     }
   3743 
   3744     private boolean enterTouchMode() {
   3745         if (mView != null && mView.hasFocus()) {
   3746             // note: not relying on mFocusedView here because this could
   3747             // be when the window is first being added, and mFocused isn't
   3748             // set yet.
   3749             final View focused = mView.findFocus();
   3750             if (focused != null && !focused.isFocusableInTouchMode()) {
   3751                 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
   3752                 if (ancestorToTakeFocus != null) {
   3753                     // there is an ancestor that wants focus after its
   3754                     // descendants that is focusable in touch mode.. give it
   3755                     // focus
   3756                     return ancestorToTakeFocus.requestFocus();
   3757                 } else {
   3758                     // There's nothing to focus. Clear and propagate through the
   3759                     // hierarchy, but don't attempt to place new focus.
   3760                     focused.clearFocusInternal(null, true, false);
   3761                     return true;
   3762                 }
   3763             }
   3764         }
   3765         return false;
   3766     }
   3767 
   3768     /**
   3769      * Find an ancestor of focused that wants focus after its descendants and is
   3770      * focusable in touch mode.
   3771      * @param focused The currently focused view.
   3772      * @return An appropriate view, or null if no such view exists.
   3773      */
   3774     private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
   3775         ViewParent parent = focused.getParent();
   3776         while (parent instanceof ViewGroup) {
   3777             final ViewGroup vgParent = (ViewGroup) parent;
   3778             if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
   3779                     && vgParent.isFocusableInTouchMode()) {
   3780                 return vgParent;
   3781             }
   3782             if (vgParent.isRootNamespace()) {
   3783                 return null;
   3784             } else {
   3785                 parent = vgParent.getParent();
   3786             }
   3787         }
   3788         return null;
   3789     }
   3790 
   3791     private boolean leaveTouchMode() {
   3792         if (mView != null) {
   3793             if (mView.hasFocus()) {
   3794                 View focusedView = mView.findFocus();
   3795                 if (!(focusedView instanceof ViewGroup)) {
   3796                     // some view has focus, let it keep it
   3797                     return false;
   3798                 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
   3799                         ViewGroup.FOCUS_AFTER_DESCENDANTS) {
   3800                     // some view group has focus, and doesn't prefer its children
   3801                     // over itself for focus, so let them keep it.
   3802                     return false;
   3803                 }
   3804             }
   3805 
   3806             // find the best view to give focus to in this brave new non-touch-mode
   3807             // world
   3808             final View focused = focusSearch(null, View.FOCUS_DOWN);
   3809             if (focused != null) {
   3810                 return focused.requestFocus(View.FOCUS_DOWN);
   3811             }
   3812         }
   3813         return false;
   3814     }
   3815 
   3816     /**
   3817      * Base class for implementing a stage in the chain of responsibility
   3818      * for processing input events.
   3819      * <p>
   3820      * Events are delivered to the stage by the {@link #deliver} method.  The stage
   3821      * then has the choice of finishing the event or forwarding it to the next stage.
   3822      * </p>
   3823      */
   3824     abstract class InputStage {
   3825         private final InputStage mNext;
   3826 
   3827         protected static final int FORWARD = 0;
   3828         protected static final int FINISH_HANDLED = 1;
   3829         protected static final int FINISH_NOT_HANDLED = 2;
   3830 
   3831         /**
   3832          * Creates an input stage.
   3833          * @param next The next stage to which events should be forwarded.
   3834          */
   3835         public InputStage(InputStage next) {
   3836             mNext = next;
   3837         }
   3838 
   3839         /**
   3840          * Delivers an event to be processed.
   3841          */
   3842         public final void deliver(QueuedInputEvent q) {
   3843             if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
   3844                 forward(q);
   3845             } else if (shouldDropInputEvent(q)) {
   3846                 finish(q, false);
   3847             } else {
   3848                 apply(q, onProcess(q));
   3849             }
   3850         }
   3851 
   3852         /**
   3853          * Marks the the input event as finished then forwards it to the next stage.
   3854          */
   3855         protected void finish(QueuedInputEvent q, boolean handled) {
   3856             q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
   3857             if (handled) {
   3858                 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
   3859             }
   3860             forward(q);
   3861         }
   3862 
   3863         /**
   3864          * Forwards the event to the next stage.
   3865          */
   3866         protected void forward(QueuedInputEvent q) {
   3867             onDeliverToNext(q);
   3868         }
   3869 
   3870         /**
   3871          * Applies a result code from {@link #onProcess} to the specified event.
   3872          */
   3873         protected void apply(QueuedInputEvent q, int result) {
   3874             if (result == FORWARD) {
   3875                 forward(q);
   3876             } else if (result == FINISH_HANDLED) {
   3877                 finish(q, true);
   3878             } else if (result == FINISH_NOT_HANDLED) {
   3879                 finish(q, false);
   3880             } else {
   3881                 throw new IllegalArgumentException("Invalid result: " + result);
   3882             }
   3883         }
   3884 
   3885         /**
   3886          * Called when an event is ready to be processed.
   3887          * @return A result code indicating how the event was handled.
   3888          */
   3889         protected int onProcess(QueuedInputEvent q) {
   3890             return FORWARD;
   3891         }
   3892 
   3893         /**
   3894          * Called when an event is being delivered to the next stage.
   3895          */
   3896         protected void onDeliverToNext(QueuedInputEvent q) {
   3897             if (DEBUG_INPUT_STAGES) {
   3898                 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
   3899             }
   3900             if (mNext != null) {
   3901                 mNext.deliver(q);
   3902             } else {
   3903                 finishInputEvent(q);
   3904             }
   3905         }
   3906 
   3907         protected boolean shouldDropInputEvent(QueuedInputEvent q) {
   3908             if (mView == null || !mAdded) {
   3909                 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
   3910                 return true;
   3911             } else if ((!mAttachInfo.mHasWindowFocus
   3912                     && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
   3913                     || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
   3914                     || (mPausedForTransition && !isBack(q.mEvent))) {
   3915                 // This is a focus event and the window doesn't currently have input focus or
   3916                 // has stopped. This could be an event that came back from the previous stage
   3917                 // but the window has lost focus or stopped in the meantime.
   3918                 if (isTerminalInputEvent(q.mEvent)) {
   3919                     // Don't drop terminal input events, however mark them as canceled.
   3920                     q.mEvent.cancel();
   3921                     Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
   3922                     return false;
   3923                 }
   3924 
   3925                 // Drop non-terminal input events.
   3926                 Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
   3927                 return true;
   3928             }
   3929             return false;
   3930         }
   3931 
   3932         void dump(String prefix, PrintWriter writer) {
   3933             if (mNext != null) {
   3934                 mNext.dump(prefix, writer);
   3935             }
   3936         }
   3937 
   3938         private boolean isBack(InputEvent event) {
   3939             if (event instanceof KeyEvent) {
   3940                 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
   3941             } else {
   3942                 return false;
   3943             }
   3944         }
   3945     }
   3946 
   3947     /**
   3948      * Base class for implementing an input pipeline stage that supports
   3949      * asynchronous and out-of-order processing of input events.
   3950      * <p>
   3951      * In addition to what a normal input stage can do, an asynchronous
   3952      * input stage may also defer an input event that has been delivered to it
   3953      * and finish or forward it later.
   3954      * </p>
   3955      */
   3956     abstract class AsyncInputStage extends InputStage {
   3957         private final String mTraceCounter;
   3958 
   3959         private QueuedInputEvent mQueueHead;
   3960         private QueuedInputEvent mQueueTail;
   3961         private int mQueueLength;
   3962 
   3963         protected static final int DEFER = 3;
   3964 
   3965         /**
   3966          * Creates an asynchronous input stage.
   3967          * @param next The next stage to which events should be forwarded.
   3968          * @param traceCounter The name of a counter to record the size of
   3969          * the queue of pending events.
   3970          */
   3971         public AsyncInputStage(InputStage next, String traceCounter) {
   3972             super(next);
   3973             mTraceCounter = traceCounter;
   3974         }
   3975 
   3976         /**
   3977          * Marks the event as deferred, which is to say that it will be handled
   3978          * asynchronously.  The caller is responsible for calling {@link #forward}
   3979          * or {@link #finish} later when it is done handling the event.
   3980          */
   3981         protected void defer(QueuedInputEvent q) {
   3982             q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
   3983             enqueue(q);
   3984         }
   3985 
   3986         @Override
   3987         protected void forward(QueuedInputEvent q) {
   3988             // Clear the deferred flag.
   3989             q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
   3990 
   3991             // Fast path if the queue is empty.
   3992             QueuedInputEvent curr = mQueueHead;
   3993             if (curr == null) {
   3994                 super.forward(q);
   3995                 return;
   3996             }
   3997 
   3998             // Determine whether the event must be serialized behind any others
   3999             // before it can be delivered to the next stage.  This is done because
   4000             // deferred events might be handled out of order by the stage.
   4001             final int deviceId = q.mEvent.getDeviceId();
   4002             QueuedInputEvent prev = null;
   4003             boolean blocked = false;
   4004             while (curr != null && curr != q) {
   4005                 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
   4006                     blocked = true;
   4007                 }
   4008                 prev = curr;
   4009                 curr = curr.mNext;
   4010             }
   4011 
   4012             // If the event is blocked, then leave it in the queue to be delivered later.
   4013             // Note that the event might not yet be in the queue if it was not previously
   4014             // deferred so we will enqueue it if needed.
   4015             if (blocked) {
   4016                 if (curr == null) {
   4017                     enqueue(q);
   4018                 }
   4019                 return;
   4020             }
   4021 
   4022             // The event is not blocked.  Deliver it immediately.
   4023             if (curr != null) {
   4024                 curr = curr.mNext;
   4025                 dequeue(q, prev);
   4026             }
   4027             super.forward(q);
   4028 
   4029             // Dequeuing this event may have unblocked successors.  Deliver them.
   4030             while (curr != null) {
   4031                 if (deviceId == curr.mEvent.getDeviceId()) {
   4032                     if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
   4033                         break;
   4034                     }
   4035                     QueuedInputEvent next = curr.mNext;
   4036                     dequeue(curr, prev);
   4037                     super.forward(curr);
   4038                     curr = next;
   4039                 } else {
   4040                     prev = curr;
   4041                     curr = curr.mNext;
   4042                 }
   4043             }
   4044         }
   4045 
   4046         @Override
   4047         protected void apply(QueuedInputEvent q, int result) {
   4048             if (result == DEFER) {
   4049                 defer(q);
   4050             } else {
   4051                 super.apply(q, result);
   4052             }
   4053         }
   4054 
   4055         private void enqueue(QueuedInputEvent q) {
   4056             if (mQueueTail == null) {
   4057                 mQueueHead = q;
   4058                 mQueueTail = q;
   4059             } else {
   4060                 mQueueTail.mNext = q;
   4061                 mQueueTail = q;
   4062             }
   4063 
   4064             mQueueLength += 1;
   4065             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
   4066         }
   4067 
   4068         private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
   4069             if (prev == null) {
   4070                 mQueueHead = q.mNext;
   4071             } else {
   4072                 prev.mNext = q.mNext;
   4073             }
   4074             if (mQueueTail == q) {
   4075                 mQueueTail = prev;
   4076             }
   4077             q.mNext = null;
   4078 
   4079             mQueueLength -= 1;
   4080             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
   4081         }
   4082 
   4083         @Override
   4084         void dump(String prefix, PrintWriter writer) {
   4085             writer.print(prefix);
   4086             writer.print(getClass().getName());
   4087             writer.print(": mQueueLength=");
   4088             writer.println(mQueueLength);
   4089 
   4090             super.dump(prefix, writer);
   4091         }
   4092     }
   4093 
   4094     /**
   4095      * Delivers pre-ime input events to a native activity.
   4096      * Does not support pointer events.
   4097      */
   4098     final class NativePreImeInputStage extends AsyncInputStage
   4099             implements InputQueue.FinishedInputEventCallback {
   4100         public NativePreImeInputStage(InputStage next, String traceCounter) {
   4101             super(next, traceCounter);
   4102         }
   4103 
   4104         @Override
   4105         protected int onProcess(QueuedInputEvent q) {
   4106             if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
   4107                 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
   4108                 return DEFER;
   4109             }
   4110             return FORWARD;
   4111         }
   4112 
   4113         @Override
   4114         public void onFinishedInputEvent(Object token, boolean handled) {
   4115             QueuedInputEvent q = (QueuedInputEvent)token;
   4116             if (handled) {
   4117                 finish(q, true);
   4118                 return;
   4119             }
   4120             forward(q);
   4121         }
   4122     }
   4123 
   4124     /**
   4125      * Delivers pre-ime input events to the view hierarchy.
   4126      * Does not support pointer events.
   4127      */
   4128     final class ViewPreImeInputStage extends InputStage {
   4129         public ViewPreImeInputStage(InputStage next) {
   4130             super(next);
   4131         }
   4132 
   4133         @Override
   4134         protected int onProcess(QueuedInputEvent q) {
   4135             if (q.mEvent instanceof KeyEvent) {
   4136                 return processKeyEvent(q);
   4137             }
   4138             return FORWARD;
   4139         }
   4140 
   4141         private int processKeyEvent(QueuedInputEvent q) {
   4142             final KeyEvent event = (KeyEvent)q.mEvent;
   4143             if (mView.dispatchKeyEventPreIme(event)) {
   4144                 return FINISH_HANDLED;
   4145             }
   4146             return FORWARD;
   4147         }
   4148     }
   4149 
   4150     /**
   4151      * Delivers input events to the ime.
   4152      * Does not support pointer events.
   4153      */
   4154     final class ImeInputStage extends AsyncInputStage
   4155             implements InputMethodManager.FinishedInputEventCallback {
   4156         public ImeInputStage(InputStage next, String traceCounter) {
   4157             super(next, traceCounter);
   4158         }
   4159 
   4160         @Override
   4161         protected int onProcess(QueuedInputEvent q) {
   4162             if (mLastWasImTarget && !isInLocalFocusMode()) {
   4163                 InputMethodManager imm = InputMethodManager.peekInstance();
   4164                 if (imm != null) {
   4165                     final InputEvent event = q.mEvent;
   4166                     if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
   4167                     int result = imm.dispatchInputEvent(event, q, this, mHandler);
   4168                     if (result == InputMethodManager.DISPATCH_HANDLED) {
   4169                         return FINISH_HANDLED;
   4170                     } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
   4171                         // The IME could not handle it, so skip along to the next InputStage
   4172                         return FORWARD;
   4173                     } else {
   4174                         return DEFER; // callback will be invoked later
   4175                     }
   4176                 }
   4177             }
   4178             return FORWARD;
   4179         }
   4180 
   4181         @Override
   4182         public void onFinishedInputEvent(Object token, boolean handled) {
   4183             QueuedInputEvent q = (QueuedInputEvent)token;
   4184             if (handled) {
   4185                 finish(q, true);
   4186                 return;
   4187             }
   4188             forward(q);
   4189         }
   4190     }
   4191 
   4192     /**
   4193      * Performs early processing of post-ime input events.
   4194      */
   4195     final class EarlyPostImeInputStage extends InputStage {
   4196         public EarlyPostImeInputStage(InputStage next) {
   4197             super(next);
   4198         }
   4199 
   4200         @Override
   4201         protected int onProcess(QueuedInputEvent q) {
   4202             if (q.mEvent instanceof KeyEvent) {
   4203                 return processKeyEvent(q);
   4204             } else {
   4205                 final int source = q.mEvent.getSource();
   4206                 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
   4207                     return processPointerEvent(q);
   4208                 }
   4209             }
   4210             return FORWARD;
   4211         }
   4212 
   4213         private int processKeyEvent(QueuedInputEvent q) {
   4214             final KeyEvent event = (KeyEvent)q.mEvent;
   4215 
   4216             // If the key's purpose is to exit touch mode then we consume it
   4217             // and consider it handled.
   4218             if (checkForLeavingTouchModeAndConsume(event)) {
   4219                 return FINISH_HANDLED;
   4220             }
   4221 
   4222             // Make sure the fallback event policy sees all keys that will be
   4223             // delivered to the view hierarchy.
   4224             mFallbackEventHandler.preDispatchKeyEvent(event);
   4225             return FORWARD;
   4226         }
   4227 
   4228         private int processPointerEvent(QueuedInputEvent q) {
   4229             final MotionEvent event = (MotionEvent)q.mEvent;
   4230 
   4231             // Translate the pointer event for compatibility, if needed.
   4232             if (mTranslator != null) {
   4233                 mTranslator.translateEventInScreenToAppWindow(event);
   4234             }
   4235 
   4236             // Enter touch mode on down or scroll.
   4237             final int action = event.getAction();
   4238             if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
   4239                 ensureTouchMode(true);
   4240             }
   4241 
   4242             // Offset the scroll position.
   4243             if (mCurScrollY != 0) {
   4244                 event.offsetLocation(0, mCurScrollY);
   4245             }
   4246 
   4247             // Remember the touch position for possible drag-initiation.
   4248             if (event.isTouchEvent()) {
   4249                 mLastTouchPoint.x = event.getRawX();
   4250                 mLastTouchPoint.y = event.getRawY();
   4251                 mLastTouchSource = event.getSource();
   4252             }
   4253             return FORWARD;
   4254         }
   4255     }
   4256 
   4257     /**
   4258      * Delivers post-ime input events to a native activity.
   4259      */
   4260     final class NativePostImeInputStage extends AsyncInputStage
   4261             implements InputQueue.FinishedInputEventCallback {
   4262         public NativePostImeInputStage(InputStage next, String traceCounter) {
   4263             super(next, traceCounter);
   4264         }
   4265 
   4266         @Override
   4267         protected int onProcess(QueuedInputEvent q) {
   4268             if (mInputQueue != null) {
   4269                 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
   4270                 return DEFER;
   4271             }
   4272             return FORWARD;
   4273         }
   4274 
   4275         @Override
   4276         public void onFinishedInputEvent(Object token, boolean handled) {
   4277             QueuedInputEvent q = (QueuedInputEvent)token;
   4278             if (handled) {
   4279                 finish(q, true);
   4280                 return;
   4281             }
   4282             forward(q);
   4283         }
   4284     }
   4285 
   4286     /**
   4287      * Delivers post-ime input events to the view hierarchy.
   4288      */
   4289     final class ViewPostImeInputStage extends InputStage {
   4290         public ViewPostImeInputStage(InputStage next) {
   4291             super(next);
   4292         }
   4293 
   4294         @Override
   4295         protected int onProcess(QueuedInputEvent q) {
   4296             if (q.mEvent instanceof KeyEvent) {
   4297                 return processKeyEvent(q);
   4298             } else {
   4299                 final int source = q.mEvent.getSource();
   4300                 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
   4301                     return processPointerEvent(q);
   4302                 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
   4303                     return processTrackballEvent(q);
   4304                 } else {
   4305                     return processGenericMotionEvent(q);
   4306                 }
   4307             }
   4308         }
   4309 
   4310         @Override
   4311         protected void onDeliverToNext(QueuedInputEvent q) {
   4312             if (mUnbufferedInputDispatch
   4313                     && q.mEvent instanceof MotionEvent
   4314                     && ((MotionEvent)q.mEvent).isTouchEvent()
   4315                     && isTerminalInputEvent(q.mEvent)) {
   4316                 mUnbufferedInputDispatch = false;
   4317                 scheduleConsumeBatchedInput();
   4318             }
   4319             super.onDeliverToNext(q);
   4320         }
   4321 
   4322         private int processKeyEvent(QueuedInputEvent q) {
   4323             final KeyEvent event = (KeyEvent)q.mEvent;
   4324 
   4325             // Deliver the key to the view hierarchy.
   4326             if (mView.dispatchKeyEvent(event)) {
   4327                 return FINISH_HANDLED;
   4328             }
   4329 
   4330             if (shouldDropInputEvent(q)) {
   4331                 return FINISH_NOT_HANDLED;
   4332             }
   4333 
   4334             // If the Control modifier is held, try to interpret the key as a shortcut.
   4335             if (event.getAction() == KeyEvent.ACTION_DOWN
   4336                     && event.isCtrlPressed()
   4337                     && event.getRepeatCount() == 0
   4338                     && !KeyEvent.isModifierKey(event.getKeyCode())) {
   4339                 if (mView.dispatchKeyShortcutEvent(event)) {
   4340                     return FINISH_HANDLED;
   4341                 }
   4342                 if (shouldDropInputEvent(q)) {
   4343                     return FINISH_NOT_HANDLED;
   4344                 }
   4345             }
   4346 
   4347             // Apply the fallback event policy.
   4348             if (mFallbackEventHandler.dispatchKeyEvent(event)) {
   4349                 return FINISH_HANDLED;
   4350             }
   4351             if (shouldDropInputEvent(q)) {
   4352                 return FINISH_NOT_HANDLED;
   4353             }
   4354 
   4355             // Handle automatic focus changes.
   4356             if (event.getAction() == KeyEvent.ACTION_DOWN) {
   4357                 int direction = 0;
   4358                 switch (event.getKeyCode()) {
   4359                     case KeyEvent.KEYCODE_DPAD_LEFT:
   4360                         if (event.hasNoModifiers()) {
   4361                             direction = View.FOCUS_LEFT;
   4362                         }
   4363                         break;
   4364                     case KeyEvent.KEYCODE_DPAD_RIGHT:
   4365                         if (event.hasNoModifiers()) {
   4366                             direction = View.FOCUS_RIGHT;
   4367                         }
   4368                         break;
   4369                     case KeyEvent.KEYCODE_DPAD_UP:
   4370                         if (event.hasNoModifiers()) {
   4371                             direction = View.FOCUS_UP;
   4372                         }
   4373                         break;
   4374                     case KeyEvent.KEYCODE_DPAD_DOWN:
   4375                         if (event.hasNoModifiers()) {
   4376                             direction = View.FOCUS_DOWN;
   4377                         }
   4378                         break;
   4379                     case KeyEvent.KEYCODE_TAB:
   4380                         if (event.hasNoModifiers()) {
   4381                             direction = View.FOCUS_FORWARD;
   4382                         } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
   4383                             direction = View.FOCUS_BACKWARD;
   4384                         }
   4385                         break;
   4386                 }
   4387                 if (direction != 0) {
   4388                     View focused = mView.findFocus();
   4389                     if (focused != null) {
   4390                         View v = focused.focusSearch(direction);
   4391                         if (v != null && v != focused) {
   4392                             // do the math the get the interesting rect
   4393                             // of previous focused into the coord system of
   4394                             // newly focused view
   4395                             focused.getFocusedRect(mTempRect);
   4396                             if (mView instanceof ViewGroup) {
   4397                                 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
   4398                                         focused, mTempRect);
   4399                                 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
   4400                                         v, mTempRect);
   4401                             }
   4402                             if (v.requestFocus(direction, mTempRect)) {
   4403                                 playSoundEffect(SoundEffectConstants
   4404                                         .getContantForFocusDirection(direction));
   4405                                 return FINISH_HANDLED;
   4406                             }
   4407                         }
   4408 
   4409                         // Give the focused view a last chance to handle the dpad key.
   4410                         if (mView.dispatchUnhandledMove(focused, direction)) {
   4411                             return FINISH_HANDLED;
   4412                         }
   4413                     } else {
   4414                         // find the best view to give focus to in this non-touch-mode with no-focus
   4415                         View v = focusSearch(null, direction);
   4416                         if (v != null && v.requestFocus(direction)) {
   4417                             return FINISH_HANDLED;
   4418                         }
   4419                     }
   4420                 }
   4421             }
   4422             return FORWARD;
   4423         }
   4424 
   4425         private int processPointerEvent(QueuedInputEvent q) {
   4426             final MotionEvent event = (MotionEvent)q.mEvent;
   4427 
   4428             mAttachInfo.mUnbufferedDispatchRequested = false;
   4429             final View eventTarget =
   4430                     (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
   4431                             mCapturingView : mView;
   4432             mAttachInfo.mHandlingPointerEvent = true;
   4433             boolean handled = eventTarget.dispatchPointerEvent(event);
   4434             maybeUpdatePointerIcon(event);
   4435             mAttachInfo.mHandlingPointerEvent = false;
   4436             if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
   4437                 mUnbufferedInputDispatch = true;
   4438                 if (mConsumeBatchedInputScheduled) {
   4439                     scheduleConsumeBatchedInputImmediately();
   4440                 }
   4441             }
   4442             return handled ? FINISH_HANDLED : FORWARD;
   4443         }
   4444 
   4445         private void maybeUpdatePointerIcon(MotionEvent event) {
   4446             if (event.getPointerCount() == 1 && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
   4447                 if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
   4448                         || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
   4449                     // Other apps or the window manager may change the icon type outside of
   4450                     // this app, therefore the icon type has to be reset on enter/exit event.
   4451                     mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
   4452                 }
   4453 
   4454                 if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
   4455                     if (!updatePointerIcon(event) &&
   4456                             event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
   4457                         mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
   4458                     }
   4459                 }
   4460             }
   4461         }
   4462 
   4463         private int processTrackballEvent(QueuedInputEvent q) {
   4464             final MotionEvent event = (MotionEvent)q.mEvent;
   4465 
   4466             if (mView.dispatchTrackballEvent(event)) {
   4467                 return FINISH_HANDLED;
   4468             }
   4469             return FORWARD;
   4470         }
   4471 
   4472         private int processGenericMotionEvent(QueuedInputEvent q) {
   4473             final MotionEvent event = (MotionEvent)q.mEvent;
   4474 
   4475             // Deliver the event to the view.
   4476             if (mView.dispatchGenericMotionEvent(event)) {
   4477                 return FINISH_HANDLED;
   4478             }
   4479             return FORWARD;
   4480         }
   4481     }
   4482 
   4483     private void resetPointerIcon(MotionEvent event) {
   4484         mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
   4485         updatePointerIcon(event);
   4486     }
   4487 
   4488     private boolean updatePointerIcon(MotionEvent event) {
   4489         final int pointerIndex = 0;
   4490         final float x = event.getX(pointerIndex);
   4491         final float y = event.getY(pointerIndex);
   4492         if (mView == null) {
   4493             // E.g. click outside a popup to dismiss it
   4494             Slog.d(mTag, "updatePointerIcon called after view was removed");
   4495             return false;
   4496         }
   4497         if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
   4498             // E.g. when moving window divider with mouse
   4499             Slog.d(mTag, "updatePointerIcon called with position out of bounds");
   4500             return false;
   4501         }
   4502         final PointerIcon pointerIcon = mView.onResolvePointerIcon(event, pointerIndex);
   4503         final int pointerType = (pointerIcon != null) ?
   4504                 pointerIcon.getType() : PointerIcon.TYPE_DEFAULT;
   4505 
   4506         if (mPointerIconType != pointerType) {
   4507             mPointerIconType = pointerType;
   4508             if (mPointerIconType != PointerIcon.TYPE_CUSTOM) {
   4509                 mCustomPointerIcon = null;
   4510                 InputManager.getInstance().setPointerIconType(pointerType);
   4511                 return true;
   4512             }
   4513         }
   4514         if (mPointerIconType == PointerIcon.TYPE_CUSTOM &&
   4515                 !pointerIcon.equals(mCustomPointerIcon)) {
   4516             mCustomPointerIcon = pointerIcon;
   4517             InputManager.getInstance().setCustomPointerIcon(mCustomPointerIcon);
   4518         }
   4519         return true;
   4520     }
   4521 
   4522     /**
   4523      * Performs synthesis of new input events from unhandled input events.
   4524      */
   4525     final class SyntheticInputStage extends InputStage {
   4526         private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
   4527         private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
   4528         private final SyntheticTouchNavigationHandler mTouchNavigation =
   4529                 new SyntheticTouchNavigationHandler();
   4530         private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
   4531 
   4532         public SyntheticInputStage() {
   4533             super(null);
   4534         }
   4535 
   4536         @Override
   4537         protected int onProcess(QueuedInputEvent q) {
   4538             q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
   4539             if (q.mEvent instanceof MotionEvent) {
   4540                 final MotionEvent event = (MotionEvent)q.mEvent;
   4541                 final int source = event.getSource();
   4542                 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
   4543                     mTrackball.process(event);
   4544                     return FINISH_HANDLED;
   4545                 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
   4546                     mJoystick.process(event);
   4547                     return FINISH_HANDLED;
   4548                 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
   4549                         == InputDevice.SOURCE_TOUCH_NAVIGATION) {
   4550                     mTouchNavigation.process(event);
   4551                     return FINISH_HANDLED;
   4552                 }
   4553             } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
   4554                 mKeyboard.process((KeyEvent)q.mEvent);
   4555                 return FINISH_HANDLED;
   4556             }
   4557 
   4558             return FORWARD;
   4559         }
   4560 
   4561         @Override
   4562         protected void onDeliverToNext(QueuedInputEvent q) {
   4563             if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
   4564                 // Cancel related synthetic events if any prior stage has handled the event.
   4565                 if (q.mEvent instanceof MotionEvent) {
   4566                     final MotionEvent event = (MotionEvent)q.mEvent;
   4567                     final int source = event.getSource();
   4568                     if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
   4569                         mTrackball.cancel(event);
   4570                     } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
   4571                         mJoystick.cancel(event);
   4572                     } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
   4573                             == InputDevice.SOURCE_TOUCH_NAVIGATION) {
   4574                         mTouchNavigation.cancel(event);
   4575                     }
   4576                 }
   4577             }
   4578             super.onDeliverToNext(q);
   4579         }
   4580     }
   4581 
   4582     /**
   4583      * Creates dpad events from unhandled trackball movements.
   4584      */
   4585     final class SyntheticTrackballHandler {
   4586         private final TrackballAxis mX = new TrackballAxis();
   4587         private final TrackballAxis mY = new TrackballAxis();
   4588         private long mLastTime;
   4589 
   4590         public void process(MotionEvent event) {
   4591             // Translate the trackball event into DPAD keys and try to deliver those.
   4592             long curTime = SystemClock.uptimeMillis();
   4593             if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
   4594                 // It has been too long since the last movement,
   4595                 // so restart at the beginning.
   4596                 mX.reset(0);
   4597                 mY.reset(0);
   4598                 mLastTime = curTime;
   4599             }
   4600 
   4601             final int action = event.getAction();
   4602             final int metaState = event.getMetaState();
   4603             switch (action) {
   4604                 case MotionEvent.ACTION_DOWN:
   4605                     mX.reset(2);
   4606                     mY.reset(2);
   4607                     enqueueInputEvent(new KeyEvent(curTime, curTime,
   4608                             KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
   4609                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   4610                             InputDevice.SOURCE_KEYBOARD));
   4611                     break;
   4612                 case MotionEvent.ACTION_UP:
   4613                     mX.reset(2);
   4614                     mY.reset(2);
   4615                     enqueueInputEvent(new KeyEvent(curTime, curTime,
   4616                             KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
   4617                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   4618                             InputDevice.SOURCE_KEYBOARD));
   4619                     break;
   4620             }
   4621 
   4622             if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
   4623                     + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
   4624                     + " move=" + event.getX()
   4625                     + " / Y=" + mY.position + " step="
   4626                     + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
   4627                     + " move=" + event.getY());
   4628             final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
   4629             final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
   4630 
   4631             // Generate DPAD events based on the trackball movement.
   4632             // We pick the axis that has moved the most as the direction of
   4633             // the DPAD.  When we generate DPAD events for one axis, then the
   4634             // other axis is reset -- we don't want to perform DPAD jumps due
   4635             // to slight movements in the trackball when making major movements
   4636             // along the other axis.
   4637             int keycode = 0;
   4638             int movement = 0;
   4639             float accel = 1;
   4640             if (xOff > yOff) {
   4641                 movement = mX.generate();
   4642                 if (movement != 0) {
   4643                     keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
   4644                             : KeyEvent.KEYCODE_DPAD_LEFT;
   4645                     accel = mX.acceleration;
   4646                     mY.reset(2);
   4647                 }
   4648             } else if (yOff > 0) {
   4649                 movement = mY.generate();
   4650                 if (movement != 0) {
   4651                     keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
   4652                             : KeyEvent.KEYCODE_DPAD_UP;
   4653                     accel = mY.acceleration;
   4654                     mX.reset(2);
   4655                 }
   4656             }
   4657 
   4658             if (keycode != 0) {
   4659                 if (movement < 0) movement = -movement;
   4660                 int accelMovement = (int)(movement * accel);
   4661                 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
   4662                         + " accelMovement=" + accelMovement
   4663                         + " accel=" + accel);
   4664                 if (accelMovement > movement) {
   4665                     if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
   4666                             + keycode);
   4667                     movement--;
   4668                     int repeatCount = accelMovement - movement;
   4669                     enqueueInputEvent(new KeyEvent(curTime, curTime,
   4670                             KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
   4671                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   4672                             InputDevice.SOURCE_KEYBOARD));
   4673                 }
   4674                 while (movement > 0) {
   4675                     if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
   4676                             + keycode);
   4677                     movement--;
   4678                     curTime = SystemClock.uptimeMillis();
   4679                     enqueueInputEvent(new KeyEvent(curTime, curTime,
   4680                             KeyEvent.ACTION_DOWN, keycode, 0, metaState,
   4681                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   4682                             InputDevice.SOURCE_KEYBOARD));
   4683                     enqueueInputEvent(new KeyEvent(curTime, curTime,
   4684                             KeyEvent.ACTION_UP, keycode, 0, metaState,
   4685                             KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
   4686                             InputDevice.SOURCE_KEYBOARD));
   4687                 }
   4688                 mLastTime = curTime;
   4689             }
   4690         }
   4691 
   4692         public void cancel(MotionEvent event) {
   4693             mLastTime = Integer.MIN_VALUE;
   4694 
   4695             // If we reach this, we consumed a trackball event.
   4696             // Because we will not translate the trackball event into a key event,
   4697             // touch mode will not exit, so we exit touch mode here.
   4698             if (mView != null && mAdded) {
   4699                 ensureTouchMode(false);
   4700             }
   4701         }
   4702     }
   4703 
   4704     /**
   4705      * Maintains state information for a single trackball axis, generating
   4706      * discrete (DPAD) movements based on raw trackball motion.
   4707      */
   4708     static final class TrackballAxis {
   4709         /**
   4710          * The maximum amount of acceleration we will apply.
   4711          */
   4712         static final float MAX_ACCELERATION = 20;
   4713 
   4714         /**
   4715          * The maximum amount of time (in milliseconds) between events in order
   4716          * for us to consider the user to be doing fast trackball movements,
   4717          * and thus apply an acceleration.
   4718          */
   4719         static final long FAST_MOVE_TIME = 150;
   4720 
   4721         /**
   4722          * Scaling factor to the time (in milliseconds) between events to how
   4723          * much to multiple/divide the current acceleration.  When movement
   4724          * is < FAST_MOVE_TIME this multiplies the acceleration; when >
   4725          * FAST_MOVE_TIME it divides it.
   4726          */
   4727         static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
   4728 
   4729         static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
   4730         static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
   4731         static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
   4732 
   4733         float position;
   4734         float acceleration = 1;
   4735         long lastMoveTime = 0;
   4736         int step;
   4737         int dir;
   4738         int nonAccelMovement;
   4739 
   4740         void reset(int _step) {
   4741             position = 0;
   4742             acceleration = 1;
   4743             lastMoveTime = 0;
   4744             step = _step;
   4745             dir = 0;
   4746         }
   4747 
   4748         /**
   4749          * Add trackball movement into the state.  If the direction of movement
   4750          * has been reversed, the state is reset before adding the
   4751          * movement (so that you don't have to compensate for any previously
   4752          * collected movement before see the result of the movement in the
   4753          * new direction).
   4754          *
   4755          * @return Returns the absolute value of the amount of movement
   4756          * collected so far.
   4757          */
   4758         float collect(float off, long time, String axis) {
   4759             long normTime;
   4760             if (off > 0) {
   4761                 normTime = (long)(off * FAST_MOVE_TIME);
   4762                 if (dir < 0) {
   4763                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
   4764                     position = 0;
   4765                     step = 0;
   4766                     acceleration = 1;
   4767                     lastMoveTime = 0;
   4768                 }
   4769                 dir = 1;
   4770             } else if (off < 0) {
   4771                 normTime = (long)((-off) * FAST_MOVE_TIME);
   4772                 if (dir > 0) {
   4773                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
   4774                     position = 0;
   4775                     step = 0;
   4776                     acceleration = 1;
   4777                     lastMoveTime = 0;
   4778                 }
   4779                 dir = -1;
   4780             } else {
   4781                 normTime = 0;
   4782             }
   4783 
   4784             // The number of milliseconds between each movement that is
   4785             // considered "normal" and will not result in any acceleration
   4786             // or deceleration, scaled by the offset we have here.
   4787             if (normTime > 0) {
   4788                 long delta = time - lastMoveTime;
   4789                 lastMoveTime = time;
   4790                 float acc = acceleration;
   4791                 if (delta < normTime) {
   4792                     // The user is scrolling rapidly, so increase acceleration.
   4793                     float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
   4794                     if (scale > 1) acc *= scale;
   4795                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
   4796                             + off + " normTime=" + normTime + " delta=" + delta
   4797                             + " scale=" + scale + " acc=" + acc);
   4798                     acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
   4799                 } else {
   4800                     // The user is scrolling slowly, so decrease acceleration.
   4801                     float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
   4802                     if (scale > 1) acc /= scale;
   4803                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
   4804                             + off + " normTime=" + normTime + " delta=" + delta
   4805                             + " scale=" + scale + " acc=" + acc);
   4806                     acceleration = acc > 1 ? acc : 1;
   4807                 }
   4808             }
   4809             position += off;
   4810             return Math.abs(position);
   4811         }
   4812 
   4813         /**
   4814          * Generate the number of discrete movement events appropriate for
   4815          * the currently collected trackball movement.
   4816          *
   4817          * @return Returns the number of discrete movements, either positive
   4818          * or negative, or 0 if there is not enough trackball movement yet
   4819          * for a discrete movement.
   4820          */
   4821         int generate() {
   4822             int movement = 0;
   4823             nonAccelMovement = 0;
   4824             do {
   4825                 final int dir = position >= 0 ? 1 : -1;
   4826                 switch (step) {
   4827                     // If we are going to execute the first step, then we want
   4828                     // to do this as soon as possible instead of waiting for
   4829                     // a full movement, in order to make things look responsive.
   4830                     case 0:
   4831                         if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
   4832                             return movement;
   4833                         }
   4834                         movement += dir;
   4835                         nonAccelMovement += dir;
   4836                         step = 1;
   4837                         break;
   4838                     // If we have generated the first movement, then we need
   4839                     // to wait for the second complete trackball motion before
   4840                     // generating the second discrete movement.
   4841                     case 1:
   4842                         if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
   4843                             return movement;
   4844                         }
   4845                         movement += dir;
   4846                         nonAccelMovement += dir;
   4847                         position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
   4848                         step = 2;
   4849                         break;
   4850                     // After the first two, we generate discrete movements
   4851                     // consistently with the trackball, applying an acceleration
   4852                     // if the trackball is moving quickly.  This is a simple
   4853                     // acceleration on top of what we already compute based
   4854                     // on how quickly the wheel is being turned, to apply
   4855                     // a longer increasing acceleration to continuous movement
   4856                     // in one direction.
   4857                     default:
   4858                         if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
   4859                             return movement;
   4860                         }
   4861                         movement += dir;
   4862                         position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
   4863                         float acc = acceleration;
   4864                         acc *= 1.1f;
   4865                         acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
   4866                         break;
   4867                 }
   4868             } while (true);
   4869         }
   4870     }
   4871 
   4872     /**
   4873      * Creates dpad events from unhandled joystick movements.
   4874      */
   4875     final class SyntheticJoystickHandler extends Handler {
   4876         private final static String TAG = "SyntheticJoystickHandler";
   4877         private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
   4878         private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
   4879 
   4880         private int mLastXDirection;
   4881         private int mLastYDirection;
   4882         private int mLastXKeyCode;
   4883         private int mLastYKeyCode;
   4884 
   4885         public SyntheticJoystickHandler() {
   4886             super(true);
   4887         }
   4888 
   4889         @Override
   4890         public void handleMessage(Message msg) {
   4891             switch (msg.what) {
   4892                 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
   4893                 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
   4894                     KeyEvent oldEvent = (KeyEvent)msg.obj;
   4895                     KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
   4896                             SystemClock.uptimeMillis(),
   4897                             oldEvent.getRepeatCount() + 1);
   4898                     if (mAttachInfo.mHasWindowFocus) {
   4899                         enqueueInputEvent(e);
   4900                         Message m = obtainMessage(msg.what, e);
   4901                         m.setAsynchronous(true);
   4902                         sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
   4903                     }
   4904                 } break;
   4905             }
   4906         }
   4907 
   4908         public void process(MotionEvent event) {
   4909             switch(event.getActionMasked()) {
   4910             case MotionEvent.ACTION_CANCEL:
   4911                 cancel(event);
   4912                 break;
   4913             case MotionEvent.ACTION_MOVE:
   4914                 update(event, true);
   4915                 break;
   4916             default:
   4917                 Log.w(mTag, "Unexpected action: " + event.getActionMasked());
   4918             }
   4919         }
   4920 
   4921         private void cancel(MotionEvent event) {
   4922             removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
   4923             removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
   4924             update(event, false);
   4925         }
   4926 
   4927         private void update(MotionEvent event, boolean synthesizeNewKeys) {
   4928             final long time = event.getEventTime();
   4929             final int metaState = event.getMetaState();
   4930             final int deviceId = event.getDeviceId();
   4931             final int source = event.getSource();
   4932 
   4933             int xDirection = joystickAxisValueToDirection(
   4934                     event.getAxisValue(MotionEvent.AXIS_HAT_X));
   4935             if (xDirection == 0) {
   4936                 xDirection = joystickAxisValueToDirection(event.getX());
   4937             }
   4938 
   4939             int yDirection = joystickAxisValueToDirection(
   4940                     event.getAxisValue(MotionEvent.AXIS_HAT_Y));
   4941             if (yDirection == 0) {
   4942                 yDirection = joystickAxisValueToDirection(event.getY());
   4943             }
   4944 
   4945             if (xDirection != mLastXDirection) {
   4946                 if (mLastXKeyCode != 0) {
   4947                     removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
   4948                     enqueueInputEvent(new KeyEvent(time, time,
   4949                             KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
   4950                             deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
   4951                     mLastXKeyCode = 0;
   4952                 }
   4953 
   4954                 mLastXDirection = xDirection;
   4955 
   4956                 if (xDirection != 0 && synthesizeNewKeys) {
   4957                     mLastXKeyCode = xDirection > 0
   4958                             ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
   4959                     final KeyEvent e = new KeyEvent(time, time,
   4960                             KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
   4961                             deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
   4962                     enqueueInputEvent(e);
   4963                     Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
   4964                     m.setAsynchronous(true);
   4965                     sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
   4966                 }
   4967             }
   4968 
   4969             if (yDirection != mLastYDirection) {
   4970                 if (mLastYKeyCode != 0) {
   4971                     removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
   4972                     enqueueInputEvent(new KeyEvent(time, time,
   4973                             KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
   4974                             deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
   4975                     mLastYKeyCode = 0;
   4976                 }
   4977 
   4978                 mLastYDirection = yDirection;
   4979 
   4980                 if (yDirection != 0 && synthesizeNewKeys) {
   4981                     mLastYKeyCode = yDirection > 0
   4982                             ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
   4983                     final KeyEvent e = new KeyEvent(time, time,
   4984                             KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
   4985                             deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
   4986                     enqueueInputEvent(e);
   4987                     Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
   4988                     m.setAsynchronous(true);
   4989                     sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
   4990                 }
   4991             }
   4992         }
   4993 
   4994         private int joystickAxisValueToDirection(float value) {
   4995             if (value >= 0.5f) {
   4996                 return 1;
   4997             } else if (value <= -0.5f) {
   4998                 return -1;
   4999             } else {
   5000                 return 0;
   5001             }
   5002         }
   5003     }
   5004 
   5005     /**
   5006      * Creates dpad events from unhandled touch navigation movements.
   5007      */
   5008     final class SyntheticTouchNavigationHandler extends Handler {
   5009         private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
   5010         private static final boolean LOCAL_DEBUG = false;
   5011 
   5012         // Assumed nominal width and height in millimeters of a touch navigation pad,
   5013         // if no resolution information is available from the input system.
   5014         private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
   5015         private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
   5016 
   5017         /* TODO: These constants should eventually be moved to ViewConfiguration. */
   5018 
   5019         // The nominal distance traveled to move by one unit.
   5020         private static final int TICK_DISTANCE_MILLIMETERS = 12;
   5021 
   5022         // Minimum and maximum fling velocity in ticks per second.
   5023         // The minimum velocity should be set such that we perform enough ticks per
   5024         // second that the fling appears to be fluid.  For example, if we set the minimum
   5025         // to 2 ticks per second, then there may be up to half a second delay between the next
   5026         // to last and last ticks which is noticeably discrete and jerky.  This value should
   5027         // probably not be set to anything less than about 4.
   5028         // If fling accuracy is a problem then consider tuning the tick distance instead.
   5029         private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
   5030         private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
   5031 
   5032         // Fling velocity decay factor applied after each new key is emitted.
   5033         // This parameter controls the deceleration and overall duration of the fling.
   5034         // The fling stops automatically when its velocity drops below the minimum
   5035         // fling velocity defined above.
   5036         private static final float FLING_TICK_DECAY = 0.8f;
   5037 
   5038         /* The input device that we are tracking. */
   5039 
   5040         private int mCurrentDeviceId = -1;
   5041         private int mCurrentSource;
   5042         private boolean mCurrentDeviceSupported;
   5043 
   5044         /* Configuration for the current input device. */
   5045 
   5046         // The scaled tick distance.  A movement of this amount should generally translate
   5047         // into a single dpad event in a given direction.
   5048         private float mConfigTickDistance;
   5049 
   5050         // The minimum and maximum scaled fling velocity.
   5051         private float mConfigMinFlingVelocity;
   5052         private float mConfigMaxFlingVelocity;
   5053 
   5054         /* Tracking state. */
   5055 
   5056         // The velocity tracker for detecting flings.
   5057         private VelocityTracker mVelocityTracker;
   5058 
   5059         // The active pointer id, or -1 if none.
   5060         private int mActivePointerId = -1;
   5061 
   5062         // Location where tracking started.
   5063         private float mStartX;
   5064         private float mStartY;
   5065 
   5066         // Most recently observed position.
   5067         private float mLastX;
   5068         private float mLastY;
   5069 
   5070         // Accumulated movement delta since the last direction key was sent.
   5071         private float mAccumulatedX;
   5072         private float mAccumulatedY;
   5073 
   5074         // Set to true if any movement was delivered to the app.
   5075         // Implies that tap slop was exceeded.
   5076         private boolean mConsumedMovement;
   5077 
   5078         // The most recently sent key down event.
   5079         // The keycode remains set until the direction changes or a fling ends
   5080         // so that repeated key events may be generated as required.
   5081         private long mPendingKeyDownTime;
   5082         private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
   5083         private int mPendingKeyRepeatCount;
   5084         private int mPendingKeyMetaState;
   5085 
   5086         // The current fling velocity while a fling is in progress.
   5087         private boolean mFlinging;
   5088         private float mFlingVelocity;
   5089 
   5090         public SyntheticTouchNavigationHandler() {
   5091             super(true);
   5092         }
   5093 
   5094         public void process(MotionEvent event) {
   5095             // Update the current device information.
   5096             final long time = event.getEventTime();
   5097             final int deviceId = event.getDeviceId();
   5098             final int source = event.getSource();
   5099             if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
   5100                 finishKeys(time);
   5101                 finishTracking(time);
   5102                 mCurrentDeviceId = deviceId;
   5103                 mCurrentSource = source;
   5104                 mCurrentDeviceSupported = false;
   5105                 InputDevice device = event.getDevice();
   5106                 if (device != null) {
   5107                     // In order to support an input device, we must know certain
   5108                     // characteristics about it, such as its size and resolution.
   5109                     InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
   5110                     InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
   5111                     if (xRange != null && yRange != null) {
   5112                         mCurrentDeviceSupported = true;
   5113 
   5114                         // Infer the resolution if it not actually known.
   5115                         float xRes = xRange.getResolution();
   5116                         if (xRes <= 0) {
   5117                             xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
   5118                         }
   5119                         float yRes = yRange.getResolution();
   5120                         if (yRes <= 0) {
   5121                             yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
   5122                         }
   5123                         float nominalRes = (xRes + yRes) * 0.5f;
   5124 
   5125                         // Precompute all of the configuration thresholds we will need.
   5126                         mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
   5127                         mConfigMinFlingVelocity =
   5128                                 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
   5129                         mConfigMaxFlingVelocity =
   5130                                 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
   5131 
   5132                         if (LOCAL_DEBUG) {
   5133                             Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
   5134                                     + " (" + Integer.toHexString(mCurrentSource) + "): "
   5135                                     + ", mConfigTickDistance=" + mConfigTickDistance
   5136                                     + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
   5137                                     + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
   5138                         }
   5139                     }
   5140                 }
   5141             }
   5142             if (!mCurrentDeviceSupported) {
   5143                 return;
   5144             }
   5145 
   5146             // Handle the event.
   5147             final int action = event.getActionMasked();
   5148             switch (action) {
   5149                 case MotionEvent.ACTION_DOWN: {
   5150                     boolean caughtFling = mFlinging;
   5151                     finishKeys(time);
   5152                     finishTracking(time);
   5153                     mActivePointerId = event.getPointerId(0);
   5154                     mVelocityTracker = VelocityTracker.obtain();
   5155                     mVelocityTracker.addMovement(event);
   5156                     mStartX = event.getX();
   5157                     mStartY = event.getY();
   5158                     mLastX = mStartX;
   5159                     mLastY = mStartY;
   5160                     mAccumulatedX = 0;
   5161                     mAccumulatedY = 0;
   5162 
   5163                     // If we caught a fling, then pretend that the tap slop has already
   5164                     // been exceeded to suppress taps whose only purpose is to stop the fling.
   5165                     mConsumedMovement = caughtFling;
   5166                     break;
   5167                 }
   5168 
   5169                 case MotionEvent.ACTION_MOVE:
   5170                 case MotionEvent.ACTION_UP: {
   5171                     if (mActivePointerId < 0) {
   5172                         break;
   5173                     }
   5174                     final int index = event.findPointerIndex(mActivePointerId);
   5175                     if (index < 0) {
   5176                         finishKeys(time);
   5177                         finishTracking(time);
   5178                         break;
   5179                     }
   5180 
   5181                     mVelocityTracker.addMovement(event);
   5182                     final float x = event.getX(index);
   5183                     final float y = event.getY(index);
   5184                     mAccumulatedX += x - mLastX;
   5185                     mAccumulatedY += y - mLastY;
   5186                     mLastX = x;
   5187                     mLastY = y;
   5188 
   5189                     // Consume any accumulated movement so far.
   5190                     final int metaState = event.getMetaState();
   5191                     consumeAccumulatedMovement(time, metaState);
   5192 
   5193                     // Detect taps and flings.
   5194                     if (action == MotionEvent.ACTION_UP) {
   5195                         if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
   5196                             // It might be a fling.
   5197                             mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
   5198                             final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
   5199                             final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
   5200                             if (!startFling(time, vx, vy)) {
   5201                                 finishKeys(time);
   5202                             }
   5203                         }
   5204                         finishTracking(time);
   5205                     }
   5206                     break;
   5207                 }
   5208 
   5209                 case MotionEvent.ACTION_CANCEL: {
   5210                     finishKeys(time);
   5211                     finishTracking(time);
   5212                     break;
   5213                 }
   5214             }
   5215         }
   5216 
   5217         public void cancel(MotionEvent event) {
   5218             if (mCurrentDeviceId == event.getDeviceId()
   5219                     && mCurrentSource == event.getSource()) {
   5220                 final long time = event.getEventTime();
   5221                 finishKeys(time);
   5222                 finishTracking(time);
   5223             }
   5224         }
   5225 
   5226         private void finishKeys(long time) {
   5227             cancelFling();
   5228             sendKeyUp(time);
   5229         }
   5230 
   5231         private void finishTracking(long time) {
   5232             if (mActivePointerId >= 0) {
   5233                 mActivePointerId = -1;
   5234                 mVelocityTracker.recycle();
   5235                 mVelocityTracker = null;
   5236             }
   5237         }
   5238 
   5239         private void consumeAccumulatedMovement(long time, int metaState) {
   5240             final float absX = Math.abs(mAccumulatedX);
   5241             final float absY = Math.abs(mAccumulatedY);
   5242             if (absX >= absY) {
   5243                 if (absX >= mConfigTickDistance) {
   5244                     mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
   5245                             KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
   5246                     mAccumulatedY = 0;
   5247                     mConsumedMovement = true;
   5248                 }
   5249             } else {
   5250                 if (absY >= mConfigTickDistance) {
   5251                     mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
   5252                             KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
   5253                     mAccumulatedX = 0;
   5254                     mConsumedMovement = true;
   5255                 }
   5256             }
   5257         }
   5258 
   5259         private float consumeAccumulatedMovement(long time, int metaState,
   5260                 float accumulator, int negativeKeyCode, int positiveKeyCode) {
   5261             while (accumulator <= -mConfigTickDistance) {
   5262                 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
   5263                 accumulator += mConfigTickDistance;
   5264             }
   5265             while (accumulator >= mConfigTickDistance) {
   5266                 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
   5267                 accumulator -= mConfigTickDistance;
   5268             }
   5269             return accumulator;
   5270         }
   5271 
   5272         private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
   5273             if (mPendingKeyCode != keyCode) {
   5274                 sendKeyUp(time);
   5275                 mPendingKeyDownTime = time;
   5276                 mPendingKeyCode = keyCode;
   5277                 mPendingKeyRepeatCount = 0;
   5278             } else {
   5279                 mPendingKeyRepeatCount += 1;
   5280             }
   5281             mPendingKeyMetaState = metaState;
   5282 
   5283             // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
   5284             // but it doesn't quite make sense when simulating the events in this way.
   5285             if (LOCAL_DEBUG) {
   5286                 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
   5287                         + ", repeatCount=" + mPendingKeyRepeatCount
   5288                         + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
   5289             }
   5290             enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
   5291                     KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
   5292                     mPendingKeyMetaState, mCurrentDeviceId,
   5293                     KeyEvent.FLAG_FALLBACK, mCurrentSource));
   5294         }
   5295 
   5296         private void sendKeyUp(long time) {
   5297             if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
   5298                 if (LOCAL_DEBUG) {
   5299                     Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
   5300                             + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
   5301                 }
   5302                 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
   5303                         KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
   5304                         mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
   5305                         mCurrentSource));
   5306                 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
   5307             }
   5308         }
   5309 
   5310         private boolean startFling(long time, float vx, float vy) {
   5311             if (LOCAL_DEBUG) {
   5312                 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
   5313                         + ", min=" + mConfigMinFlingVelocity);
   5314             }
   5315 
   5316             // Flings must be oriented in the same direction as the preceding movements.
   5317             switch (mPendingKeyCode) {
   5318                 case KeyEvent.KEYCODE_DPAD_LEFT:
   5319                     if (-vx >= mConfigMinFlingVelocity
   5320                             && Math.abs(vy) < mConfigMinFlingVelocity) {
   5321                         mFlingVelocity = -vx;
   5322                         break;
   5323                     }
   5324                     return false;
   5325 
   5326                 case KeyEvent.KEYCODE_DPAD_RIGHT:
   5327                     if (vx >= mConfigMinFlingVelocity
   5328                             && Math.abs(vy) < mConfigMinFlingVelocity) {
   5329                         mFlingVelocity = vx;
   5330                         break;
   5331                     }
   5332                     return false;
   5333 
   5334                 case KeyEvent.KEYCODE_DPAD_UP:
   5335                     if (-vy >= mConfigMinFlingVelocity
   5336                             && Math.abs(vx) < mConfigMinFlingVelocity) {
   5337                         mFlingVelocity = -vy;
   5338                         break;
   5339                     }
   5340                     return false;
   5341 
   5342                 case KeyEvent.KEYCODE_DPAD_DOWN:
   5343                     if (vy >= mConfigMinFlingVelocity
   5344                             && Math.abs(vx) < mConfigMinFlingVelocity) {
   5345                         mFlingVelocity = vy;
   5346                         break;
   5347                     }
   5348                     return false;
   5349             }
   5350 
   5351             // Post the first fling event.
   5352             mFlinging = postFling(time);
   5353             return mFlinging;
   5354         }
   5355 
   5356         private boolean postFling(long time) {
   5357             // The idea here is to estimate the time when the pointer would have
   5358             // traveled one tick distance unit given the current fling velocity.
   5359             // This effect creates continuity of motion.
   5360             if (mFlingVelocity >= mConfigMinFlingVelocity) {
   5361                 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
   5362                 postAtTime(mFlingRunnable, time + delay);
   5363                 if (LOCAL_DEBUG) {
   5364                     Log.d(LOCAL_TAG, "Posted fling: velocity="
   5365                             + mFlingVelocity + ", delay=" + delay
   5366                             + ", keyCode=" + mPendingKeyCode);
   5367                 }
   5368                 return true;
   5369             }
   5370             return false;
   5371         }
   5372 
   5373         private void cancelFling() {
   5374             if (mFlinging) {
   5375                 removeCallbacks(mFlingRunnable);
   5376                 mFlinging = false;
   5377             }
   5378         }
   5379 
   5380         private final Runnable mFlingRunnable = new Runnable() {
   5381             @Override
   5382             public void run() {
   5383                 final long time = SystemClock.uptimeMillis();
   5384                 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
   5385                 mFlingVelocity *= FLING_TICK_DECAY;
   5386                 if (!postFling(time)) {
   5387                     mFlinging = false;
   5388                     finishKeys(time);
   5389                 }
   5390             }
   5391         };
   5392     }
   5393 
   5394     final class SyntheticKeyboardHandler {
   5395         public void process(KeyEvent event) {
   5396             if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
   5397                 return;
   5398             }
   5399 
   5400             final KeyCharacterMap kcm = event.getKeyCharacterMap();
   5401             final int keyCode = event.getKeyCode();
   5402             final int metaState = event.getMetaState();
   5403 
   5404             // Check for fallback actions specified by the key character map.
   5405             KeyCharacterMap.FallbackAction fallbackAction =
   5406                     kcm.getFallbackAction(keyCode, metaState);
   5407             if (fallbackAction != null) {
   5408                 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
   5409                 KeyEvent fallbackEvent = KeyEvent.obtain(
   5410                         event.getDownTime(), event.getEventTime(),
   5411                         event.getAction(), fallbackAction.keyCode,
   5412                         event.getRepeatCount(), fallbackAction.metaState,
   5413                         event.getDeviceId(), event.getScanCode(),
   5414                         flags, event.getSource(), null);
   5415                 fallbackAction.recycle();
   5416                 enqueueInputEvent(fallbackEvent);
   5417             }
   5418         }
   5419     }
   5420 
   5421     /**
   5422      * Returns true if the key is used for keyboard navigation.
   5423      * @param keyEvent The key event.
   5424      * @return True if the key is used for keyboard navigation.
   5425      */
   5426     private static boolean isNavigationKey(KeyEvent keyEvent) {
   5427         switch (keyEvent.getKeyCode()) {
   5428         case KeyEvent.KEYCODE_DPAD_LEFT:
   5429         case KeyEvent.KEYCODE_DPAD_RIGHT:
   5430         case KeyEvent.KEYCODE_DPAD_UP:
   5431         case KeyEvent.KEYCODE_DPAD_DOWN:
   5432         case KeyEvent.KEYCODE_DPAD_CENTER:
   5433         case KeyEvent.KEYCODE_PAGE_UP:
   5434         case KeyEvent.KEYCODE_PAGE_DOWN:
   5435         case KeyEvent.KEYCODE_MOVE_HOME:
   5436         case KeyEvent.KEYCODE_MOVE_END:
   5437         case KeyEvent.KEYCODE_TAB:
   5438         case KeyEvent.KEYCODE_SPACE:
   5439         case KeyEvent.KEYCODE_ENTER:
   5440             return true;
   5441         }
   5442         return false;
   5443     }
   5444 
   5445     /**
   5446      * Returns true if the key is used for typing.
   5447      * @param keyEvent The key event.
   5448      * @return True if the key is used for typing.
   5449      */
   5450     private static boolean isTypingKey(KeyEvent keyEvent) {
   5451         return keyEvent.getUnicodeChar() > 0;
   5452     }
   5453 
   5454     /**
   5455      * See if the key event means we should leave touch mode (and leave touch mode if so).
   5456      * @param event The key event.
   5457      * @return Whether this key event should be consumed (meaning the act of
   5458      *   leaving touch mode alone is considered the event).
   5459      */
   5460     private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
   5461         // Only relevant in touch mode.
   5462         if (!mAttachInfo.mInTouchMode) {
   5463             return false;
   5464         }
   5465 
   5466         // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
   5467         final int action = event.getAction();
   5468         if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
   5469             return false;
   5470         }
   5471 
   5472         // Don't leave touch mode if the IME told us not to.
   5473         if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
   5474             return false;
   5475         }
   5476 
   5477         // If the key can be used for keyboard navigation then leave touch mode
   5478         // and select a focused view if needed (in ensureTouchMode).
   5479         // When a new focused view is selected, we consume the navigation key because
   5480         // navigation doesn't make much sense unless a view already has focus so
   5481         // the key's purpose is to set focus.
   5482         if (isNavigationKey(event)) {
   5483             return ensureTouchMode(false);
   5484         }
   5485 
   5486         // If the key can be used for typing then leave touch mode
   5487         // and select a focused view if needed (in ensureTouchMode).
   5488         // Always allow the view to process the typing key.
   5489         if (isTypingKey(event)) {
   5490             ensureTouchMode(false);
   5491             return false;
   5492         }
   5493 
   5494         return false;
   5495     }
   5496 
   5497     /* drag/drop */
   5498     void setLocalDragState(Object obj) {
   5499         mLocalDragState = obj;
   5500     }
   5501 
   5502     private void handleDragEvent(DragEvent event) {
   5503         // From the root, only drag start/end/location are dispatched.  entered/exited
   5504         // are determined and dispatched by the viewgroup hierarchy, who then report
   5505         // that back here for ultimate reporting back to the framework.
   5506         if (mView != null && mAdded) {
   5507             final int what = event.mAction;
   5508 
   5509             // Cache the drag description when the operation starts, then fill it in
   5510             // on subsequent calls as a convenience
   5511             if (what == DragEvent.ACTION_DRAG_STARTED) {
   5512                 mCurrentDragView = null;    // Start the current-recipient tracking
   5513                 mDragDescription = event.mClipDescription;
   5514             } else {
   5515                 event.mClipDescription = mDragDescription;
   5516             }
   5517 
   5518             if (what == DragEvent.ACTION_DRAG_EXITED) {
   5519                 // A direct EXITED event means that the window manager knows we've just crossed
   5520                 // a window boundary, so the current drag target within this one must have
   5521                 // just been exited.  Send it the usual notifications and then we're done
   5522                 // for now.
   5523                 mView.dispatchDragEvent(event);
   5524             } else {
   5525                 // For events with a [screen] location, translate into window coordinates
   5526                 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
   5527                     mDragPoint.set(event.mX, event.mY);
   5528                     if (mTranslator != null) {
   5529                         mTranslator.translatePointInScreenToAppWindow(mDragPoint);
   5530                     }
   5531 
   5532                     if (mCurScrollY != 0) {
   5533                         mDragPoint.offset(0, mCurScrollY);
   5534                     }
   5535 
   5536                     event.mX = mDragPoint.x;
   5537                     event.mY = mDragPoint.y;
   5538                 }
   5539 
   5540                 // Remember who the current drag target is pre-dispatch
   5541                 final View prevDragView = mCurrentDragView;
   5542 
   5543                 // Now dispatch the drag/drop event
   5544                 boolean result = mView.dispatchDragEvent(event);
   5545 
   5546                 // If we changed apparent drag target, tell the OS about it
   5547                 if (prevDragView != mCurrentDragView) {
   5548                     try {
   5549                         if (prevDragView != null) {
   5550                             mWindowSession.dragRecipientExited(mWindow);
   5551                         }
   5552                         if (mCurrentDragView != null) {
   5553                             mWindowSession.dragRecipientEntered(mWindow);
   5554                         }
   5555                     } catch (RemoteException e) {
   5556                         Slog.e(mTag, "Unable to note drag target change");
   5557                     }
   5558                 }
   5559 
   5560                 // Report the drop result when we're done
   5561                 if (what == DragEvent.ACTION_DROP) {
   5562                     mDragDescription = null;
   5563                     try {
   5564                         Log.i(mTag, "Reporting drop result: " + result);
   5565                         mWindowSession.reportDropResult(mWindow, result);
   5566                     } catch (RemoteException e) {
   5567                         Log.e(mTag, "Unable to report drop result");
   5568                     }
   5569                 }
   5570 
   5571                 // When the drag operation ends, reset drag-related state
   5572                 if (what == DragEvent.ACTION_DRAG_ENDED) {
   5573                     setLocalDragState(null);
   5574                     mAttachInfo.mDragToken = null;
   5575                     if (mAttachInfo.mDragSurface != null) {
   5576                         mAttachInfo.mDragSurface.release();
   5577                         mAttachInfo.mDragSurface = null;
   5578                     }
   5579                 }
   5580             }
   5581         }
   5582         event.recycle();
   5583     }
   5584 
   5585     public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
   5586         if (mSeq != args.seq) {
   5587             // The sequence has changed, so we need to update our value and make
   5588             // sure to do a traversal afterward so the window manager is given our
   5589             // most recent data.
   5590             mSeq = args.seq;
   5591             mAttachInfo.mForceReportNewAttributes = true;
   5592             scheduleTraversals();
   5593         }
   5594         if (mView == null) return;
   5595         if (args.localChanges != 0) {
   5596             mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
   5597         }
   5598 
   5599         int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
   5600         if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
   5601             mAttachInfo.mGlobalSystemUiVisibility = visibility;
   5602             mView.dispatchSystemUiVisibilityChanged(visibility);
   5603         }
   5604     }
   5605 
   5606     public void handleDispatchWindowShown() {
   5607         mAttachInfo.mTreeObserver.dispatchOnWindowShown();
   5608     }
   5609 
   5610     public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
   5611         Bundle data = new Bundle();
   5612         ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
   5613         if (mView != null) {
   5614             mView.requestKeyboardShortcuts(list, deviceId);
   5615         }
   5616         data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
   5617         try {
   5618             receiver.send(0, data);
   5619         } catch (RemoteException e) {
   5620         }
   5621     }
   5622 
   5623     public void getLastTouchPoint(Point outLocation) {
   5624         outLocation.x = (int) mLastTouchPoint.x;
   5625         outLocation.y = (int) mLastTouchPoint.y;
   5626     }
   5627 
   5628     public int getLastTouchSource() {
   5629         return mLastTouchSource;
   5630     }
   5631 
   5632     public void setDragFocus(View newDragTarget) {
   5633         if (mCurrentDragView != newDragTarget) {
   5634             mCurrentDragView = newDragTarget;
   5635         }
   5636     }
   5637 
   5638     private AudioManager getAudioManager() {
   5639         if (mView == null) {
   5640             throw new IllegalStateException("getAudioManager called when there is no mView");
   5641         }
   5642         if (mAudioManager == null) {
   5643             mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
   5644         }
   5645         return mAudioManager;
   5646     }
   5647 
   5648     public AccessibilityInteractionController getAccessibilityInteractionController() {
   5649         if (mView == null) {
   5650             throw new IllegalStateException("getAccessibilityInteractionController"
   5651                     + " called when there is no mView");
   5652         }
   5653         if (mAccessibilityInteractionController == null) {
   5654             mAccessibilityInteractionController = new AccessibilityInteractionController(this);
   5655         }
   5656         return mAccessibilityInteractionController;
   5657     }
   5658 
   5659     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
   5660             boolean insetsPending) throws RemoteException {
   5661 
   5662         float appScale = mAttachInfo.mApplicationScale;
   5663         boolean restore = false;
   5664         if (params != null && mTranslator != null) {
   5665             restore = true;
   5666             params.backup();
   5667             mTranslator.translateWindowLayout(params);
   5668         }
   5669         if (params != null) {
   5670             if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
   5671         }
   5672         mPendingConfiguration.seq = 0;
   5673         //Log.d(mTag, ">>>>>> CALLING relayout");
   5674         if (params != null && mOrigWindowType != params.type) {
   5675             // For compatibility with old apps, don't crash here.
   5676             if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
   5677                 Slog.w(mTag, "Window type can not be changed after "
   5678                         + "the window is added; ignoring change of " + mView);
   5679                 params.type = mOrigWindowType;
   5680             }
   5681         }
   5682         int relayoutResult = mWindowSession.relayout(
   5683                 mWindow, mSeq, params,
   5684                 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
   5685                 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
   5686                 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
   5687                 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
   5688                 mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
   5689                 mSurface);
   5690 
   5691         mPendingAlwaysConsumeNavBar =
   5692                 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
   5693 
   5694         //Log.d(mTag, "<<<<<< BACK FROM relayout");
   5695         if (restore) {
   5696             params.restore();
   5697         }
   5698 
   5699         if (mTranslator != null) {
   5700             mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
   5701             mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
   5702             mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
   5703             mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
   5704             mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
   5705         }
   5706         return relayoutResult;
   5707     }
   5708 
   5709     /**
   5710      * {@inheritDoc}
   5711      */
   5712     @Override
   5713     public void playSoundEffect(int effectId) {
   5714         checkThread();
   5715 
   5716         try {
   5717             final AudioManager audioManager = getAudioManager();
   5718 
   5719             switch (effectId) {
   5720                 case SoundEffectConstants.CLICK:
   5721                     audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
   5722                     return;
   5723                 case SoundEffectConstants.NAVIGATION_DOWN:
   5724                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
   5725                     return;
   5726                 case SoundEffectConstants.NAVIGATION_LEFT:
   5727                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
   5728                     return;
   5729                 case SoundEffectConstants.NAVIGATION_RIGHT:
   5730                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
   5731                     return;
   5732                 case SoundEffectConstants.NAVIGATION_UP:
   5733                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
   5734                     return;
   5735                 default:
   5736                     throw new IllegalArgumentException("unknown effect id " + effectId +
   5737                             " not defined in " + SoundEffectConstants.class.getCanonicalName());
   5738             }
   5739         } catch (IllegalStateException e) {
   5740             // Exception thrown by getAudioManager() when mView is null
   5741             Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
   5742             e.printStackTrace();
   5743         }
   5744     }
   5745 
   5746     /**
   5747      * {@inheritDoc}
   5748      */
   5749     @Override
   5750     public boolean performHapticFeedback(int effectId, boolean always) {
   5751         try {
   5752             return mWindowSession.performHapticFeedback(mWindow, effectId, always);
   5753         } catch (RemoteException e) {
   5754             return false;
   5755         }
   5756     }
   5757 
   5758     /**
   5759      * {@inheritDoc}
   5760      */
   5761     @Override
   5762     public View focusSearch(View focused, int direction) {
   5763         checkThread();
   5764         if (!(mView instanceof ViewGroup)) {
   5765             return null;
   5766         }
   5767         return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
   5768     }
   5769 
   5770     public void debug() {
   5771         mView.debug();
   5772     }
   5773 
   5774     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
   5775         String innerPrefix = prefix + "  ";
   5776         writer.print(prefix); writer.println("ViewRoot:");
   5777         writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
   5778                 writer.print(" mRemoved="); writer.println(mRemoved);
   5779         writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
   5780                 writer.println(mConsumeBatchedInputScheduled);
   5781         writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
   5782                 writer.println(mConsumeBatchedInputImmediatelyScheduled);
   5783         writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
   5784                 writer.println(mPendingInputEventCount);
   5785         writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
   5786                 writer.println(mProcessInputEventsScheduled);
   5787         writer.print(innerPrefix); writer.print("mTraversalScheduled=");
   5788                 writer.print(mTraversalScheduled);
   5789         writer.print(innerPrefix); writer.print("mIsAmbientMode=");
   5790                 writer.print(mIsAmbientMode);
   5791         if (mTraversalScheduled) {
   5792             writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
   5793         } else {
   5794             writer.println();
   5795         }
   5796         mFirstInputStage.dump(innerPrefix, writer);
   5797 
   5798         mChoreographer.dump(prefix, writer);
   5799 
   5800         writer.print(prefix); writer.println("View Hierarchy:");
   5801         dumpViewHierarchy(innerPrefix, writer, mView);
   5802     }
   5803 
   5804     private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
   5805         writer.print(prefix);
   5806         if (view == null) {
   5807             writer.println("null");
   5808             return;
   5809         }
   5810         writer.println(view.toString());
   5811         if (!(view instanceof ViewGroup)) {
   5812             return;
   5813         }
   5814         ViewGroup grp = (ViewGroup)view;
   5815         final int N = grp.getChildCount();
   5816         if (N <= 0) {
   5817             return;
   5818         }
   5819         prefix = prefix + "  ";
   5820         for (int i=0; i<N; i++) {
   5821             dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
   5822         }
   5823     }
   5824 
   5825     public void dumpGfxInfo(int[] info) {
   5826         info[0] = info[1] = 0;
   5827         if (mView != null) {
   5828             getGfxInfo(mView, info);
   5829         }
   5830     }
   5831 
   5832     private static void getGfxInfo(View view, int[] info) {
   5833         RenderNode renderNode = view.mRenderNode;
   5834         info[0]++;
   5835         if (renderNode != null) {
   5836             info[1] += renderNode.getDebugSize();
   5837         }
   5838 
   5839         if (view instanceof ViewGroup) {
   5840             ViewGroup group = (ViewGroup) view;
   5841 
   5842             int count = group.getChildCount();
   5843             for (int i = 0; i < count; i++) {
   5844                 getGfxInfo(group.getChildAt(i), info);
   5845             }
   5846         }
   5847     }
   5848 
   5849     /**
   5850      * @param immediate True, do now if not in traversal. False, put on queue and do later.
   5851      * @return True, request has been queued. False, request has been completed.
   5852      */
   5853     boolean die(boolean immediate) {
   5854         // Make sure we do execute immediately if we are in the middle of a traversal or the damage
   5855         // done by dispatchDetachedFromWindow will cause havoc on return.
   5856         if (immediate && !mIsInTraversal) {
   5857             doDie();
   5858             return false;
   5859         }
   5860 
   5861         if (!mIsDrawing) {
   5862             destroyHardwareRenderer();
   5863         } else {
   5864             Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
   5865                     "  window=" + this + ", title=" + mWindowAttributes.getTitle());
   5866         }
   5867         mHandler.sendEmptyMessage(MSG_DIE);
   5868         return true;
   5869     }
   5870 
   5871     void doDie() {
   5872         checkThread();
   5873         if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
   5874         synchronized (this) {
   5875             if (mRemoved) {
   5876                 return;
   5877             }
   5878             mRemoved = true;
   5879             if (mAdded) {
   5880                 dispatchDetachedFromWindow();
   5881             }
   5882 
   5883             if (mAdded && !mFirst) {
   5884                 destroyHardwareRenderer();
   5885 
   5886                 if (mView != null) {
   5887                     int viewVisibility = mView.getVisibility();
   5888                     boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
   5889                     if (mWindowAttributesChanged || viewVisibilityChanged) {
   5890                         // If layout params have been changed, first give them
   5891                         // to the window manager to make sure it has the correct
   5892                         // animation info.
   5893                         try {
   5894                             if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
   5895                                     & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
   5896                                 mWindowSession.finishDrawing(mWindow);
   5897                             }
   5898                         } catch (RemoteException e) {
   5899                         }
   5900                     }
   5901 
   5902                     mSurface.release();
   5903                 }
   5904             }
   5905 
   5906             mAdded = false;
   5907         }
   5908         WindowManagerGlobal.getInstance().doRemoveView(this);
   5909     }
   5910 
   5911     public void requestUpdateConfiguration(Configuration config) {
   5912         Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
   5913         mHandler.sendMessage(msg);
   5914     }
   5915 
   5916     public void loadSystemProperties() {
   5917         mHandler.post(new Runnable() {
   5918             @Override
   5919             public void run() {
   5920                 // Profiling
   5921                 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
   5922                 profileRendering(mAttachInfo.mHasWindowFocus);
   5923 
   5924                 // Hardware rendering
   5925                 if (mAttachInfo.mHardwareRenderer != null) {
   5926                     if (mAttachInfo.mHardwareRenderer.loadSystemProperties()) {
   5927                         invalidate();
   5928                     }
   5929                 }
   5930 
   5931                 // Layout debugging
   5932                 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
   5933                 if (layout != mAttachInfo.mDebugLayout) {
   5934                     mAttachInfo.mDebugLayout = layout;
   5935                     if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
   5936                         mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
   5937                     }
   5938                 }
   5939             }
   5940         });
   5941     }
   5942 
   5943     private void destroyHardwareRenderer() {
   5944         ThreadedRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
   5945 
   5946         if (hardwareRenderer != null) {
   5947             if (mView != null) {
   5948                 hardwareRenderer.destroyHardwareResources(mView);
   5949             }
   5950             hardwareRenderer.destroy();
   5951             hardwareRenderer.setRequested(false);
   5952 
   5953             mAttachInfo.mHardwareRenderer = null;
   5954             mAttachInfo.mHardwareAccelerated = false;
   5955         }
   5956     }
   5957 
   5958     public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
   5959             Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
   5960             Configuration newConfig, Rect backDropFrame, boolean forceLayout,
   5961             boolean alwaysConsumeNavBar) {
   5962         if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
   5963                 + " contentInsets=" + contentInsets.toShortString()
   5964                 + " visibleInsets=" + visibleInsets.toShortString()
   5965                 + " reportDraw=" + reportDraw
   5966                 + " backDropFrame=" + backDropFrame);
   5967 
   5968         // Tell all listeners that we are resizing the window so that the chrome can get
   5969         // updated as fast as possible on a separate thread,
   5970         if (mDragResizing) {
   5971             boolean fullscreen = frame.equals(backDropFrame);
   5972             synchronized (mWindowCallbacks) {
   5973                 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
   5974                     mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen,
   5975                             visibleInsets, stableInsets);
   5976                 }
   5977             }
   5978         }
   5979 
   5980         Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
   5981         if (mTranslator != null) {
   5982             mTranslator.translateRectInScreenToAppWindow(frame);
   5983             mTranslator.translateRectInScreenToAppWindow(overscanInsets);
   5984             mTranslator.translateRectInScreenToAppWindow(contentInsets);
   5985             mTranslator.translateRectInScreenToAppWindow(visibleInsets);
   5986         }
   5987         SomeArgs args = SomeArgs.obtain();
   5988         final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
   5989         args.arg1 = sameProcessCall ? new Rect(frame) : frame;
   5990         args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
   5991         args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
   5992         args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
   5993         args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
   5994         args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
   5995         args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
   5996         args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
   5997         args.argi1 = forceLayout ? 1 : 0;
   5998         args.argi2 = alwaysConsumeNavBar ? 1 : 0;
   5999         msg.obj = args;
   6000         mHandler.sendMessage(msg);
   6001     }
   6002 
   6003     public void dispatchMoved(int newX, int newY) {
   6004         if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
   6005         if (mTranslator != null) {
   6006             PointF point = new PointF(newX, newY);
   6007             mTranslator.translatePointInScreenToAppWindow(point);
   6008             newX = (int) (point.x + 0.5);
   6009             newY = (int) (point.y + 0.5);
   6010         }
   6011         Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
   6012         mHandler.sendMessage(msg);
   6013     }
   6014 
   6015     /**
   6016      * Represents a pending input event that is waiting in a queue.
   6017      *
   6018      * Input events are processed in serial order by the timestamp specified by
   6019      * {@link InputEvent#getEventTimeNano()}.  In general, the input dispatcher delivers
   6020      * one input event to the application at a time and waits for the application
   6021      * to finish handling it before delivering the next one.
   6022      *
   6023      * However, because the application or IME can synthesize and inject multiple
   6024      * key events at a time without going through the input dispatcher, we end up
   6025      * needing a queue on the application's side.
   6026      */
   6027     private static final class QueuedInputEvent {
   6028         public static final int FLAG_DELIVER_POST_IME = 1 << 0;
   6029         public static final int FLAG_DEFERRED = 1 << 1;
   6030         public static final int FLAG_FINISHED = 1 << 2;
   6031         public static final int FLAG_FINISHED_HANDLED = 1 << 3;
   6032         public static final int FLAG_RESYNTHESIZED = 1 << 4;
   6033         public static final int FLAG_UNHANDLED = 1 << 5;
   6034 
   6035         public QueuedInputEvent mNext;
   6036 
   6037         public InputEvent mEvent;
   6038         public InputEventReceiver mReceiver;
   6039         public int mFlags;
   6040 
   6041         public boolean shouldSkipIme() {
   6042             if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
   6043                 return true;
   6044             }
   6045             return mEvent instanceof MotionEvent
   6046                     && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
   6047         }
   6048 
   6049         public boolean shouldSendToSynthesizer() {
   6050             if ((mFlags & FLAG_UNHANDLED) != 0) {
   6051                 return true;
   6052             }
   6053 
   6054             return false;
   6055         }
   6056 
   6057         @Override
   6058         public String toString() {
   6059             StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
   6060             boolean hasPrevious = false;
   6061             hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
   6062             hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
   6063             hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
   6064             hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
   6065             hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
   6066             hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
   6067             if (!hasPrevious) {
   6068                 sb.append("0");
   6069             }
   6070             sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
   6071             sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
   6072             sb.append(", mEvent=" + mEvent + "}");
   6073             return sb.toString();
   6074         }
   6075 
   6076         private boolean flagToString(String name, int flag,
   6077                 boolean hasPrevious, StringBuilder sb) {
   6078             if ((mFlags & flag) != 0) {
   6079                 if (hasPrevious) {
   6080                     sb.append("|");
   6081                 }
   6082                 sb.append(name);
   6083                 return true;
   6084             }
   6085             return hasPrevious;
   6086         }
   6087     }
   6088 
   6089     private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
   6090             InputEventReceiver receiver, int flags) {
   6091         QueuedInputEvent q = mQueuedInputEventPool;
   6092         if (q != null) {
   6093             mQueuedInputEventPoolSize -= 1;
   6094             mQueuedInputEventPool = q.mNext;
   6095             q.mNext = null;
   6096         } else {
   6097             q = new QueuedInputEvent();
   6098         }
   6099 
   6100         q.mEvent = event;
   6101         q.mReceiver = receiver;
   6102         q.mFlags = flags;
   6103         return q;
   6104     }
   6105 
   6106     private void recycleQueuedInputEvent(QueuedInputEvent q) {
   6107         q.mEvent = null;
   6108         q.mReceiver = null;
   6109 
   6110         if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
   6111             mQueuedInputEventPoolSize += 1;
   6112             q.mNext = mQueuedInputEventPool;
   6113             mQueuedInputEventPool = q;
   6114         }
   6115     }
   6116 
   6117     void enqueueInputEvent(InputEvent event) {
   6118         enqueueInputEvent(event, null, 0, false);
   6119     }
   6120 
   6121     void enqueueInputEvent(InputEvent event,
   6122             InputEventReceiver receiver, int flags, boolean processImmediately) {
   6123         adjustInputEventForCompatibility(event);
   6124         QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
   6125 
   6126         // Always enqueue the input event in order, regardless of its time stamp.
   6127         // We do this because the application or the IME may inject key events
   6128         // in response to touch events and we want to ensure that the injected keys
   6129         // are processed in the order they were received and we cannot trust that
   6130         // the time stamp of injected events are monotonic.
   6131         QueuedInputEvent last = mPendingInputEventTail;
   6132         if (last == null) {
   6133             mPendingInputEventHead = q;
   6134             mPendingInputEventTail = q;
   6135         } else {
   6136             last.mNext = q;
   6137             mPendingInputEventTail = q;
   6138         }
   6139         mPendingInputEventCount += 1;
   6140         Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
   6141                 mPendingInputEventCount);
   6142 
   6143         if (processImmediately) {
   6144             doProcessInputEvents();
   6145         } else {
   6146             scheduleProcessInputEvents();
   6147         }
   6148     }
   6149 
   6150     private void scheduleProcessInputEvents() {
   6151         if (!mProcessInputEventsScheduled) {
   6152             mProcessInputEventsScheduled = true;
   6153             Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
   6154             msg.setAsynchronous(true);
   6155             mHandler.sendMessage(msg);
   6156         }
   6157     }
   6158 
   6159     void doProcessInputEvents() {
   6160         // Deliver all pending input events in the queue.
   6161         while (mPendingInputEventHead != null) {
   6162             QueuedInputEvent q = mPendingInputEventHead;
   6163             mPendingInputEventHead = q.mNext;
   6164             if (mPendingInputEventHead == null) {
   6165                 mPendingInputEventTail = null;
   6166             }
   6167             q.mNext = null;
   6168 
   6169             mPendingInputEventCount -= 1;
   6170             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
   6171                     mPendingInputEventCount);
   6172 
   6173             long eventTime = q.mEvent.getEventTimeNano();
   6174             long oldestEventTime = eventTime;
   6175             if (q.mEvent instanceof MotionEvent) {
   6176                 MotionEvent me = (MotionEvent)q.mEvent;
   6177                 if (me.getHistorySize() > 0) {
   6178                     oldestEventTime = me.getHistoricalEventTimeNano(0);
   6179                 }
   6180             }
   6181             mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
   6182 
   6183             deliverInputEvent(q);
   6184         }
   6185 
   6186         // We are done processing all input events that we can process right now
   6187         // so we can clear the pending flag immediately.
   6188         if (mProcessInputEventsScheduled) {
   6189             mProcessInputEventsScheduled = false;
   6190             mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
   6191         }
   6192     }
   6193 
   6194     private void deliverInputEvent(QueuedInputEvent q) {
   6195         Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
   6196                 q.mEvent.getSequenceNumber());
   6197         if (mInputEventConsistencyVerifier != null) {
   6198             mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
   6199         }
   6200 
   6201         InputStage stage;
   6202         if (q.shouldSendToSynthesizer()) {
   6203             stage = mSyntheticInputStage;
   6204         } else {
   6205             stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
   6206         }
   6207 
   6208         if (stage != null) {
   6209             stage.deliver(q);
   6210         } else {
   6211             finishInputEvent(q);
   6212         }
   6213     }
   6214 
   6215     private void finishInputEvent(QueuedInputEvent q) {
   6216         Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
   6217                 q.mEvent.getSequenceNumber());
   6218 
   6219         if (q.mReceiver != null) {
   6220             boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
   6221             q.mReceiver.finishInputEvent(q.mEvent, handled);
   6222         } else {
   6223             q.mEvent.recycleIfNeededAfterDispatch();
   6224         }
   6225 
   6226         recycleQueuedInputEvent(q);
   6227     }
   6228 
   6229     private void adjustInputEventForCompatibility(InputEvent e) {
   6230         if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
   6231             MotionEvent motion = (MotionEvent) e;
   6232             final int mask =
   6233                 MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
   6234             final int buttonState = motion.getButtonState();
   6235             final int compatButtonState = (buttonState & mask) >> 4;
   6236             if (compatButtonState != 0) {
   6237                 motion.setButtonState(buttonState | compatButtonState);
   6238             }
   6239         }
   6240     }
   6241 
   6242     static boolean isTerminalInputEvent(InputEvent event) {
   6243         if (event instanceof KeyEvent) {
   6244             final KeyEvent keyEvent = (KeyEvent)event;
   6245             return keyEvent.getAction() == KeyEvent.ACTION_UP;
   6246         } else {
   6247             final MotionEvent motionEvent = (MotionEvent)event;
   6248             final int action = motionEvent.getAction();
   6249             return action == MotionEvent.ACTION_UP
   6250                     || action == MotionEvent.ACTION_CANCEL
   6251                     || action == MotionEvent.ACTION_HOVER_EXIT;
   6252         }
   6253     }
   6254 
   6255     void scheduleConsumeBatchedInput() {
   6256         if (!mConsumeBatchedInputScheduled) {
   6257             mConsumeBatchedInputScheduled = true;
   6258             mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
   6259                     mConsumedBatchedInputRunnable, null);
   6260         }
   6261     }
   6262 
   6263     void unscheduleConsumeBatchedInput() {
   6264         if (mConsumeBatchedInputScheduled) {
   6265             mConsumeBatchedInputScheduled = false;
   6266             mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
   6267                     mConsumedBatchedInputRunnable, null);
   6268         }
   6269     }
   6270 
   6271     void scheduleConsumeBatchedInputImmediately() {
   6272         if (!mConsumeBatchedInputImmediatelyScheduled) {
   6273             unscheduleConsumeBatchedInput();
   6274             mConsumeBatchedInputImmediatelyScheduled = true;
   6275             mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
   6276         }
   6277     }
   6278 
   6279     void doConsumeBatchedInput(long frameTimeNanos) {
   6280         if (mConsumeBatchedInputScheduled) {
   6281             mConsumeBatchedInputScheduled = false;
   6282             if (mInputEventReceiver != null) {
   6283                 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
   6284                         && frameTimeNanos != -1) {
   6285                     // If we consumed a batch here, we want to go ahead and schedule the
   6286                     // consumption of batched input events on the next frame. Otherwise, we would
   6287                     // wait until we have more input events pending and might get starved by other
   6288                     // things occurring in the process. If the frame time is -1, however, then
   6289                     // we're in a non-batching mode, so there's no need to schedule this.
   6290                     scheduleConsumeBatchedInput();
   6291                 }
   6292             }
   6293             doProcessInputEvents();
   6294         }
   6295     }
   6296 
   6297     final class TraversalRunnable implements Runnable {
   6298         @Override
   6299         public void run() {
   6300             doTraversal();
   6301         }
   6302     }
   6303     final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
   6304 
   6305     final class WindowInputEventReceiver extends InputEventReceiver {
   6306         public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
   6307             super(inputChannel, looper);
   6308         }
   6309 
   6310         @Override
   6311         public void onInputEvent(InputEvent event) {
   6312             enqueueInputEvent(event, this, 0, true);
   6313         }
   6314 
   6315         @Override
   6316         public void onBatchedInputEventPending() {
   6317             if (mUnbufferedInputDispatch) {
   6318                 super.onBatchedInputEventPending();
   6319             } else {
   6320                 scheduleConsumeBatchedInput();
   6321             }
   6322         }
   6323 
   6324         @Override
   6325         public void dispose() {
   6326             unscheduleConsumeBatchedInput();
   6327             super.dispose();
   6328         }
   6329     }
   6330     WindowInputEventReceiver mInputEventReceiver;
   6331 
   6332     final class ConsumeBatchedInputRunnable implements Runnable {
   6333         @Override
   6334         public void run() {
   6335             doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
   6336         }
   6337     }
   6338     final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
   6339             new ConsumeBatchedInputRunnable();
   6340     boolean mConsumeBatchedInputScheduled;
   6341 
   6342     final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
   6343         @Override
   6344         public void run() {
   6345             doConsumeBatchedInput(-1);
   6346         }
   6347     }
   6348     final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
   6349             new ConsumeBatchedInputImmediatelyRunnable();
   6350     boolean mConsumeBatchedInputImmediatelyScheduled;
   6351 
   6352     final class InvalidateOnAnimationRunnable implements Runnable {
   6353         private boolean mPosted;
   6354         private final ArrayList<View> mViews = new ArrayList<View>();
   6355         private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
   6356                 new ArrayList<AttachInfo.InvalidateInfo>();
   6357         private View[] mTempViews;
   6358         private AttachInfo.InvalidateInfo[] mTempViewRects;
   6359 
   6360         public void addView(View view) {
   6361             synchronized (this) {
   6362                 mViews.add(view);
   6363                 postIfNeededLocked();
   6364             }
   6365         }
   6366 
   6367         public void addViewRect(AttachInfo.InvalidateInfo info) {
   6368             synchronized (this) {
   6369                 mViewRects.add(info);
   6370                 postIfNeededLocked();
   6371             }
   6372         }
   6373 
   6374         public void removeView(View view) {
   6375             synchronized (this) {
   6376                 mViews.remove(view);
   6377 
   6378                 for (int i = mViewRects.size(); i-- > 0; ) {
   6379                     AttachInfo.InvalidateInfo info = mViewRects.get(i);
   6380                     if (info.target == view) {
   6381                         mViewRects.remove(i);
   6382                         info.recycle();
   6383                     }
   6384                 }
   6385 
   6386                 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
   6387                     mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
   6388                     mPosted = false;
   6389                 }
   6390             }
   6391         }
   6392 
   6393         @Override
   6394         public void run() {
   6395             final int viewCount;
   6396             final int viewRectCount;
   6397             synchronized (this) {
   6398                 mPosted = false;
   6399 
   6400                 viewCount = mViews.size();
   6401                 if (viewCount != 0) {
   6402                     mTempViews = mViews.toArray(mTempViews != null
   6403                             ? mTempViews : new View[viewCount]);
   6404                     mViews.clear();
   6405                 }
   6406 
   6407                 viewRectCount = mViewRects.size();
   6408                 if (viewRectCount != 0) {
   6409                     mTempViewRects = mViewRects.toArray(mTempViewRects != null
   6410                             ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
   6411                     mViewRects.clear();
   6412                 }
   6413             }
   6414 
   6415             for (int i = 0; i < viewCount; i++) {
   6416                 mTempViews[i].invalidate();
   6417                 mTempViews[i] = null;
   6418             }
   6419 
   6420             for (int i = 0; i < viewRectCount; i++) {
   6421                 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
   6422                 info.target.invalidate(info.left, info.top, info.right, info.bottom);
   6423                 info.recycle();
   6424             }
   6425         }
   6426 
   6427         private void postIfNeededLocked() {
   6428             if (!mPosted) {
   6429                 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
   6430                 mPosted = true;
   6431             }
   6432         }
   6433     }
   6434     final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
   6435             new InvalidateOnAnimationRunnable();
   6436 
   6437     public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
   6438         Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
   6439         mHandler.sendMessageDelayed(msg, delayMilliseconds);
   6440     }
   6441 
   6442     public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
   6443             long delayMilliseconds) {
   6444         final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
   6445         mHandler.sendMessageDelayed(msg, delayMilliseconds);
   6446     }
   6447 
   6448     public void dispatchInvalidateOnAnimation(View view) {
   6449         mInvalidateOnAnimationRunnable.addView(view);
   6450     }
   6451 
   6452     public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
   6453         mInvalidateOnAnimationRunnable.addViewRect(info);
   6454     }
   6455 
   6456     public void cancelInvalidate(View view) {
   6457         mHandler.removeMessages(MSG_INVALIDATE, view);
   6458         // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
   6459         // them to the pool
   6460         mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
   6461         mInvalidateOnAnimationRunnable.removeView(view);
   6462     }
   6463 
   6464     public void dispatchInputEvent(InputEvent event) {
   6465         dispatchInputEvent(event, null);
   6466     }
   6467 
   6468     public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
   6469         SomeArgs args = SomeArgs.obtain();
   6470         args.arg1 = event;
   6471         args.arg2 = receiver;
   6472         Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
   6473         msg.setAsynchronous(true);
   6474         mHandler.sendMessage(msg);
   6475     }
   6476 
   6477     public void synthesizeInputEvent(InputEvent event) {
   6478         Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
   6479         msg.setAsynchronous(true);
   6480         mHandler.sendMessage(msg);
   6481     }
   6482 
   6483     public void dispatchKeyFromIme(KeyEvent event) {
   6484         Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
   6485         msg.setAsynchronous(true);
   6486         mHandler.sendMessage(msg);
   6487     }
   6488 
   6489     /**
   6490      * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
   6491      *
   6492      * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
   6493      * passes in.
   6494      */
   6495     public void dispatchUnhandledInputEvent(InputEvent event) {
   6496         if (event instanceof MotionEvent) {
   6497             event = MotionEvent.obtain((MotionEvent) event);
   6498         }
   6499         synthesizeInputEvent(event);
   6500     }
   6501 
   6502     public void dispatchAppVisibility(boolean visible) {
   6503         Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
   6504         msg.arg1 = visible ? 1 : 0;
   6505         mHandler.sendMessage(msg);
   6506     }
   6507 
   6508     public void dispatchGetNewSurface() {
   6509         Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
   6510         mHandler.sendMessage(msg);
   6511     }
   6512 
   6513     public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
   6514         Message msg = Message.obtain();
   6515         msg.what = MSG_WINDOW_FOCUS_CHANGED;
   6516         msg.arg1 = hasFocus ? 1 : 0;
   6517         msg.arg2 = inTouchMode ? 1 : 0;
   6518         mHandler.sendMessage(msg);
   6519     }
   6520 
   6521     public void dispatchWindowShown() {
   6522         mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
   6523     }
   6524 
   6525     public void dispatchCloseSystemDialogs(String reason) {
   6526         Message msg = Message.obtain();
   6527         msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
   6528         msg.obj = reason;
   6529         mHandler.sendMessage(msg);
   6530     }
   6531 
   6532     public void dispatchDragEvent(DragEvent event) {
   6533         final int what;
   6534         if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
   6535             what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
   6536             mHandler.removeMessages(what);
   6537         } else {
   6538             what = MSG_DISPATCH_DRAG_EVENT;
   6539         }
   6540         Message msg = mHandler.obtainMessage(what, event);
   6541         mHandler.sendMessage(msg);
   6542     }
   6543 
   6544     public void updatePointerIcon(float x, float y) {
   6545         final int what = MSG_UPDATE_POINTER_ICON;
   6546         mHandler.removeMessages(what);
   6547         final long now = SystemClock.uptimeMillis();
   6548         final MotionEvent event = MotionEvent.obtain(
   6549                 0, now, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
   6550         Message msg = mHandler.obtainMessage(what, event);
   6551         mHandler.sendMessage(msg);
   6552     }
   6553 
   6554     public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
   6555             int localValue, int localChanges) {
   6556         SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
   6557         args.seq = seq;
   6558         args.globalVisibility = globalVisibility;
   6559         args.localValue = localValue;
   6560         args.localChanges = localChanges;
   6561         mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
   6562     }
   6563 
   6564     public void dispatchCheckFocus() {
   6565         if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
   6566             // This will result in a call to checkFocus() below.
   6567             mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
   6568         }
   6569     }
   6570 
   6571     public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
   6572         mHandler.obtainMessage(
   6573                 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
   6574     }
   6575 
   6576     /**
   6577      * Post a callback to send a
   6578      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
   6579      * This event is send at most once every
   6580      * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
   6581      */
   6582     private void postSendWindowContentChangedCallback(View source, int changeType) {
   6583         if (mSendWindowContentChangedAccessibilityEvent == null) {
   6584             mSendWindowContentChangedAccessibilityEvent =
   6585                 new SendWindowContentChangedAccessibilityEvent();
   6586         }
   6587         mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
   6588     }
   6589 
   6590     /**
   6591      * Remove a posted callback to send a
   6592      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
   6593      */
   6594     private void removeSendWindowContentChangedCallback() {
   6595         if (mSendWindowContentChangedAccessibilityEvent != null) {
   6596             mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
   6597         }
   6598     }
   6599 
   6600     @Override
   6601     public boolean showContextMenuForChild(View originalView) {
   6602         return false;
   6603     }
   6604 
   6605     @Override
   6606     public boolean showContextMenuForChild(View originalView, float x, float y) {
   6607         return false;
   6608     }
   6609 
   6610     @Override
   6611     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
   6612         return null;
   6613     }
   6614 
   6615     @Override
   6616     public ActionMode startActionModeForChild(
   6617             View originalView, ActionMode.Callback callback, int type) {
   6618         return null;
   6619     }
   6620 
   6621     @Override
   6622     public void createContextMenu(ContextMenu menu) {
   6623     }
   6624 
   6625     @Override
   6626     public void childDrawableStateChanged(View child) {
   6627     }
   6628 
   6629     @Override
   6630     public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
   6631         if (mView == null || mStopped || mPausedForTransition) {
   6632             return false;
   6633         }
   6634         // Intercept accessibility focus events fired by virtual nodes to keep
   6635         // track of accessibility focus position in such nodes.
   6636         final int eventType = event.getEventType();
   6637         switch (eventType) {
   6638             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
   6639                 final long sourceNodeId = event.getSourceNodeId();
   6640                 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
   6641                         sourceNodeId);
   6642                 View source = mView.findViewByAccessibilityId(accessibilityViewId);
   6643                 if (source != null) {
   6644                     AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
   6645                     if (provider != null) {
   6646                         final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
   6647                                 sourceNodeId);
   6648                         final AccessibilityNodeInfo node;
   6649                         if (virtualNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
   6650                             node = provider.createAccessibilityNodeInfo(
   6651                                     AccessibilityNodeProvider.HOST_VIEW_ID);
   6652                         } else {
   6653                             node = provider.createAccessibilityNodeInfo(virtualNodeId);
   6654                         }
   6655                         setAccessibilityFocus(source, node);
   6656                     }
   6657                 }
   6658             } break;
   6659             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
   6660                 final long sourceNodeId = event.getSourceNodeId();
   6661                 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
   6662                         sourceNodeId);
   6663                 View source = mView.findViewByAccessibilityId(accessibilityViewId);
   6664                 if (source != null) {
   6665                     AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
   6666                     if (provider != null) {
   6667                         setAccessibilityFocus(null, null);
   6668                     }
   6669                 }
   6670             } break;
   6671 
   6672 
   6673             case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
   6674                 handleWindowContentChangedEvent(event);
   6675             } break;
   6676         }
   6677         mAccessibilityManager.sendAccessibilityEvent(event);
   6678         return true;
   6679     }
   6680 
   6681     /**
   6682      * Updates the focused virtual view, when necessary, in response to a
   6683      * content changed event.
   6684      * <p>
   6685      * This is necessary to get updated bounds after a position change.
   6686      *
   6687      * @param event an accessibility event of type
   6688      *              {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
   6689      */
   6690     private void handleWindowContentChangedEvent(AccessibilityEvent event) {
   6691         final View focusedHost = mAccessibilityFocusedHost;
   6692         if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
   6693             // No virtual view focused, nothing to do here.
   6694             return;
   6695         }
   6696 
   6697         final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
   6698         if (provider == null) {
   6699             // Error state: virtual view with no provider. Clear focus.
   6700             mAccessibilityFocusedHost = null;
   6701             mAccessibilityFocusedVirtualView = null;
   6702             focusedHost.clearAccessibilityFocusNoCallbacks(0);
   6703             return;
   6704         }
   6705 
   6706         // We only care about change types that may affect the bounds of the
   6707         // focused virtual view.
   6708         final int changes = event.getContentChangeTypes();
   6709         if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
   6710                 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
   6711             return;
   6712         }
   6713 
   6714         final long eventSourceNodeId = event.getSourceNodeId();
   6715         final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
   6716 
   6717         // Search up the tree for subtree containment.
   6718         boolean hostInSubtree = false;
   6719         View root = mAccessibilityFocusedHost;
   6720         while (root != null && !hostInSubtree) {
   6721             if (changedViewId == root.getAccessibilityViewId()) {
   6722                 hostInSubtree = true;
   6723             } else {
   6724                 final ViewParent parent = root.getParent();
   6725                 if (parent instanceof View) {
   6726                     root = (View) parent;
   6727                 } else {
   6728                     root = null;
   6729                 }
   6730             }
   6731         }
   6732 
   6733         // We care only about changes in subtrees containing the host view.
   6734         if (!hostInSubtree) {
   6735             return;
   6736         }
   6737 
   6738         final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
   6739         int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
   6740         if (focusedChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
   6741             // TODO: Should we clear the focused virtual view?
   6742             focusedChildId = AccessibilityNodeProvider.HOST_VIEW_ID;
   6743         }
   6744 
   6745         // Refresh the node for the focused virtual view.
   6746         final Rect oldBounds = mTempRect;
   6747         mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
   6748         mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
   6749         if (mAccessibilityFocusedVirtualView == null) {
   6750             // Error state: The node no longer exists. Clear focus.
   6751             mAccessibilityFocusedHost = null;
   6752             focusedHost.clearAccessibilityFocusNoCallbacks(0);
   6753 
   6754             // This will probably fail, but try to keep the provider's internal
   6755             // state consistent by clearing focus.
   6756             provider.performAction(focusedChildId,
   6757                     AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
   6758             invalidateRectOnScreen(oldBounds);
   6759         } else {
   6760             // The node was refreshed, invalidate bounds if necessary.
   6761             final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
   6762             if (!oldBounds.equals(newBounds)) {
   6763                 oldBounds.union(newBounds);
   6764                 invalidateRectOnScreen(oldBounds);
   6765             }
   6766         }
   6767     }
   6768 
   6769     @Override
   6770     public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
   6771         postSendWindowContentChangedCallback(source, changeType);
   6772     }
   6773 
   6774     @Override
   6775     public boolean canResolveLayoutDirection() {
   6776         return true;
   6777     }
   6778 
   6779     @Override
   6780     public boolean isLayoutDirectionResolved() {
   6781         return true;
   6782     }
   6783 
   6784     @Override
   6785     public int getLayoutDirection() {
   6786         return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
   6787     }
   6788 
   6789     @Override
   6790     public boolean canResolveTextDirection() {
   6791         return true;
   6792     }
   6793 
   6794     @Override
   6795     public boolean isTextDirectionResolved() {
   6796         return true;
   6797     }
   6798 
   6799     @Override
   6800     public int getTextDirection() {
   6801         return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
   6802     }
   6803 
   6804     @Override
   6805     public boolean canResolveTextAlignment() {
   6806         return true;
   6807     }
   6808 
   6809     @Override
   6810     public boolean isTextAlignmentResolved() {
   6811         return true;
   6812     }
   6813 
   6814     @Override
   6815     public int getTextAlignment() {
   6816         return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
   6817     }
   6818 
   6819     private View getCommonPredecessor(View first, View second) {
   6820         if (mTempHashSet == null) {
   6821             mTempHashSet = new HashSet<View>();
   6822         }
   6823         HashSet<View> seen = mTempHashSet;
   6824         seen.clear();
   6825         View firstCurrent = first;
   6826         while (firstCurrent != null) {
   6827             seen.add(firstCurrent);
   6828             ViewParent firstCurrentParent = firstCurrent.mParent;
   6829             if (firstCurrentParent instanceof View) {
   6830                 firstCurrent = (View) firstCurrentParent;
   6831             } else {
   6832                 firstCurrent = null;
   6833             }
   6834         }
   6835         View secondCurrent = second;
   6836         while (secondCurrent != null) {
   6837             if (seen.contains(secondCurrent)) {
   6838                 seen.clear();
   6839                 return secondCurrent;
   6840             }
   6841             ViewParent secondCurrentParent = secondCurrent.mParent;
   6842             if (secondCurrentParent instanceof View) {
   6843                 secondCurrent = (View) secondCurrentParent;
   6844             } else {
   6845                 secondCurrent = null;
   6846             }
   6847         }
   6848         seen.clear();
   6849         return null;
   6850     }
   6851 
   6852     void checkThread() {
   6853         if (mThread != Thread.currentThread()) {
   6854             throw new CalledFromWrongThreadException(
   6855                     "Only the original thread that created a view hierarchy can touch its views.");
   6856         }
   6857     }
   6858 
   6859     @Override
   6860     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
   6861         // ViewAncestor never intercepts touch event, so this can be a no-op
   6862     }
   6863 
   6864     @Override
   6865     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
   6866         if (rectangle == null) {
   6867             return scrollToRectOrFocus(null, immediate);
   6868         }
   6869         rectangle.offset(child.getLeft() - child.getScrollX(),
   6870                 child.getTop() - child.getScrollY());
   6871         final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
   6872         mTempRect.set(rectangle);
   6873         mTempRect.offset(0, -mCurScrollY);
   6874         mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
   6875         try {
   6876             mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
   6877         } catch (RemoteException re) {
   6878             /* ignore */
   6879         }
   6880         return scrolled;
   6881     }
   6882 
   6883     @Override
   6884     public void childHasTransientStateChanged(View child, boolean hasTransientState) {
   6885         // Do nothing.
   6886     }
   6887 
   6888     @Override
   6889     public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
   6890         return false;
   6891     }
   6892 
   6893     @Override
   6894     public void onStopNestedScroll(View target) {
   6895     }
   6896 
   6897     @Override
   6898     public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
   6899     }
   6900 
   6901     @Override
   6902     public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
   6903             int dxUnconsumed, int dyUnconsumed) {
   6904     }
   6905 
   6906     @Override
   6907     public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
   6908     }
   6909 
   6910     @Override
   6911     public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
   6912         return false;
   6913     }
   6914 
   6915     @Override
   6916     public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
   6917         return false;
   6918     }
   6919 
   6920     @Override
   6921     public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
   6922         return false;
   6923     }
   6924 
   6925     /**
   6926      * Force the window to report its next draw.
   6927      * <p>
   6928      * This method is only supposed to be used to speed up the interaction from SystemUI and window
   6929      * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
   6930      * unless you fully understand this interaction.
   6931      * @hide
   6932      */
   6933     public void setReportNextDraw() {
   6934         mReportNextDraw = true;
   6935         invalidate();
   6936     }
   6937 
   6938     void changeCanvasOpacity(boolean opaque) {
   6939         Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
   6940         if (mAttachInfo.mHardwareRenderer != null) {
   6941             mAttachInfo.mHardwareRenderer.setOpaque(opaque);
   6942         }
   6943     }
   6944 
   6945     class TakenSurfaceHolder extends BaseSurfaceHolder {
   6946         @Override
   6947         public boolean onAllowLockCanvas() {
   6948             return mDrawingAllowed;
   6949         }
   6950 
   6951         @Override
   6952         public void onRelayoutContainer() {
   6953             // Not currently interesting -- from changing between fixed and layout size.
   6954         }
   6955 
   6956         @Override
   6957         public void setFormat(int format) {
   6958             ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
   6959         }
   6960 
   6961         @Override
   6962         public void setType(int type) {
   6963             ((RootViewSurfaceTaker)mView).setSurfaceType(type);
   6964         }
   6965 
   6966         @Override
   6967         public void onUpdateSurface() {
   6968             // We take care of format and type changes on our own.
   6969             throw new IllegalStateException("Shouldn't be here");
   6970         }
   6971 
   6972         @Override
   6973         public boolean isCreating() {
   6974             return mIsCreating;
   6975         }
   6976 
   6977         @Override
   6978         public void setFixedSize(int width, int height) {
   6979             throw new UnsupportedOperationException(
   6980                     "Currently only support sizing from layout");
   6981         }
   6982 
   6983         @Override
   6984         public void setKeepScreenOn(boolean screenOn) {
   6985             ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
   6986         }
   6987     }
   6988 
   6989     static class W extends IWindow.Stub {
   6990         private final WeakReference<ViewRootImpl> mViewAncestor;
   6991         private final IWindowSession mWindowSession;
   6992 
   6993         W(ViewRootImpl viewAncestor) {
   6994             mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
   6995             mWindowSession = viewAncestor.mWindowSession;
   6996         }
   6997 
   6998         @Override
   6999         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
   7000                 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
   7001                 Configuration newConfig, Rect backDropFrame, boolean forceLayout,
   7002                 boolean alwaysConsumeNavBar) {
   7003             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7004             if (viewAncestor != null) {
   7005                 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
   7006                         visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame,
   7007                         forceLayout, alwaysConsumeNavBar);
   7008             }
   7009         }
   7010 
   7011         @Override
   7012         public void moved(int newX, int newY) {
   7013             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7014             if (viewAncestor != null) {
   7015                 viewAncestor.dispatchMoved(newX, newY);
   7016             }
   7017         }
   7018 
   7019         @Override
   7020         public void dispatchAppVisibility(boolean visible) {
   7021             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7022             if (viewAncestor != null) {
   7023                 viewAncestor.dispatchAppVisibility(visible);
   7024             }
   7025         }
   7026 
   7027         @Override
   7028         public void dispatchGetNewSurface() {
   7029             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7030             if (viewAncestor != null) {
   7031                 viewAncestor.dispatchGetNewSurface();
   7032             }
   7033         }
   7034 
   7035         @Override
   7036         public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
   7037             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7038             if (viewAncestor != null) {
   7039                 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
   7040             }
   7041         }
   7042 
   7043         private static int checkCallingPermission(String permission) {
   7044             try {
   7045                 return ActivityManagerNative.getDefault().checkPermission(
   7046                         permission, Binder.getCallingPid(), Binder.getCallingUid());
   7047             } catch (RemoteException e) {
   7048                 return PackageManager.PERMISSION_DENIED;
   7049             }
   7050         }
   7051 
   7052         @Override
   7053         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
   7054             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7055             if (viewAncestor != null) {
   7056                 final View view = viewAncestor.mView;
   7057                 if (view != null) {
   7058                     if (checkCallingPermission(Manifest.permission.DUMP) !=
   7059                             PackageManager.PERMISSION_GRANTED) {
   7060                         throw new SecurityException("Insufficient permissions to invoke"
   7061                                 + " executeCommand() from pid=" + Binder.getCallingPid()
   7062                                 + ", uid=" + Binder.getCallingUid());
   7063                     }
   7064 
   7065                     OutputStream clientStream = null;
   7066                     try {
   7067                         clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
   7068                         ViewDebug.dispatchCommand(view, command, parameters, clientStream);
   7069                     } catch (IOException e) {
   7070                         e.printStackTrace();
   7071                     } finally {
   7072                         if (clientStream != null) {
   7073                             try {
   7074                                 clientStream.close();
   7075                             } catch (IOException e) {
   7076                                 e.printStackTrace();
   7077                             }
   7078                         }
   7079                     }
   7080                 }
   7081             }
   7082         }
   7083 
   7084         @Override
   7085         public void closeSystemDialogs(String reason) {
   7086             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7087             if (viewAncestor != null) {
   7088                 viewAncestor.dispatchCloseSystemDialogs(reason);
   7089             }
   7090         }
   7091 
   7092         @Override
   7093         public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
   7094                 boolean sync) {
   7095             if (sync) {
   7096                 try {
   7097                     mWindowSession.wallpaperOffsetsComplete(asBinder());
   7098                 } catch (RemoteException e) {
   7099                 }
   7100             }
   7101         }
   7102 
   7103         @Override
   7104         public void dispatchWallpaperCommand(String action, int x, int y,
   7105                 int z, Bundle extras, boolean sync) {
   7106             if (sync) {
   7107                 try {
   7108                     mWindowSession.wallpaperCommandComplete(asBinder(), null);
   7109                 } catch (RemoteException e) {
   7110                 }
   7111             }
   7112         }
   7113 
   7114         /* Drag/drop */
   7115         @Override
   7116         public void dispatchDragEvent(DragEvent event) {
   7117             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7118             if (viewAncestor != null) {
   7119                 viewAncestor.dispatchDragEvent(event);
   7120             }
   7121         }
   7122 
   7123         @Override
   7124         public void updatePointerIcon(float x, float y) {
   7125             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7126             if (viewAncestor != null) {
   7127                 viewAncestor.updatePointerIcon(x, y);
   7128             }
   7129         }
   7130 
   7131         @Override
   7132         public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
   7133                 int localValue, int localChanges) {
   7134             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7135             if (viewAncestor != null) {
   7136                 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
   7137                         localValue, localChanges);
   7138             }
   7139         }
   7140 
   7141         @Override
   7142         public void dispatchWindowShown() {
   7143             final ViewRootImpl viewAncestor = mViewAncestor.get();
   7144             if (viewAncestor != null) {
   7145                 viewAncestor.dispatchWindowShown();
   7146             }
   7147         }
   7148 
   7149         @Override
   7150         public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
   7151             ViewRootImpl viewAncestor = mViewAncestor.get();
   7152             if (viewAncestor != null) {
   7153                 viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
   7154             }
   7155         }
   7156     }
   7157 
   7158     public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
   7159         public CalledFromWrongThreadException(String msg) {
   7160             super(msg);
   7161         }
   7162     }
   7163 
   7164     static HandlerActionQueue getRunQueue() {
   7165         HandlerActionQueue rq = sRunQueues.get();
   7166         if (rq != null) {
   7167             return rq;
   7168         }
   7169         rq = new HandlerActionQueue();
   7170         sRunQueues.set(rq);
   7171         return rq;
   7172     }
   7173 
   7174     /**
   7175      * Start a drag resizing which will inform all listeners that a window resize is taking place.
   7176      */
   7177     private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
   7178             Rect stableInsets, int resizeMode) {
   7179         if (!mDragResizing) {
   7180             mDragResizing = true;
   7181             for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
   7182                 mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
   7183                         systemInsets, stableInsets, resizeMode);
   7184             }
   7185             mFullRedrawNeeded = true;
   7186         }
   7187     }
   7188 
   7189     /**
   7190      * End a drag resize which will inform all listeners that a window resize has ended.
   7191      */
   7192     private void endDragResizing() {
   7193         if (mDragResizing) {
   7194             mDragResizing = false;
   7195             for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
   7196                 mWindowCallbacks.get(i).onWindowDragResizeEnd();
   7197             }
   7198             mFullRedrawNeeded = true;
   7199         }
   7200     }
   7201 
   7202     private boolean updateContentDrawBounds() {
   7203         boolean updated = false;
   7204         for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
   7205             updated |= mWindowCallbacks.get(i).onContentDrawn(
   7206                     mWindowAttributes.surfaceInsets.left,
   7207                     mWindowAttributes.surfaceInsets.top,
   7208                     mWidth, mHeight);
   7209         }
   7210         return updated | (mDragResizing && mReportNextDraw);
   7211     }
   7212 
   7213     private void requestDrawWindow() {
   7214         if (mReportNextDraw) {
   7215             mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
   7216         }
   7217         for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
   7218             mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
   7219         }
   7220     }
   7221 
   7222     /**
   7223      * Tells this instance that its corresponding activity has just relaunched. In this case, we
   7224      * need to force a relayout of the window to make sure we get the correct bounds from window
   7225      * manager.
   7226      */
   7227     public void reportActivityRelaunched() {
   7228         mActivityRelaunched = true;
   7229     }
   7230 
   7231     /**
   7232      * Class for managing the accessibility interaction connection
   7233      * based on the global accessibility state.
   7234      */
   7235     final class AccessibilityInteractionConnectionManager
   7236             implements AccessibilityStateChangeListener {
   7237         @Override
   7238         public void onAccessibilityStateChanged(boolean enabled) {
   7239             if (enabled) {
   7240                 ensureConnection();
   7241                 if (mAttachInfo.mHasWindowFocus) {
   7242                     mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
   7243                     View focusedView = mView.findFocus();
   7244                     if (focusedView != null && focusedView != mView) {
   7245                         focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
   7246                     }
   7247                 }
   7248             } else {
   7249                 ensureNoConnection();
   7250                 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
   7251             }
   7252         }
   7253 
   7254         public void ensureConnection() {
   7255             final boolean registered =
   7256                     mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
   7257             if (!registered) {
   7258                 mAttachInfo.mAccessibilityWindowId =
   7259                         mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
   7260                                 new AccessibilityInteractionConnection(ViewRootImpl.this));
   7261             }
   7262         }
   7263 
   7264         public void ensureNoConnection() {
   7265             final boolean registered =
   7266                 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
   7267             if (registered) {
   7268                 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
   7269                 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
   7270             }
   7271         }
   7272     }
   7273 
   7274     final class HighContrastTextManager implements HighTextContrastChangeListener {
   7275         HighContrastTextManager() {
   7276             mAttachInfo.mHighContrastText = mAccessibilityManager.isHighTextContrastEnabled();
   7277         }
   7278         @Override
   7279         public void onHighTextContrastStateChanged(boolean enabled) {
   7280             mAttachInfo.mHighContrastText = enabled;
   7281 
   7282             // Destroy Displaylists so they can be recreated with high contrast recordings
   7283             destroyHardwareResources();
   7284 
   7285             // Schedule redraw, which will rerecord + redraw all text
   7286             invalidate();
   7287         }
   7288     }
   7289 
   7290     /**
   7291      * This class is an interface this ViewAncestor provides to the
   7292      * AccessibilityManagerService to the latter can interact with
   7293      * the view hierarchy in this ViewAncestor.
   7294      */
   7295     static final class AccessibilityInteractionConnection
   7296             extends IAccessibilityInteractionConnection.Stub {
   7297         private final WeakReference<ViewRootImpl> mViewRootImpl;
   7298 
   7299         AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
   7300             mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
   7301         }
   7302 
   7303         @Override
   7304         public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
   7305                 Region interactiveRegion, int interactionId,
   7306                 IAccessibilityInteractionConnectionCallback callback, int flags,
   7307                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
   7308             ViewRootImpl viewRootImpl = mViewRootImpl.get();
   7309             if (viewRootImpl != null && viewRootImpl.mView != null) {
   7310                 viewRootImpl.getAccessibilityInteractionController()
   7311                     .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
   7312                             interactiveRegion, interactionId, callback, flags, interrogatingPid,
   7313                             interrogatingTid, spec);
   7314             } else {
   7315                 // We cannot make the call and notify the caller so it does not wait.
   7316                 try {
   7317                     callback.setFindAccessibilityNodeInfosResult(null, interactionId);
   7318                 } catch (RemoteException re) {
   7319                     /* best effort - ignore */
   7320                 }
   7321             }
   7322         }
   7323 
   7324         @Override
   7325         public void performAccessibilityAction(long accessibilityNodeId, int action,
   7326                 Bundle arguments, int interactionId,
   7327                 IAccessibilityInteractionConnectionCallback callback, int flags,
   7328                 int interrogatingPid, long interrogatingTid) {
   7329             ViewRootImpl viewRootImpl = mViewRootImpl.get();
   7330             if (viewRootImpl != null && viewRootImpl.mView != null) {
   7331                 viewRootImpl.getAccessibilityInteractionController()
   7332                     .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
   7333                             interactionId, callback, flags, interrogatingPid, interrogatingTid);
   7334             } else {
   7335                 // We cannot make the call and notify the caller so it does not wait.
   7336                 try {
   7337                     callback.setPerformAccessibilityActionResult(false, interactionId);
   7338                 } catch (RemoteException re) {
   7339                     /* best effort - ignore */
   7340                 }
   7341             }
   7342         }
   7343 
   7344         @Override
   7345         public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
   7346                 String viewId, Region interactiveRegion, int interactionId,
   7347                 IAccessibilityInteractionConnectionCallback callback, int flags,
   7348                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
   7349             ViewRootImpl viewRootImpl = mViewRootImpl.get();
   7350             if (viewRootImpl != null && viewRootImpl.mView != null) {
   7351                 viewRootImpl.getAccessibilityInteractionController()
   7352                     .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
   7353                             viewId, interactiveRegion, interactionId, callback, flags,
   7354                             interrogatingPid, interrogatingTid, spec);
   7355             } else {
   7356                 // We cannot make the call and notify the caller so it does not wait.
   7357                 try {
   7358                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
   7359                 } catch (RemoteException re) {
   7360                     /* best effort - ignore */
   7361                 }
   7362             }
   7363         }
   7364 
   7365         @Override
   7366         public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
   7367                 Region interactiveRegion, int interactionId,
   7368                 IAccessibilityInteractionConnectionCallback callback, int flags,
   7369                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
   7370             ViewRootImpl viewRootImpl = mViewRootImpl.get();
   7371             if (viewRootImpl != null && viewRootImpl.mView != null) {
   7372                 viewRootImpl.getAccessibilityInteractionController()
   7373                     .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
   7374                             interactiveRegion, interactionId, callback, flags, interrogatingPid,
   7375                             interrogatingTid, spec);
   7376             } else {
   7377                 // We cannot make the call and notify the caller so it does not wait.
   7378                 try {
   7379                     callback.setFindAccessibilityNodeInfosResult(null, interactionId);
   7380                 } catch (RemoteException re) {
   7381                     /* best effort - ignore */
   7382                 }
   7383             }
   7384         }
   7385 
   7386         @Override
   7387         public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
   7388                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
   7389                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
   7390             ViewRootImpl viewRootImpl = mViewRootImpl.get();
   7391             if (viewRootImpl != null && viewRootImpl.mView != null) {
   7392                 viewRootImpl.getAccessibilityInteractionController()
   7393                     .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
   7394                             interactionId, callback, flags, interrogatingPid, interrogatingTid,
   7395                             spec);
   7396             } else {
   7397                 // We cannot make the call and notify the caller so it does not wait.
   7398                 try {
   7399                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
   7400                 } catch (RemoteException re) {
   7401                     /* best effort - ignore */
   7402                 }
   7403             }
   7404         }
   7405 
   7406         @Override
   7407         public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
   7408                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
   7409                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
   7410             ViewRootImpl viewRootImpl = mViewRootImpl.get();
   7411             if (viewRootImpl != null && viewRootImpl.mView != null) {
   7412                 viewRootImpl.getAccessibilityInteractionController()
   7413                     .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
   7414                             interactionId, callback, flags, interrogatingPid, interrogatingTid,
   7415                             spec);
   7416             } else {
   7417                 // We cannot make the call and notify the caller so it does not wait.
   7418                 try {
   7419                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
   7420                 } catch (RemoteException re) {
   7421                     /* best effort - ignore */
   7422                 }
   7423             }
   7424         }
   7425     }
   7426 
   7427     private class SendWindowContentChangedAccessibilityEvent implements Runnable {
   7428         private int mChangeTypes = 0;
   7429 
   7430         public View mSource;
   7431         public long mLastEventTimeMillis;
   7432 
   7433         @Override
   7434         public void run() {
   7435             // The accessibility may be turned off while we were waiting so check again.
   7436             if (AccessibilityManager.getInstance(mContext).isEnabled()) {
   7437                 mLastEventTimeMillis = SystemClock.uptimeMillis();
   7438                 AccessibilityEvent event = AccessibilityEvent.obtain();
   7439                 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
   7440                 event.setContentChangeTypes(mChangeTypes);
   7441                 mSource.sendAccessibilityEventUnchecked(event);
   7442             } else {
   7443                 mLastEventTimeMillis = 0;
   7444             }
   7445             // In any case reset to initial state.
   7446             mSource.resetSubtreeAccessibilityStateChanged();
   7447             mSource = null;
   7448             mChangeTypes = 0;
   7449         }
   7450 
   7451         public void runOrPost(View source, int changeType) {
   7452             if (mSource != null) {
   7453                 // If there is no common predecessor, then mSource points to
   7454                 // a removed view, hence in this case always prefer the source.
   7455                 View predecessor = getCommonPredecessor(mSource, source);
   7456                 mSource = (predecessor != null) ? predecessor : source;
   7457                 mChangeTypes |= changeType;
   7458                 return;
   7459             }
   7460             mSource = source;
   7461             mChangeTypes = changeType;
   7462             final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
   7463             final long minEventIntevalMillis =
   7464                     ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
   7465             if (timeSinceLastMillis >= minEventIntevalMillis) {
   7466                 mSource.removeCallbacks(this);
   7467                 run();
   7468             } else {
   7469                 mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
   7470             }
   7471         }
   7472     }
   7473 }
   7474