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