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