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