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