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