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