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