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