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