FileDocCategorySizeDatePackage
ViewRoot.javaAPI DocAndroid 1.5 API116012Wed May 06 22:41:56 BST 2009android.view

ViewRoot

public final class ViewRoot extends Handler implements View.AttachInfo.Callbacks, ViewParent
The top of a view hierarchy, implementing the needed protocol between View and the WindowManager. This is for the most part an internal implementation detail of {@link WindowManagerImpl}. {@hide}

Fields Summary
private static final String
TAG
private static final boolean
DBG
private static final boolean
LOCAL_LOGV
private static final boolean
DEBUG_DRAW
private static final boolean
DEBUG_LAYOUT
private static final boolean
DEBUG_INPUT_RESIZE
private static final boolean
DEBUG_ORIENTATION
private static final boolean
DEBUG_TRACKBALL
private static final boolean
DEBUG_IMF
private static final boolean
WATCH_POINTER
static final boolean
PROFILE_DRAWING
private static final boolean
PROFILE_LAYOUT
private static final boolean
SHOW_FPS
private static int
sDrawTime
static final int
MAX_TRACKBALL_DELAY
Maximum time we allow the user to roll the trackball enough to generate a key event, before resetting the counters.
static long
sInstanceCount
static IWindowSession
sWindowSession
static final Object
mStaticInit
static boolean
mInitialized
static final ThreadLocal
sRunQueues
long
mLastTrackballTime
final TrackballAxis
mTrackballAxisX
final TrackballAxis
mTrackballAxisY
final int[]
mTmpLocation
final InputMethodCallback
mInputMethodCallback
final android.util.SparseArray
mPendingEvents
int
mPendingEventSeq
final Thread
mThread
final WindowLeaked
mLocation
final WindowManager.LayoutParams
mWindowAttributes
final W
mWindow
View
mView
View
mFocusedView
View
mRealFocusedView
int
mViewVisibility
boolean
mAppVisible
final android.graphics.Region
mTransparentRegion
final android.graphics.Region
mPreviousTransparentRegion
int
mWidth
int
mHeight
android.graphics.Rect
mDirty
boolean
mIsAnimating
final View.AttachInfo
mAttachInfo
final android.graphics.Rect
mTempRect
final android.graphics.Rect
mVisRect
final android.graphics.Point
mVisPoint
boolean
mTraversalScheduled
boolean
mWillDrawSoon
boolean
mLayoutRequested
boolean
mFirst
boolean
mReportNextDraw
boolean
mFullRedrawNeeded
boolean
mNewSurfaceNeeded
boolean
mHasHadWindowFocus
boolean
mLastWasImTarget
boolean
mWindowAttributesChanged
Surface
mSurface
boolean
mAdded
boolean
mAddedTouchMode
int
mAddNesting
final android.graphics.Rect
mWinFrame
final android.graphics.Rect
mPendingVisibleInsets
final android.graphics.Rect
mPendingContentInsets
final ViewTreeObserver.InternalInsetsInfo
mLastGivenInsets
boolean
mScrollMayChange
int
mSoftInputMode
View
mLastScrolledFocus
int
mScrollY
int
mCurScrollY
android.widget.Scroller
mScroller
EGL10
mEgl
EGLDisplay
mEglDisplay
EGLContext
mEglContext
EGLSurface
mEglSurface
GL11
mGL
android.graphics.Canvas
mGlCanvas
boolean
mUseGL
boolean
mGlWanted
final ViewConfiguration
mViewConfiguration
android.media.AudioManager
mAudioManager
see {@link #playSoundEffect(int)}
private final float
mDensity
private boolean
mProfile
public static final int
DO_TRAVERSAL
public static final int
DIE
public static final int
RESIZED
public static final int
RESIZED_REPORT
public static final int
WINDOW_FOCUS_CHANGED
public static final int
DISPATCH_KEY
public static final int
DISPATCH_POINTER
public static final int
DISPATCH_TRACKBALL
public static final int
DISPATCH_APP_VISIBILITY
public static final int
DISPATCH_GET_NEW_SURFACE
public static final int
FINISHED_EVENT
public static final int
DISPATCH_KEY_FROM_IME
public static final int
FINISH_INPUT_CONNECTION
public static final int
CHECK_FOCUS
private SurfaceHolder
mHolder
Constructors Summary
public ViewRoot(android.content.Context context)


       
        super();

        ++sInstanceCount;

        // Initialize the statics when this class is first instantiated. This is
        // done here instead of in the static block because Zygote does not
        // allow the spawning of threads.
        synchronized (mStaticInit) {
            if (!mInitialized) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance(context);
                    sWindowSession = IWindowManager.Stub.asInterface(
                            ServiceManager.getService("window"))
                            .openSession(imm.getClient(), imm.getInputContext());
                    mInitialized = true;
                } catch (RemoteException e) {
                }
            }
        }

        mThread = Thread.currentThread();
        mLocation = new WindowLeaked(null);
        mLocation.fillInStackTrace();
        mWidth = -1;
        mHeight = -1;
        mDirty = new Rect();
        mTempRect = new Rect();
        mVisRect = new Rect();
        mVisPoint = new Point();
        mWinFrame = new Rect();
        mWindow = new W(this, context);
        mInputMethodCallback = new InputMethodCallback(this);
        mViewVisibility = View.GONE;
        mTransparentRegion = new Region();
        mPreviousTransparentRegion = new Region();
        mFirst = true; // true for the first time the view is added
        mSurface = new Surface();
        mAdded = false;
        mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
        mViewConfiguration = ViewConfiguration.get(context);
        mDensity = context.getResources().getDisplayMetrics().density;
    
Methods Summary
public voidbringChildToFront(View child)

    
private static voidcaptureKeyLog(java.lang.String subTag, KeyEvent ev)
log motion events

        //check dynamic switch                
        if (ev == null || 
                SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) {
            return;
        }
        StringBuilder sb = new StringBuilder(subTag + ": ");        
        sb.append(ev.getDownTime()).append(',");
        sb.append(ev.getEventTime()).append(',");
        sb.append(ev.getAction()).append(',");
        sb.append(ev.getKeyCode()).append(',");        
        sb.append(ev.getRepeatCount()).append(',");
        sb.append(ev.getMetaState()).append(',");
        sb.append(ev.getDeviceId()).append(',");
        sb.append(ev.getScanCode());
        Log.d(TAG, sb.toString());        
    
private static voidcaptureMotionLog(java.lang.String subTag, MotionEvent ev)
log motion events

        //check dynamic switch        
        if (ev == null ||
                SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) {
            return;
        } 
        
        StringBuilder sb = new StringBuilder(subTag + ": ");        
        sb.append(ev.getDownTime()).append(',");        
        sb.append(ev.getEventTime()).append(',");        
        sb.append(ev.getAction()).append(',");        
        sb.append(ev.getX()).append(',");        
        sb.append(ev.getY()).append(',");        
        sb.append(ev.getPressure()).append(',");        
        sb.append(ev.getSize()).append(',");        
        sb.append(ev.getMetaState()).append(',");        
        sb.append(ev.getXPrecision()).append(',");        
        sb.append(ev.getYPrecision()).append(',");        
        sb.append(ev.getDeviceId()).append(',");        
        sb.append(ev.getEdgeFlags());
        Log.d(TAG, sb.toString());        
    
private voidcheckEglErrors()

        if (mUseGL) {
            int err = mEgl.eglGetError();
            if (err != EGL10.EGL_SUCCESS) {
                // something bad has happened revert to
                // normal rendering.
                destroyGL();
                if (err != EGL11.EGL_CONTEXT_LOST) {
                    // we'll try again if it was context lost
                    mGlWanted = false;
                }
            }
        }
    
private booleancheckForLeavingTouchModeAndConsume(KeyEvent event)
See if the key event means we should leave touch mode (and leave touch mode if so).

param
event The key event.
return
Whether this key event should be consumed (meaning the act of leaving touch mode alone is considered the event).

        if (event.getAction() != KeyEvent.ACTION_DOWN) {
            return false;
        }
        if ((event.getFlags()&KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
            return false;
        }

        // only relevant if we are in touch mode
        if (!mAttachInfo.mInTouchMode) {
            return false;
        }

        // if something like an edit text has focus and the user is typing,
        // leave touch mode
        //
        // note: the condition of not being a keyboard key is kind of a hacky
        // approximation of whether we think the focused view will want the
        // key; if we knew for sure whether the focused view would consume
        // the event, that would be better.
        if (isKeyboardKey(event) && mView != null && mView.hasFocus()) {
            mFocusedView = mView.findFocus();
            if ((mFocusedView instanceof ViewGroup)
                    && ((ViewGroup) mFocusedView).getDescendantFocusability() ==
                    ViewGroup.FOCUS_AFTER_DESCENDANTS) {
                // something has focus, but is holding it weakly as a container
                return false;
            }
            if (ensureTouchMode(false)) {
                throw new IllegalStateException("should not have changed focus "
                        + "when leaving touch mode while a view has focus.");
            }
            return false;
        }

        if (isDirectional(event.getKeyCode())) {
            // no view has focus, so we leave touch mode (and find something
            // to give focus to).  the event is consumed if we were able to
            // find something to give focus to.
            return ensureTouchMode(false);
        }
        return false;
    
voidcheckThread()

        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    
public voidchildDrawableStateChanged(View child)

    
public voidclearChildFocus(View child)

        checkThread();

        View oldFocus = mFocusedView;

        if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus");
        mFocusedView = mRealFocusedView = null;
        if (mView != null && !mView.hasFocus()) {
            // If a view gets the focus, the listener will be invoked from requestChildFocus()
            if (!mView.requestFocus(View.FOCUS_FORWARD)) {
                mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
            }
        } else if (oldFocus != null) {
            mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
        }
    
public voidcreateContextMenu(ContextMenu menu)

    
public voiddebug()

        mView.debug();
    
private voiddeliverKeyEvent(KeyEvent event, boolean sendDone)

        // If mView is null, we just consume the key event because it doesn't
        // make sense to do anything else with it.
        boolean handled = mView != null
                ? mView.dispatchKeyEventPreIme(event) : true;
        if (handled) {
            if (sendDone) {
                if (LOCAL_LOGV) Log.v(
                    "ViewRoot", "Telling window manager key is finished");
                try {
                    sWindowSession.finishKey(mWindow);
                } catch (RemoteException e) {
                }
            }
            return;
        }
        // If it is possible for this window to interact with the input
        // method window, then we want to first dispatch our key events
        // to the input method.
        if (mLastWasImTarget) {
            InputMethodManager imm = InputMethodManager.peekInstance();
            if (imm != null && mView != null) {
                int seq = enqueuePendingEvent(event, sendDone);
                if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
                        + seq + " event=" + event);
                imm.dispatchKeyEvent(mView.getContext(), seq, event,
                        mInputMethodCallback);
                return;
            }
        }
        deliverKeyEventToViewHierarchy(event, sendDone);
    
private voiddeliverKeyEventToViewHierarchy(KeyEvent event, boolean sendDone)

        try {
            if (mView != null && mAdded) {
                final int action = event.getAction();
                boolean isDown = (action == KeyEvent.ACTION_DOWN);

                if (checkForLeavingTouchModeAndConsume(event)) {
                    return;
                }                
                
                if (Config.LOGV) {
                    captureKeyLog("captureDispatchKeyEvent", event);
                }
                boolean keyHandled = mView.dispatchKeyEvent(event);

                if (!keyHandled && isDown) {
                    int direction = 0;
                    switch (event.getKeyCode()) {
                    case KeyEvent.KEYCODE_DPAD_LEFT:
                        direction = View.FOCUS_LEFT;
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT:
                        direction = View.FOCUS_RIGHT;
                        break;
                    case KeyEvent.KEYCODE_DPAD_UP:
                        direction = View.FOCUS_UP;
                        break;
                    case KeyEvent.KEYCODE_DPAD_DOWN:
                        direction = View.FOCUS_DOWN;
                        break;
                    }

                    if (direction != 0) {

                        View focused = mView != null ? mView.findFocus() : null;
                        if (focused != null) {
                            View v = focused.focusSearch(direction);
                            boolean focusPassed = false;
                            if (v != null && v != focused) {
                                // do the math the get the interesting rect
                                // of previous focused into the coord system of
                                // newly focused view
                                focused.getFocusedRect(mTempRect);
                                ((ViewGroup) mView).offsetDescendantRectToMyCoords(focused, mTempRect);
                                ((ViewGroup) mView).offsetRectIntoDescendantCoords(v, mTempRect);
                                focusPassed = v.requestFocus(direction, mTempRect);
                            }

                            if (!focusPassed) {
                                mView.dispatchUnhandledMove(focused, direction);
                            } else {
                                playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
                            }
                        }
                    }
                }
            }

        } finally {
            if (sendDone) {
                if (LOCAL_LOGV) Log.v(
                    "ViewRoot", "Telling window manager key is finished");
                try {
                    sWindowSession.finishKey(mWindow);
                } catch (RemoteException e) {
                }
            }
            // Let the exception fall through -- the looper will catch
            // it and take care of the bad app for us.
        }
    
private voiddeliverTrackballEvent(MotionEvent event)

        boolean didFinish;
        if (event == null) {
            try {
                event = sWindowSession.getPendingTrackballMove(mWindow);
            } catch (RemoteException e) {
            }
            didFinish = true;
        } else {
            didFinish = false;
        }

        if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);

        boolean handled = false;
        try {
            if (event == null) {
                handled = true;
            } else if (mView != null && mAdded) {
                handled = mView.dispatchTrackballEvent(event);
                if (!handled) {
                    // we could do something here, like changing the focus
                    // or something?
                }
            }
        } finally {
            if (handled) {
                if (!didFinish) {
                    try {
                        sWindowSession.finishKey(mWindow);
                    } catch (RemoteException e) {
                    }
                }
                if (event != null) {
                    event.recycle();
                }
                // If we reach this, we delivered a trackball event to mView and
                // mView consumed it. Because we will not translate the trackball
                // event into a key event, touch mode will not exit, so we exit
                // touch mode here.
                ensureTouchMode(false);
                //noinspection ReturnInsideFinallyBlock
                return;
            }
            // Let the exception fall through -- the looper will catch
            // it and take care of the bad app for us.
        }

        final TrackballAxis x = mTrackballAxisX;
        final TrackballAxis y = mTrackballAxisY;

        long curTime = SystemClock.uptimeMillis();
        if ((mLastTrackballTime+MAX_TRACKBALL_DELAY) < curTime) {
            // It has been too long since the last movement,
            // so restart at the beginning.
            x.reset(0);
            y.reset(0);
            mLastTrackballTime = curTime;
        }

        try {
            final int action = event.getAction();
            final int metastate = event.getMetaState();
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    x.reset(2);
                    y.reset(2);
                    deliverKeyEvent(new KeyEvent(curTime, curTime,
                            KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER,
                            0, metastate), false);
                    break;
                case MotionEvent.ACTION_UP:
                    x.reset(2);
                    y.reset(2);
                    deliverKeyEvent(new KeyEvent(curTime, curTime,
                            KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER,
                            0, metastate), false);
                    break;
            }

            if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
                    + x.step + " dir=" + x.dir + " acc=" + x.acceleration
                    + " move=" + event.getX()
                    + " / Y=" + y.position + " step="
                    + y.step + " dir=" + y.dir + " acc=" + y.acceleration
                    + " move=" + event.getY());
            final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
            final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");

            // Generate DPAD events based on the trackball movement.
            // We pick the axis that has moved the most as the direction of
            // the DPAD.  When we generate DPAD events for one axis, then the
            // other axis is reset -- we don't want to perform DPAD jumps due
            // to slight movements in the trackball when making major movements
            // along the other axis.
            int keycode = 0;
            int movement = 0;
            float accel = 1;
            if (xOff > yOff) {
                movement = x.generate((2/event.getXPrecision()));
                if (movement != 0) {
                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
                            : KeyEvent.KEYCODE_DPAD_LEFT;
                    accel = x.acceleration;
                    y.reset(2);
                }
            } else if (yOff > 0) {
                movement = y.generate((2/event.getYPrecision()));
                if (movement != 0) {
                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
                            : KeyEvent.KEYCODE_DPAD_UP;
                    accel = y.acceleration;
                    x.reset(2);
                }
            }

            if (keycode != 0) {
                if (movement < 0) movement = -movement;
                int accelMovement = (int)(movement * accel);
                if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
                        + " accelMovement=" + accelMovement
                        + " accel=" + accel);
                if (accelMovement > movement) {
                    if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
                            + keycode);
                    movement--;
                    deliverKeyEvent(new KeyEvent(curTime, curTime,
                            KeyEvent.ACTION_MULTIPLE, keycode,
                            accelMovement-movement, metastate), false);
                }
                while (movement > 0) {
                    if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
                            + keycode);
                    movement--;
                    curTime = SystemClock.uptimeMillis();
                    deliverKeyEvent(new KeyEvent(curTime, curTime,
                            KeyEvent.ACTION_DOWN, keycode, 0, event.getMetaState()), false);
                    deliverKeyEvent(new KeyEvent(curTime, curTime,
                            KeyEvent.ACTION_UP, keycode, 0, metastate), false);
                }
                mLastTrackballTime = curTime;
            }
        } finally {
            if (!didFinish) {
                try {
                    sWindowSession.finishKey(mWindow);
                } catch (RemoteException e) {
                }
                if (event != null) {
                    event.recycle();
                }
            }
            // Let the exception fall through -- the looper will catch
            // it and take care of the bad app for us.
        }
    
private voiddestroyGL()

        // inform skia that the context is gone
        nativeAbandonGlCaches();

        mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
        mEgl.eglDestroyContext(mEglDisplay, mEglContext);
        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
        mEgl.eglTerminate(mEglDisplay);
        mEglContext = null;
        mEglSurface = null;
        mEglDisplay = null;
        mEgl = null;
        mGlCanvas = null;
        mGL = null;
        mUseGL = false;
    
public voiddie(boolean immediate)

        checkThread();
        if (Config.LOGV) Log.v("ViewRoot", "DIE in " + this + " of " + mSurface);
        synchronized (this) {
            if (mAdded && !mFirst) {
                int viewVisibility = mView.getVisibility();
                boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
                if (mWindowAttributesChanged || viewVisibilityChanged) {
                    // If layout params have been changed, first give them
                    // to the window manager to make sure it has the correct
                    // animation info.
                    try {
                        if ((sWindowSession.relayout(
                                    mWindow, mWindowAttributes,
                                    mView.mMeasuredWidth, mView.mMeasuredHeight,
                                    viewVisibility, false, mWinFrame, mPendingContentInsets,
                                    mPendingVisibleInsets, mSurface)
                                &WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
                            sWindowSession.finishDrawing(mWindow);
                        }
                    } catch (RemoteException e) {
                    }
                }

                mSurface = null;
            }
            if (mAdded) {
                mAdded = false;
                if (immediate) {
                    dispatchDetachedFromWindow();
                } else if (mView != null) {
                    sendEmptyMessage(DIE);
                }
            }
        }
    
public voiddispatchAppVisibility(boolean visible)

        Message msg = obtainMessage(DISPATCH_APP_VISIBILITY);
        msg.arg1 = visible ? 1 : 0;
        sendMessage(msg);
    
voiddispatchDetachedFromWindow()

        if (Config.LOGV) Log.v("ViewRoot", "Detaching in " + this + " of " + mSurface);

        if (mView != null) {
            mView.dispatchDetachedFromWindow();
        }

        mView = null;
        mAttachInfo.mRootView = null;

        if (mUseGL) {
            destroyGL();
        }

        try {
            sWindowSession.remove(mWindow);
        } catch (RemoteException e) {
        }
    
public voiddispatchFinishedEvent(int seq, boolean handled)

        Message msg = obtainMessage(FINISHED_EVENT);
        msg.arg1 = seq;
        msg.arg2 = handled ? 1 : 0;
        sendMessage(msg);
    
public voiddispatchGetNewSurface()

        Message msg = obtainMessage(DISPATCH_GET_NEW_SURFACE);
        sendMessage(msg);
    
public voiddispatchKey(KeyEvent event)

        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            //noinspection ConstantConditions
            if (false && event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
                if (Config.LOGD) Log.d("keydisp",
                        "===================================================");
                if (Config.LOGD) Log.d("keydisp", "Focused view Hierarchy is:");
                debug();

                if (Config.LOGD) Log.d("keydisp",
                        "===================================================");
            }
        }

        Message msg = obtainMessage(DISPATCH_KEY);
        msg.obj = event;

        if (LOCAL_LOGV) Log.v(
            "ViewRoot", "sending key " + event + " to " + mView);

        sendMessageAtTime(msg, event.getEventTime());
    
public voiddispatchPointer(MotionEvent event, long eventTime)

        Message msg = obtainMessage(DISPATCH_POINTER);
        msg.obj = event;
        sendMessageAtTime(msg, eventTime);
    
public voiddispatchResized(int w, int h, android.graphics.Rect coveredInsets, android.graphics.Rect visibleInsets, boolean reportDraw)

        if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w
                + " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
                + " visibleInsets=" + visibleInsets.toShortString()
                + " reportDraw=" + reportDraw);
        Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
        msg.arg1 = w;
        msg.arg2 = h;
        msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
        sendMessage(msg);
    
public voiddispatchTrackball(MotionEvent event, long eventTime)

        Message msg = obtainMessage(DISPATCH_TRACKBALL);
        msg.obj = event;
        sendMessageAtTime(msg, eventTime);
    
private voiddraw(boolean fullRedrawNeeded)

        Surface surface = mSurface;
        if (surface == null || !surface.isValid()) {
            return;
        }

        scrollToRectOrFocus(null, false);

        if (mAttachInfo.mViewScrollChanged) {
            mAttachInfo.mViewScrollChanged = false;
            mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
        }
        
        int yoff;
        final boolean scrolling = mScroller != null
                && mScroller.computeScrollOffset(); 
        if (scrolling) {
            yoff = mScroller.getCurrY();
        } else {
            yoff = mScrollY;
        }
        if (mCurScrollY != yoff) {
            mCurScrollY = yoff;
            fullRedrawNeeded = true;
        }

        Rect dirty = mDirty;
        if (mUseGL) {
            if (!dirty.isEmpty()) {
                Canvas canvas = mGlCanvas;
                if (mGL!=null && canvas != null) {
                    mGL.glDisable(GL_SCISSOR_TEST);
                    mGL.glClearColor(0, 0, 0, 0);
                    mGL.glClear(GL_COLOR_BUFFER_BIT);
                    mGL.glEnable(GL_SCISSOR_TEST);

                    mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
                    canvas.translate(0, -yoff);
                    mView.mPrivateFlags |= View.DRAWN;
                    mView.draw(canvas);
                    canvas.translate(0, yoff);

                    mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
                    checkEglErrors();

                    if (SHOW_FPS) {
                        int now = (int)SystemClock.elapsedRealtime();
                        if (sDrawTime != 0) {
                            nativeShowFPS(canvas, now - sDrawTime);
                        }
                        sDrawTime = now;
                    }
                }
            }
            if (scrolling) {
                mFullRedrawNeeded = true;
                scheduleTraversals();
            }
            return;
        }

        if (fullRedrawNeeded)
            dirty.union(0, 0, mWidth, mHeight);

        if (DEBUG_ORIENTATION || DEBUG_DRAW) {
            Log.v("ViewRoot", "Draw " + mView + "/"
                    + mWindowAttributes.getTitle()
                    + ": dirty={" + dirty.left + "," + dirty.top
                    + "," + dirty.right + "," + dirty.bottom + "} surface="
                    + surface + " surface.isValid()=" + surface.isValid());
        }

        Canvas canvas;
        try {
            canvas = surface.lockCanvas(dirty);
            // TODO: Do this in native
            canvas.setDensityScale(mDensity);
        } catch (Surface.OutOfResourcesException e) {
            Log.e("ViewRoot", "OutOfResourcesException locking surface", e);
            // TODO: we should ask the window manager to do something!
            // for now we just do nothing
            return;
        }

        try {
            if (!dirty.isEmpty() || mIsAnimating) {
                long startTime;

                if (DEBUG_ORIENTATION || DEBUG_DRAW) {
                    Log.v("ViewRoot", "Surface " + surface + " drawing to bitmap w="
                            + canvas.getWidth() + ", h=" + canvas.getHeight());
                    //canvas.drawARGB(255, 255, 0, 0);
                }

                if (PROFILE_DRAWING) {
                    startTime = SystemClock.elapsedRealtime();
                }

                // If this bitmap's format includes an alpha channel, we
                // need to clear it before drawing so that the child will
                // properly re-composite its drawing on a transparent
                // background. This automatically respects the clip/dirty region
                if (!canvas.isOpaque()) {
                    canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
                } else if (yoff != 0) {
                    // If we are applying an offset, we need to clear the area
                    // where the offset doesn't appear to avoid having garbage
                    // left in the blank areas.
                    canvas.drawColor(0, PorterDuff.Mode.CLEAR);
                }

                dirty.setEmpty();
                mIsAnimating = false;
                mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
                canvas.translate(0, -yoff);
                mView.mPrivateFlags |= View.DRAWN;                    
                mView.draw(canvas);
                canvas.translate(0, yoff);

                if (SHOW_FPS) {
                    int now = (int)SystemClock.elapsedRealtime();
                    if (sDrawTime != 0) {
                        nativeShowFPS(canvas, now - sDrawTime);
                    }
                    sDrawTime = now;
                }

                if (PROFILE_DRAWING) {
                    EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
                }
            }
            
        } finally {
            surface.unlockCanvasAndPost(canvas);
        }

        if (LOCAL_LOGV) {
            Log.v("ViewRoot", "Surface " + surface + " unlockCanvasAndPost");
        }
        
        if (scrolling) {
            mFullRedrawNeeded = true;
            scheduleTraversals();
        }
    
intenqueuePendingEvent(java.lang.Object event, boolean sendDone)

        int seq = mPendingEventSeq+1;
        if (seq < 0) seq = 0;
        mPendingEventSeq = seq;
        mPendingEvents.put(seq, event);
        return sendDone ? seq : -seq;
    
booleanensureTouchMode(boolean inTouchMode)
Something in the current window tells us we need to change the touch mode. For example, we are not in touch mode, and the user touches the screen. If the touch mode has changed, tell the window manager, and handle it locally.

param
inTouchMode Whether we want to be in touch mode.
return
True if the touch mode changed and focus changed was changed as a result

        if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
                + "touch mode is " + mAttachInfo.mInTouchMode);
        if (mAttachInfo.mInTouchMode == inTouchMode) return false;

        // tell the window manager
        try {
            sWindowSession.setInTouchMode(inTouchMode);
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }

        // handle the change
        return ensureTouchModeLocally(inTouchMode);
    
private booleanensureTouchModeLocally(boolean inTouchMode)
Ensure that the touch mode for this window is set, and if it is changing, take the appropriate action.

param
inTouchMode Whether we want to be in touch mode.
return
True if the touch mode changed and focus changed was changed as a result

        if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
                + "touch mode is " + mAttachInfo.mInTouchMode);

        if (mAttachInfo.mInTouchMode == inTouchMode) return false;

        mAttachInfo.mInTouchMode = inTouchMode;
        mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);

        return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
    
private booleanenterTouchMode()

        if (mView != null) {
            if (mView.hasFocus()) {
                // note: not relying on mFocusedView here because this could
                // be when the window is first being added, and mFocused isn't
                // set yet.
                final View focused = mView.findFocus();
                if (focused != null && !focused.isFocusableInTouchMode()) {

                    final ViewGroup ancestorToTakeFocus =
                            findAncestorToTakeFocusInTouchMode(focused);
                    if (ancestorToTakeFocus != null) {
                        // there is an ancestor that wants focus after its descendants that
                        // is focusable in touch mode.. give it focus
                        return ancestorToTakeFocus.requestFocus();
                    } else {
                        // nothing appropriate to have focus in touch mode, clear it out
                        mView.unFocus();
                        mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
                        mFocusedView = null;
                        return true;
                    }
                }
            }
        }
        return false;
    
protected voidfinalize()

        super.finalize();
        --sInstanceCount;
    
private ViewGroupfindAncestorToTakeFocusInTouchMode(View focused)
Find an ancestor of focused that wants focus after its descendants and is focusable in touch mode.

param
focused The currently focused view.
return
An appropriate view, or null if no such view exists.

        ViewParent parent = focused.getParent();
        while (parent instanceof ViewGroup) {
            final ViewGroup vgParent = (ViewGroup) parent;
            if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
                    && vgParent.isFocusableInTouchMode()) {
                return vgParent;
            }
            if (vgParent.isRootNamespace()) {
                return null;
            } else {
                parent = vgParent.getParent();
            }
        }
        return null;
    
public ViewfocusSearch(View focused, int direction)
{@inheritDoc}

        checkThread();
        if (!(mView instanceof ViewGroup)) {
            return null;
        }
        return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
    
public voidfocusableViewAvailable(View v)

        checkThread();

        if (mView != null && !mView.hasFocus()) {
            v.requestFocus();
        } else {
            // the one case where will transfer focus away from the current one
            // is if the current view is a view group that prefers to give focus
            // to its children first AND the view is a descendant of it.
            mFocusedView = mView.findFocus();
            boolean descendantsHaveDibsOnFocus =
                    (mFocusedView instanceof ViewGroup) &&
                        (((ViewGroup) mFocusedView).getDescendantFocusability() ==
                                ViewGroup.FOCUS_AFTER_DESCENDANTS);
            if (descendantsHaveDibsOnFocus && isViewDescendantOf(v, mFocusedView)) {
                // If a view gets the focus, the listener will be invoked from requestChildFocus()
                v.requestFocus();
            }
        }
    
private android.media.AudioManagergetAudioManager()

        if (mView == null) {
            throw new IllegalStateException("getAudioManager called when there is no mView");
        }
        if (mAudioManager == null) {
            mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
        }
        return mAudioManager;
    
public booleangetChildVisibleRect(View child, android.graphics.Rect r, android.graphics.Point offset)

        if (child != mView) {
            throw new RuntimeException("child is not mine, honest!");
        }
        // Note: don't apply scroll offset, because we want to know its
        // visibility in the virtual canvas being given to the view hierarchy.
        return r.intersect(0, 0, mWidth, mHeight);
    
intgetHostVisibility()

        return mAppVisible ? mView.getVisibility() : View.GONE;
    
public static longgetInstanceCount()

        return sInstanceCount;
    
final WindowLeakedgetLocation()

        return mLocation;
    
public ViewParentgetParent()

        return null;
    
private intgetRootMeasureSpec(int windowSize, int rootDimension)
Figures out the measure spec for the root view in a window based on it's layout params.

param
windowSize The available width or height of the window
param
rootDimension The layout params for one dimension (width or height) of the window.
return
The measure spec to use to measure the root view.

        int measureSpec;
        switch (rootDimension) {

        case ViewGroup.LayoutParams.FILL_PARENT:
            // Window can't resize. Force root view to be windowSize.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
            break;
        case ViewGroup.LayoutParams.WRAP_CONTENT:
            // Window can resize. Set max size for root view.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
            break;
        default:
            // Window wants to be an exact size. Force root view to be that size.
            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
            break;
        }
        return measureSpec;
    
static android.view.ViewRoot$RunQueuegetRunQueue()


       
        RunQueue rq = sRunQueues.get();
        if (rq != null) {
            return rq;
        }
        rq = new RunQueue();
        sRunQueues.set(rq);
        return rq;
    
public ViewgetView()

        return mView;
    
protected android.graphics.RectgetWindowFrame()

        return mWinFrame;
    
voidhandleAppVisibility(boolean visible)

        if (mAppVisible != visible) {
            mAppVisible = visible;
            scheduleTraversals();
        }
    
voidhandleFinishedEvent(int seq, boolean handled)

        final KeyEvent event = (KeyEvent)retrievePendingEvent(seq);
        if (DEBUG_IMF) Log.v(TAG, "IME finished event: seq=" + seq
                + " handled=" + handled + " event=" + event);
        if (event != null) {
            final boolean sendDone = seq >= 0;
            if (!handled) {
                deliverKeyEventToViewHierarchy(event, sendDone);
                return;
            } else if (sendDone) {
                if (LOCAL_LOGV) Log.v(
                        "ViewRoot", "Telling window manager key is finished");
                try {
                    sWindowSession.finishKey(mWindow);
                } catch (RemoteException e) {
                }
            } else {
                Log.w("ViewRoot", "handleFinishedEvent(seq=" + seq
                        + " handled=" + handled + " ev=" + event
                        + ") neither delivering nor finishing key");
            }
        }
    
voidhandleGetNewSurface()

        mNewSurfaceNeeded = true;
        mFullRedrawNeeded = true;
        scheduleTraversals();
    
public voidhandleMessage(Message msg)


    
        
        switch (msg.what) {
        case View.AttachInfo.INVALIDATE_MSG:
            ((View) msg.obj).invalidate();
            break;
        case View.AttachInfo.INVALIDATE_RECT_MSG:
            final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
            info.target.invalidate(info.left, info.top, info.right, info.bottom);
            info.release();
            break;
        case DO_TRAVERSAL:
            if (mProfile) {
                Debug.startMethodTracing("ViewRoot");
            }

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
            break;
        case FINISHED_EVENT:
            handleFinishedEvent(msg.arg1, msg.arg2 != 0);
            break;
        case DISPATCH_KEY:
            if (LOCAL_LOGV) Log.v(
                "ViewRoot", "Dispatching key "
                + msg.obj + " to " + mView);
            deliverKeyEvent((KeyEvent)msg.obj, true);
            break;
        case DISPATCH_POINTER: {
            MotionEvent event = (MotionEvent)msg.obj;

            boolean didFinish;
            if (event == null) {
                try {
                    event = sWindowSession.getPendingPointerMove(mWindow);
                } catch (RemoteException e) {
                }
                didFinish = true;
            } else {
                didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
            }

            try {
                boolean handled;
                if (mView != null && mAdded && event != null) {

                    // enter touch mode on the down
                    boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
                    if (isDown) {
                        ensureTouchMode(true);
                    }
                    if(Config.LOGV) {
                        captureMotionLog("captureDispatchPointer", event);
                    }
                    event.offsetLocation(0, mCurScrollY);
                    handled = mView.dispatchTouchEvent(event);
                    if (!handled && isDown) {
                        int edgeSlop = mViewConfiguration.getScaledEdgeSlop();

                        final int edgeFlags = event.getEdgeFlags();
                        int direction = View.FOCUS_UP;
                        int x = (int)event.getX();
                        int y = (int)event.getY();
                        final int[] deltas = new int[2];

                        if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
                            direction = View.FOCUS_DOWN;
                            if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
                                deltas[0] = edgeSlop;
                                x += edgeSlop;
                            } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
                                deltas[0] = -edgeSlop;
                                x -= edgeSlop;
                            }
                        } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
                            direction = View.FOCUS_UP;
                            if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
                                deltas[0] = edgeSlop;
                                x += edgeSlop;
                            } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
                                deltas[0] = -edgeSlop;
                                x -= edgeSlop;
                            }
                        } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
                            direction = View.FOCUS_RIGHT;
                        } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
                            direction = View.FOCUS_LEFT;
                        }

                        if (edgeFlags != 0 && mView instanceof ViewGroup) {
                            View nearest = FocusFinder.getInstance().findNearestTouchable(
                                    ((ViewGroup) mView), x, y, direction, deltas);
                            if (nearest != null) {
                                event.offsetLocation(deltas[0], deltas[1]);
                                event.setEdgeFlags(0);
                                mView.dispatchTouchEvent(event);
                            }
                        }
                    }
                }
            } finally {
                if (!didFinish) {
                    try {
                        sWindowSession.finishKey(mWindow);
                    } catch (RemoteException e) {
                    }
                }
                if (event != null) {
                    event.recycle();
                }
                if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
                // Let the exception fall through -- the looper will catch
                // it and take care of the bad app for us.
            }
        } break;
        case DISPATCH_TRACKBALL:
            deliverTrackballEvent((MotionEvent)msg.obj);
            break;
        case DISPATCH_APP_VISIBILITY:
            handleAppVisibility(msg.arg1 != 0);
            break;
        case DISPATCH_GET_NEW_SURFACE:
            handleGetNewSurface();
            break;
        case RESIZED:
            Rect coveredInsets = ((Rect[])msg.obj)[0];
            Rect visibleInsets = ((Rect[])msg.obj)[1];
            if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
                    && mPendingContentInsets.equals(coveredInsets)
                    && mPendingVisibleInsets.equals(visibleInsets)) {
                break;
            }
            // fall through...
        case RESIZED_REPORT:
            if (mAdded) {
                mWinFrame.left = 0;
                mWinFrame.right = msg.arg1;
                mWinFrame.top = 0;
                mWinFrame.bottom = msg.arg2;
                mPendingContentInsets.set(((Rect[])msg.obj)[0]);
                mPendingVisibleInsets.set(((Rect[])msg.obj)[1]);
                if (msg.what == RESIZED_REPORT) {
                    mReportNextDraw = true;
                }
                requestLayout();
            }
            break;
        case WINDOW_FOCUS_CHANGED: {
            if (mAdded) {
                boolean hasWindowFocus = msg.arg1 != 0;
                mAttachInfo.mHasWindowFocus = hasWindowFocus;
                if (hasWindowFocus) {
                    boolean inTouchMode = msg.arg2 != 0;
                    ensureTouchModeLocally(inTouchMode);

                    if (mGlWanted) {
                        checkEglErrors();
                        // we lost the gl context, so recreate it.
                        if (mGlWanted && !mUseGL) {
                            initializeGL();
                            if (mGlCanvas != null) {
                                mGlCanvas.setViewport(mWidth, mHeight);
                            }
                        }
                    }
                }
                
                mLastWasImTarget = WindowManager.LayoutParams
                        .mayUseInputMethod(mWindowAttributes.flags);
                
                InputMethodManager imm = InputMethodManager.peekInstance();
                if (mView != null) {
                    if (hasWindowFocus && imm != null && mLastWasImTarget) {
                        imm.startGettingWindowFocus(mView);
                    }
                    mView.dispatchWindowFocusChanged(hasWindowFocus);
                }
                
                // Note: must be done after the focus change callbacks,
                // so all of the view state is set up correctly.
                if (hasWindowFocus) {
                    if (imm != null && mLastWasImTarget) {
                        imm.onWindowFocus(mView, mView.findFocus(),
                                mWindowAttributes.softInputMode,
                                !mHasHadWindowFocus, mWindowAttributes.flags);
                    }
                    // Clear the forward bit.  We can just do this directly, since
                    // the window manager doesn't care about it.
                    mWindowAttributes.softInputMode &=
                            ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
                    ((WindowManager.LayoutParams)mView.getLayoutParams())
                            .softInputMode &=
                                ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
                    mHasHadWindowFocus = true;
                }
            }
        } break;
        case DIE:
            dispatchDetachedFromWindow();
            break;
        case DISPATCH_KEY_FROM_IME: {
            if (LOCAL_LOGV) Log.v(
                "ViewRoot", "Dispatching key "
                + msg.obj + " from IME to " + mView);
            KeyEvent event = (KeyEvent)msg.obj;
            if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
                // The IME is trying to say this event is from the
                // system!  Bad bad bad!
                event = KeyEvent.changeFlags(event,
                        event.getFlags()&~KeyEvent.FLAG_FROM_SYSTEM);
            }
            deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
        } break;
        case FINISH_INPUT_CONNECTION: {
            InputMethodManager imm = InputMethodManager.peekInstance();
            if (imm != null) {
                imm.reportFinishInputConnection((InputConnection)msg.obj);
            }
        } break;
        case CHECK_FOCUS: {
            InputMethodManager imm = InputMethodManager.peekInstance();
            if (imm != null) {
                imm.checkFocus();
            }
        } break;
        }
    
private voidinitializeGL()

        initializeGLInner();
        int err = mEgl.eglGetError();
        if (err != EGL10.EGL_SUCCESS) {
            // give-up on using GL
            destroyGL();
            mGlWanted = false;
        }
    
private voidinitializeGLInner()

        final EGL10 egl = (EGL10) EGLContext.getEGL();
        mEgl = egl;

        /*
         * Get to the default display.
         */
        final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
        mEglDisplay = eglDisplay;

        /*
         * We can now initialize EGL for that display
         */
        int[] version = new int[2];
        egl.eglInitialize(eglDisplay, version);

        /*
         * Specify a configuration for our opengl session
         * and grab the first configuration that matches is
         */
        final int[] configSpec = {
                EGL10.EGL_RED_SIZE,      5,
                EGL10.EGL_GREEN_SIZE,    6,
                EGL10.EGL_BLUE_SIZE,     5,
                EGL10.EGL_DEPTH_SIZE,    0,
                EGL10.EGL_NONE
        };
        final EGLConfig[] configs = new EGLConfig[1];
        final int[] num_config = new int[1];
        egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, num_config);
        final EGLConfig config = configs[0];

        /*
         * Create an OpenGL ES context. This must be done only once, an
         * OpenGL context is a somewhat heavy object.
         */
        final EGLContext context = egl.eglCreateContext(eglDisplay, config,
                EGL10.EGL_NO_CONTEXT, null);
        mEglContext = context;

        /*
         * Create an EGL surface we can render into.
         */
        final EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, mHolder, null);
        mEglSurface = surface;

        /*
         * Before we can issue GL commands, we need to make sure
         * the context is current and bound to a surface.
         */
        egl.eglMakeCurrent(eglDisplay, surface, surface, context);

        /*
         * Get to the appropriate GL interface.
         * This is simply done by casting the GL context to either
         * GL10 or GL11.
         */
        final GL11 gl = (GL11) context.getGL();
        mGL = gl;
        mGlCanvas = new Canvas(gl);
        mUseGL = true;
    
public voidinvalidateChild(View child, android.graphics.Rect dirty)

        checkThread();
        if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
        if (mCurScrollY != 0) {
            mTempRect.set(dirty);
            mTempRect.offset(0, -mCurScrollY);
            dirty = mTempRect;
        }
        mDirty.union(dirty);
        if (!mWillDrawSoon) {
            scheduleTraversals();
        }
    
public ViewParentinvalidateChildInParent(int[] location, android.graphics.Rect dirty)

        invalidateChild(null, dirty);
        return null;
    
static booleanisDirectional(int keyCode)

param
keyCode The key code
return
True if the key is directional.

        switch (keyCode) {
        case KeyEvent.KEYCODE_DPAD_LEFT:
        case KeyEvent.KEYCODE_DPAD_RIGHT:
        case KeyEvent.KEYCODE_DPAD_UP:
        case KeyEvent.KEYCODE_DPAD_DOWN:
            return true;
        }
        return false;
    
static booleanisInTouchMode()
Indicates whether we are in touch mode. Calling this method triggers an IPC call and should be avoided whenever possible.

return
True, if the device is in touch mode, false otherwise.
hide

        if (mInitialized) {
            try {
                return sWindowSession.getInTouchMode();
            } catch (RemoteException e) {
            }
        }
        return false;
    
private static booleanisKeyboardKey(KeyEvent keyEvent)
Returns true if this key is a keyboard key.

param
keyEvent The key event.
return
whether this key is a keyboard key.

      final int convertedKey = keyEvent.getUnicodeChar();
        return convertedKey > 0;
    
public booleanisLayoutRequested()
{@inheritDoc}

        return mLayoutRequested;
    
private static booleanisViewDescendantOf(View child, View parent)
Return true if child is an ancestor of parent, (or equal to the parent).

        if (child == parent) {
            return true;
        }

        final ViewParent theParent = child.getParent();
        return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
    
private booleanleaveTouchMode()

        if (mView != null) {
            if (mView.hasFocus()) {
                // i learned the hard way to not trust mFocusedView :)
                mFocusedView = mView.findFocus();
                if (!(mFocusedView instanceof ViewGroup)) {
                    // some view has focus, let it keep it
                    return false;
                } else if (((ViewGroup)mFocusedView).getDescendantFocusability() !=
                        ViewGroup.FOCUS_AFTER_DESCENDANTS) {
                    // some view group has focus, and doesn't prefer its children
                    // over itself for focus, so let them keep it.
                    return false;
                }
            }

            // find the best view to give focus to in this brave new non-touch-mode
            // world
            final View focused = focusSearch(null, View.FOCUS_DOWN);
            if (focused != null) {
                return focused.requestFocus(View.FOCUS_DOWN);
            }
        }
        return false;
    
private static native voidnativeAbandonGlCaches()

private static native voidnativeShowFPS(android.graphics.Canvas canvas, int durationMillis)

public booleanperformHapticFeedback(int effectId, boolean always)
{@inheritDoc}

        try {
            return sWindowSession.performHapticFeedback(mWindow, effectId, always);
        } catch (RemoteException e) {
            return false;
        }
    
private voidperformTraversals()

        // cache mView since it is used so much below...
        final View host = mView;

        if (DBG) {
            System.out.println("======================================");
            System.out.println("performTraversals");
            host.debug();
        }

        if (host == null || !mAdded)
            return;

        mTraversalScheduled = false;
        mWillDrawSoon = true;
        boolean windowResizesToFitContent = false;
        boolean fullRedrawNeeded = mFullRedrawNeeded;
        boolean newSurface = false;
        WindowManager.LayoutParams lp = mWindowAttributes;

        int desiredWindowWidth;
        int desiredWindowHeight;
        int childWidthMeasureSpec;
        int childHeightMeasureSpec;

        final View.AttachInfo attachInfo = mAttachInfo;

        final int viewVisibility = getHostVisibility();
        boolean viewVisibilityChanged = mViewVisibility != viewVisibility
                || mNewSurfaceNeeded;

        WindowManager.LayoutParams params = null;
        if (mWindowAttributesChanged) {
            mWindowAttributesChanged = false;
            params = lp;
        }

        if (mFirst) {
            fullRedrawNeeded = true;
            mLayoutRequested = true;

            Display d = new Display(0);
            desiredWindowWidth = d.getWidth();
            desiredWindowHeight = d.getHeight();

            // For the very first time, tell the view hierarchy that it
            // is attached to the window.  Note that at this point the surface
            // object is not initialized to its backing store, but soon it
            // will be (assuming the window is visible).
            attachInfo.mSurface = mSurface;
            attachInfo.mHasWindowFocus = false;
            attachInfo.mWindowVisibility = viewVisibility;
            attachInfo.mRecomputeGlobalAttributes = false;
            attachInfo.mKeepScreenOn = false;
            viewVisibilityChanged = false;
            host.dispatchAttachedToWindow(attachInfo, 0);
            getRunQueue().executeActions(attachInfo.mHandler);
            //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
        } else {
            desiredWindowWidth = mWinFrame.width();
            desiredWindowHeight = mWinFrame.height();
            if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
                if (DEBUG_ORIENTATION) Log.v("ViewRoot",
                        "View " + host + " resized to: " + mWinFrame);
                fullRedrawNeeded = true;
                mLayoutRequested = true;
                windowResizesToFitContent = true;
            }
        }

        if (viewVisibilityChanged) {
            attachInfo.mWindowVisibility = viewVisibility;
            host.dispatchWindowVisibilityChanged(viewVisibility);
            if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
                if (mUseGL) {
                    destroyGL();
                }
            }
            if (viewVisibility == View.GONE) {
                // After making a window gone, we will count it as being
                // shown for the first time the next time it gets focus.
                mHasHadWindowFocus = false;
            }
        }

        boolean insetsChanged = false;
        
        if (mLayoutRequested) {
            if (mFirst) {
                host.fitSystemWindows(mAttachInfo.mContentInsets);
                // make sure touch mode code executes by setting cached value
                // to opposite of the added touch mode.
                mAttachInfo.mInTouchMode = !mAddedTouchMode;
                ensureTouchModeLocally(mAddedTouchMode);
            } else {
                if (!mAttachInfo.mContentInsets.equals(mPendingContentInsets)) {
                    mAttachInfo.mContentInsets.set(mPendingContentInsets);
                    host.fitSystemWindows(mAttachInfo.mContentInsets);
                    insetsChanged = true;
                    if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
                            + mAttachInfo.mContentInsets);
                }
                if (!mAttachInfo.mVisibleInsets.equals(mPendingVisibleInsets)) {
                    mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
                    if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
                            + mAttachInfo.mVisibleInsets);
                }
                if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
                        || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
                    windowResizesToFitContent = true;

                    Display d = new Display(0);
                    desiredWindowWidth = d.getWidth();
                    desiredWindowHeight = d.getHeight();
                }
            }

            childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
            childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);

            // Ask host how big it wants to be
            if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v("ViewRoot",
                    "Measuring " + host + " in display " + desiredWindowWidth
                    + "x" + desiredWindowHeight + "...");
            host.measure(childWidthMeasureSpec, childHeightMeasureSpec);

            if (DBG) {
                System.out.println("======================================");
                System.out.println("performTraversals -- after measure");
                host.debug();
            }
        }

        if (attachInfo.mRecomputeGlobalAttributes) {
            //Log.i(TAG, "Computing screen on!");
            attachInfo.mRecomputeGlobalAttributes = false;
            boolean oldVal = attachInfo.mKeepScreenOn;
            attachInfo.mKeepScreenOn = false;
            host.dispatchCollectViewAttributes(0);
            if (attachInfo.mKeepScreenOn != oldVal) {
                params = lp;
                //Log.i(TAG, "Keep screen on changed: " + attachInfo.mKeepScreenOn);
            }
        }

        if (mFirst || attachInfo.mViewVisibilityChanged) {
            attachInfo.mViewVisibilityChanged = false;
            int resizeMode = mSoftInputMode &
                    WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
            // If we are in auto resize mode, then we need to determine
            // what mode to use now.
            if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
                final int N = attachInfo.mScrollContainers.size();
                for (int i=0; i<N; i++) {
                    if (attachInfo.mScrollContainers.get(i).isShown()) {
                        resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
                    }
                }
                if (resizeMode == 0) {
                    resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
                }
                if ((lp.softInputMode &
                        WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
                    lp.softInputMode = (lp.softInputMode &
                            ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
                            resizeMode;
                    params = lp;
                }
            }
        }
        
        if (params != null && (host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
            if (!PixelFormat.formatHasAlpha(params.format)) {
                params.format = PixelFormat.TRANSLUCENT;
            }
        }

        boolean windowShouldResize = mLayoutRequested && windowResizesToFitContent
            && (mWidth != host.mMeasuredWidth || mHeight != host.mMeasuredHeight);

        final boolean computesInternalInsets =
                attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
        boolean insetsPending = false;
        int relayoutResult = 0;
        if (mFirst || windowShouldResize || insetsChanged
                || viewVisibilityChanged || params != null) {

            if (viewVisibility == View.VISIBLE) {
                // If this window is giving internal insets to the window
                // manager, and it is being added or changing its visibility,
                // then we want to first give the window manager "fake"
                // insets to cause it to effectively ignore the content of
                // the window during layout.  This avoids it briefly causing
                // other windows to resize/move based on the raw frame of the
                // window, waiting until we can finish laying out this window
                // and get back to the window manager with the ultimately
                // computed insets.
                insetsPending = computesInternalInsets
                        && (mFirst || viewVisibilityChanged);
                
                if (mWindowAttributes.memoryType == WindowManager.LayoutParams.MEMORY_TYPE_GPU) {
                    if (params == null) {
                        params = mWindowAttributes;
                    }
                    mGlWanted = true;
                }
            }

            final Rect frame = mWinFrame;
            boolean initialized = false;
            boolean contentInsetsChanged = false;
            boolean visibleInsetsChanged = false;
            try {
                boolean hadSurface = mSurface.isValid();
                int fl = 0;
                if (params != null) {
                    fl = params.flags;
                    if (attachInfo.mKeepScreenOn) {
                        params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
                    }
                }
                relayoutResult = sWindowSession.relayout(
                    mWindow, params, host.mMeasuredWidth, host.mMeasuredHeight,
                    viewVisibility, insetsPending, frame,
                    mPendingContentInsets, mPendingVisibleInsets, mSurface);
                if (params != null) {
                    params.flags = fl;
                }

                if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
                        + " content=" + mPendingContentInsets.toShortString()
                        + " visible=" + mPendingVisibleInsets.toShortString()
                        + " surface=" + mSurface);
                
                contentInsetsChanged = !mPendingContentInsets.equals(
                        mAttachInfo.mContentInsets);
                visibleInsetsChanged = !mPendingVisibleInsets.equals(
                        mAttachInfo.mVisibleInsets);
                if (contentInsetsChanged) {
                    mAttachInfo.mContentInsets.set(mPendingContentInsets);
                    host.fitSystemWindows(mAttachInfo.mContentInsets);
                    if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
                            + mAttachInfo.mContentInsets);
                }
                if (visibleInsetsChanged) {
                    mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
                    if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
                            + mAttachInfo.mVisibleInsets);
                }

                if (!hadSurface) {
                    if (mSurface.isValid()) {
                        // If we are creating a new surface, then we need to
                        // completely redraw it.  Also, when we get to the
                        // point of drawing it we will hold off and schedule
                        // a new traversal instead.  This is so we can tell the
                        // window manager about all of the windows being displayed
                        // before actually drawing them, so it can display then
                        // all at once.
                        newSurface = true;
                        fullRedrawNeeded = true;
    
                        if (mGlWanted && !mUseGL) {
                            initializeGL();
                            initialized = mGlCanvas != null;
                        }
                    }
                } else if (!mSurface.isValid()) {
                    // If the surface has been removed, then reset the scroll
                    // positions.
                    mLastScrolledFocus = null;
                    mScrollY = mCurScrollY = 0;
                    if (mScroller != null) {
                        mScroller.abortAnimation();
                    }
                }
            } catch (RemoteException e) {
            }
            if (DEBUG_ORIENTATION) Log.v(
                    "ViewRoot", "Relayout returned: frame=" + mWinFrame + ", surface=" + mSurface);

            attachInfo.mWindowLeft = frame.left;
            attachInfo.mWindowTop = frame.top;

            // !!FIXME!! This next section handles the case where we did not get the
            // window size we asked for. We should avoid this by getting a maximum size from
            // the window session beforehand.
            mWidth = frame.width();
            mHeight = frame.height();

            if (initialized) {
                mGlCanvas.setViewport(mWidth, mHeight);
            }

            boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                    (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
            if (focusChangedDueToTouchMode || mWidth != host.mMeasuredWidth
                    || mHeight != host.mMeasuredHeight || contentInsetsChanged) {
                childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
                childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

                if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
                        + mWidth + " measuredWidth=" + host.mMeasuredWidth
                        + " mHeight=" + mHeight
                        + " measuredHeight" + host.mMeasuredHeight
                        + " coveredInsetsChanged=" + contentInsetsChanged);
                
                 // Ask host how big it wants to be
                host.measure(childWidthMeasureSpec, childHeightMeasureSpec);

                // Implementation of weights from WindowManager.LayoutParams
                // We just grow the dimensions as needed and re-measure if
                // needs be
                int width = host.mMeasuredWidth;
                int height = host.mMeasuredHeight;
                boolean measureAgain = false;

                if (lp.horizontalWeight > 0.0f) {
                    width += (int) ((mWidth - width) * lp.horizontalWeight);
                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
                            MeasureSpec.EXACTLY);
                    measureAgain = true;
                }
                if (lp.verticalWeight > 0.0f) {
                    height += (int) ((mHeight - height) * lp.verticalWeight);
                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
                            MeasureSpec.EXACTLY);
                    measureAgain = true;
                }

                if (measureAgain) {
                    if (DEBUG_LAYOUT) Log.v(TAG,
                            "And hey let's measure once more: width=" + width
                            + " height=" + height);
                    host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
                }

                mLayoutRequested = true;
            }
        }

        final boolean didLayout = mLayoutRequested;
        boolean triggerGlobalLayoutListener = didLayout
                || attachInfo.mRecomputeGlobalAttributes;
        if (didLayout) {
            mLayoutRequested = false;
            mScrollMayChange = true;
            if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
                "ViewRoot", "Laying out " + host + " to (" +
                host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
            long startTime;
            if (PROFILE_LAYOUT) {
                startTime = SystemClock.elapsedRealtime();
            }

            host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);

            if (PROFILE_LAYOUT) {
                EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
            }

            // By this point all views have been sized and positionned
            // We can compute the transparent area

            if ((host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
                // start out transparent
                // TODO: AVOID THAT CALL BY CACHING THE RESULT?
                host.getLocationInWindow(mTmpLocation);
                mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
                        mTmpLocation[0] + host.mRight - host.mLeft,
                        mTmpLocation[1] + host.mBottom - host.mTop);

                host.gatherTransparentRegion(mTransparentRegion);
                if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
                    mPreviousTransparentRegion.set(mTransparentRegion);
                    // reconfigure window manager
                    try {
                        sWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
                    } catch (RemoteException e) {
                    }
                }
            }


            if (DBG) {
                System.out.println("======================================");
                System.out.println("performTraversals -- after setFrame");
                host.debug();
            }
        }

        if (triggerGlobalLayoutListener) {
            attachInfo.mRecomputeGlobalAttributes = false;
            attachInfo.mTreeObserver.dispatchOnGlobalLayout();
        }

        if (computesInternalInsets) {
            ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
            final Rect givenContent = attachInfo.mGivenInternalInsets.contentInsets;
            final Rect givenVisible = attachInfo.mGivenInternalInsets.visibleInsets;
            givenContent.left = givenContent.top = givenContent.right
                    = givenContent.bottom = givenVisible.left = givenVisible.top
                    = givenVisible.right = givenVisible.bottom = 0;
            attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
            if (insetsPending || !mLastGivenInsets.equals(insets)) {
                mLastGivenInsets.set(insets);
                try {
                    sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
                            insets.contentInsets, insets.visibleInsets);
                } catch (RemoteException e) {
                }
            }
        }
            
        if (mFirst) {
            // handle first focus request
            if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
                    + mView.hasFocus());
            if (mView != null) {
                if (!mView.hasFocus()) {
                    mView.requestFocus(View.FOCUS_FORWARD);
                    mFocusedView = mRealFocusedView = mView.findFocus();
                    if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
                            + mFocusedView);
                } else {
                    mRealFocusedView = mView.findFocus();
                    if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
                            + mRealFocusedView);
                }
            }
        }

        mFirst = false;
        mWillDrawSoon = false;
        mNewSurfaceNeeded = false;
        mViewVisibility = viewVisibility;

        if (mAttachInfo.mHasWindowFocus) {
            final boolean imTarget = WindowManager.LayoutParams
                    .mayUseInputMethod(mWindowAttributes.flags);
            if (imTarget != mLastWasImTarget) {
                mLastWasImTarget = imTarget;
                InputMethodManager imm = InputMethodManager.peekInstance();
                if (imm != null && imTarget) {
                    imm.startGettingWindowFocus(mView);
                    imm.onWindowFocus(mView, mView.findFocus(),
                            mWindowAttributes.softInputMode,
                            !mHasHadWindowFocus, mWindowAttributes.flags);
                }
            }
        }
        
        boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();

        if (!cancelDraw && !newSurface) {
            mFullRedrawNeeded = false;
            draw(fullRedrawNeeded);

            if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0
                    || mReportNextDraw) {
                if (LOCAL_LOGV) {
                    Log.v("ViewRoot", "FINISHED DRAWING: " + mWindowAttributes.getTitle());
                }
                mReportNextDraw = false;
                try {
                    sWindowSession.finishDrawing(mWindow);
                } catch (RemoteException e) {
                }
            }
        } else {
            // We were supposed to report when we are done drawing. Since we canceled the
            // draw, remember it here.
            if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
                mReportNextDraw = true;
            }
            if (fullRedrawNeeded) {
                mFullRedrawNeeded = true;
            }
            // Try again
            scheduleTraversals();
        }
    
public voidplaySoundEffect(int effectId)
{@inheritDoc}

        checkThread();

        final AudioManager audioManager = getAudioManager();

        switch (effectId) {
            case SoundEffectConstants.CLICK:
                audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
                return;
            case SoundEffectConstants.NAVIGATION_DOWN:
                audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
                return;
            case SoundEffectConstants.NAVIGATION_LEFT:
                audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
                return;
            case SoundEffectConstants.NAVIGATION_RIGHT:
                audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
                return;
            case SoundEffectConstants.NAVIGATION_UP:
                audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
                return;
            default:
                throw new IllegalArgumentException("unknown effect id " + effectId +
                        " not defined in " + SoundEffectConstants.class.getCanonicalName());
        }
    
public voidprofile()
Call this to profile the next traversal call. FIXME for perf testing only. Remove eventually


                        
       
        mProfile = true;
    
public voidrecomputeViewAttributes(View child)

        checkThread();
        if (mView == child) {
            mAttachInfo.mRecomputeGlobalAttributes = true;
            if (!mWillDrawSoon) {
                scheduleTraversals();
            }
        }
    
public voidrequestChildFocus(View child, View focused)

        checkThread();
        if (mFocusedView != focused) {
            mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
            scheduleTraversals();
        }
        mFocusedView = mRealFocusedView = focused;
        if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now "
                + mFocusedView);
    
public booleanrequestChildRectangleOnScreen(View child, android.graphics.Rect rectangle, boolean immediate)

        return scrollToRectOrFocus(rectangle, immediate);
    
public voidrequestDisallowInterceptTouchEvent(boolean disallowIntercept)

        // ViewRoot never intercepts touch event, so this can be a no-op
    
public voidrequestLayout()
{@inheritDoc}

        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    
public voidrequestTransparentRegion(View child)

        // the test below should not fail unless someone is messing with us
        checkThread();
        if (mView == child) {
            mView.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
            // Need to make sure we re-evaluate the window attributes next
            // time around, to ensure the window has the correct format.
            mWindowAttributesChanged = true;
        }
    
java.lang.ObjectretrievePendingEvent(int seq)

        if (seq < 0) seq = -seq;
        Object event = mPendingEvents.get(seq);
        if (event != null) {
            mPendingEvents.remove(seq);
        }
        return event;
    
public voidscheduleTraversals()

        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            sendEmptyMessage(DO_TRAVERSAL);
        }
    
booleanscrollToRectOrFocus(android.graphics.Rect rectangle, boolean immediate)

        final View.AttachInfo attachInfo = mAttachInfo;
        final Rect ci = attachInfo.mContentInsets;
        final Rect vi = attachInfo.mVisibleInsets;
        int scrollY = 0;
        boolean handled = false;
        
        if (vi.left > ci.left || vi.top > ci.top
                || vi.right > ci.right || vi.bottom > ci.bottom) {
            // We'll assume that we aren't going to change the scroll
            // offset, since we want to avoid that unless it is actually
            // going to make the focus visible...  otherwise we scroll
            // all over the place.
            scrollY = mScrollY;
            // We can be called for two different situations: during a draw,
            // to update the scroll position if the focus has changed (in which
            // case 'rectangle' is null), or in response to a
            // requestChildRectangleOnScreen() call (in which case 'rectangle'
            // is non-null and we just want to scroll to whatever that
            // rectangle is).
            View focus = mRealFocusedView;
            if (focus != mLastScrolledFocus) {
                // If the focus has changed, then ignore any requests to scroll
                // to a rectangle; first we want to make sure the entire focus
                // view is visible.
                rectangle = null;
            }
            if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
                    + " rectangle=" + rectangle + " ci=" + ci
                    + " vi=" + vi);
            if (focus == mLastScrolledFocus && !mScrollMayChange
                    && rectangle == null) {
                // Optimization: if the focus hasn't changed since last
                // time, and no layout has happened, then just leave things
                // as they are.
                if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
                        + mScrollY + " vi=" + vi.toShortString());
            } else if (focus != null) {
                // We need to determine if the currently focused view is
                // within the visible part of the window and, if not, apply
                // a pan so it can be seen.
                mLastScrolledFocus = focus;
                mScrollMayChange = false;
                if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
                // Try to find the rectangle from the focus view.
                if (focus.getGlobalVisibleRect(mVisRect, null)) {
                    if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
                            + mView.getWidth() + " h=" + mView.getHeight()
                            + " ci=" + ci.toShortString()
                            + " vi=" + vi.toShortString());
                    if (rectangle == null) {
                        focus.getFocusedRect(mTempRect);
                        if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
                                + ": focusRect=" + mTempRect.toShortString());
                        ((ViewGroup) mView).offsetDescendantRectToMyCoords(
                                focus, mTempRect);
                        if (DEBUG_INPUT_RESIZE) Log.v(TAG,
                                "Focus in window: focusRect="
                                + mTempRect.toShortString()
                                + " visRect=" + mVisRect.toShortString());
                    } else {
                        mTempRect.set(rectangle);
                        if (DEBUG_INPUT_RESIZE) Log.v(TAG,
                                "Request scroll to rect: "
                                + mTempRect.toShortString()
                                + " visRect=" + mVisRect.toShortString());
                    }
                    if (mTempRect.intersect(mVisRect)) {
                        if (DEBUG_INPUT_RESIZE) Log.v(TAG,
                                "Focus window visible rect: "
                                + mTempRect.toShortString());
                        if (mTempRect.height() >
                                (mView.getHeight()-vi.top-vi.bottom)) {
                            // If the focus simply is not going to fit, then
                            // best is probably just to leave things as-is.
                            if (DEBUG_INPUT_RESIZE) Log.v(TAG,
                                    "Too tall; leaving scrollY=" + scrollY);
                        } else if ((mTempRect.top-scrollY) < vi.top) {
                            scrollY -= vi.top - (mTempRect.top-scrollY);
                            if (DEBUG_INPUT_RESIZE) Log.v(TAG,
                                    "Top covered; scrollY=" + scrollY);
                        } else if ((mTempRect.bottom-scrollY)
                                > (mView.getHeight()-vi.bottom)) {
                            scrollY += (mTempRect.bottom-scrollY)
                                    - (mView.getHeight()-vi.bottom);
                            if (DEBUG_INPUT_RESIZE) Log.v(TAG,
                                    "Bottom covered; scrollY=" + scrollY);
                        }
                        handled = true;
                    }
                }
            }
        }
        
        if (scrollY != mScrollY) {
            if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
                    + mScrollY + " , new=" + scrollY);
            if (!immediate) {
                if (mScroller == null) {
                    mScroller = new Scroller(mView.getContext());
                }
                mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
            } else if (mScroller != null) {
                mScroller.abortAnimation();
            }
            mScrollY = scrollY;
        }
        
        return handled;
    
voidsetLayoutParams(WindowManager.LayoutParams attrs, boolean newView)

        synchronized (this) {
            int oldSoftInputMode = mWindowAttributes.softInputMode;
            mWindowAttributes.copyFrom(attrs);
            if (newView) {
                mSoftInputMode = attrs.softInputMode;
                requestLayout();
            }
            // Don't lose the mode we last auto-computed.
            if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
                    == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
                mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
                        & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
                        | (oldSoftInputMode
                                & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
            }
            mWindowAttributesChanged = true;
            scheduleTraversals();
        }
    
public voidsetView(View view, WindowManager.LayoutParams attrs, View panelParentView)
We have one child

        synchronized (this) {
            if (mView == null) {
                mWindowAttributes.copyFrom(attrs);
                mSoftInputMode = attrs.softInputMode;
                mWindowAttributesChanged = true;
                mView = view;
                mAttachInfo.mRootView = view;
                if (panelParentView != null) {
                    mAttachInfo.mPanelParentWindowToken
                            = panelParentView.getApplicationWindowToken();
                }
                mAdded = true;
                int res; /* = WindowManagerImpl.ADD_OKAY; */
                
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                requestLayout();
                
                try {
                    res = sWindowSession.add(mWindow, attrs,
                            getHostVisibility(), mAttachInfo.mContentInsets);
                } catch (RemoteException e) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    unscheduleTraversals();
                    throw new RuntimeException("Adding window failed", e);
                }
                mPendingContentInsets.set(mAttachInfo.mContentInsets);
                mPendingVisibleInsets.set(0, 0, 0, 0);
                if (Config.LOGV) Log.v("ViewRoot", "Added window " + mWindow);
                if (res < WindowManagerImpl.ADD_OKAY) {
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mAdded = false;
                    unscheduleTraversals();
                    switch (res) {
                        case WindowManagerImpl.ADD_BAD_APP_TOKEN:
                        case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
                            throw new WindowManagerImpl.BadTokenException(
                                "Unable to add window -- token " + attrs.token
                                + " is not valid; is your activity running?");
                        case WindowManagerImpl.ADD_NOT_APP_TOKEN:
                            throw new WindowManagerImpl.BadTokenException(
                                "Unable to add window -- token " + attrs.token
                                + " is not for an application");
                        case WindowManagerImpl.ADD_APP_EXITING:
                            throw new WindowManagerImpl.BadTokenException(
                                "Unable to add window -- app for token " + attrs.token
                                + " is exiting");
                        case WindowManagerImpl.ADD_DUPLICATE_ADD:
                            throw new WindowManagerImpl.BadTokenException(
                                "Unable to add window -- window " + mWindow
                                + " has already been added");
                        case WindowManagerImpl.ADD_STARTING_NOT_NEEDED:
                            // Silently ignore -- we would have just removed it
                            // right away, anyway.
                            return;
                        case WindowManagerImpl.ADD_MULTIPLE_SINGLETON:
                            throw new WindowManagerImpl.BadTokenException(
                                "Unable to add window " + mWindow +
                                " -- another window of this type already exists");
                        case WindowManagerImpl.ADD_PERMISSION_DENIED:
                            throw new WindowManagerImpl.BadTokenException(
                                "Unable to add window " + mWindow +
                                " -- permission denied for this window type");
                    }
                    throw new RuntimeException(
                        "Unable to add window -- unknown error code " + res);
                }
                view.assignParent(this);
                mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0;
                mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0;
            }
        }
    
public booleanshowContextMenuForChild(View originalView)

        return false;
    
public voidunscheduleTraversals()

        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            removeMessages(DO_TRAVERSAL);
        }
    
public voidwindowFocusChanged(boolean hasFocus, boolean inTouchMode)

        Message msg = Message.obtain();
        msg.what = WINDOW_FOCUS_CHANGED;
        msg.arg1 = hasFocus ? 1 : 0;
        msg.arg2 = inTouchMode ? 1 : 0;
        sendMessage(msg);