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