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