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