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