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