OSDN Git Service

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