FileDocCategorySizeDatePackage
Workspace.javaAPI DocAndroid 1.5 API48565Wed May 06 22:42:46 BST 2009com.android.launcher

Workspace

public class Workspace extends android.view.ViewGroup implements DropTarget, DragSource, DragScroller
The workspace is a wide area with a wallpaper and a finite number of screens. Each screen contains a number of icons, folders or widgets the user can interact with. A workspace is meant to be used with a fixed width only.

Fields Summary
private static final int
INVALID_SCREEN
private static final int
SNAP_VELOCITY
The velocity at which a fling gesture will cause us to snap to the next screen
private int
mDefaultScreen
private android.graphics.Paint
mPaint
private android.graphics.Bitmap
mWallpaper
private int
mWallpaperWidth
private int
mWallpaperHeight
private float
mWallpaperOffset
private boolean
mWallpaperLoaded
private boolean
mFirstLayout
private int
mCurrentScreen
private int
mNextScreen
private android.widget.Scroller
mScroller
private android.view.VelocityTracker
mVelocityTracker
private CellLayout.CellInfo
mDragInfo
CellInfo for the cell that is currently being dragged
private float
mLastMotionX
private float
mLastMotionY
private static final int
TOUCH_STATE_REST
private static final int
TOUCH_STATE_SCROLLING
private int
mTouchState
private OnLongClickListener
mLongClickListener
private Launcher
mLauncher
private DragController
mDragger
private int[]
mTempCell
private boolean
mAllowLongPress
private boolean
mLocked
private int
mTouchSlop
final android.graphics.Rect
mDrawerBounds
final android.graphics.Rect
mClipBounds
int
mDrawerContentHeight
int
mDrawerContentWidth
Constructors Summary
public Workspace(android.content.Context context, android.util.AttributeSet attrs)
Used to inflate the Workspace from XML.

param
context The application's context.
param
attrs The attribtues set containing the Workspace's customization values.


                               
         
        this(context, attrs, 0);
    
public Workspace(android.content.Context context, android.util.AttributeSet attrs, int defStyle)
Used to inflate the Workspace from XML.

param
context The application's context.
param
attrs The attribtues set containing the Workspace's customization values.
param
defStyle Unused.

        super(context, attrs, defStyle);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0);
        mDefaultScreen = a.getInt(R.styleable.Workspace_defaultScreen, 1);
        a.recycle();

        initWorkspace();
    
Methods Summary
public booleanacceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, java.lang.Object dragInfo)


        final CellLayout.CellInfo cellInfo = mDragInfo;
        int cellHSpan = cellInfo == null ? 1 : cellInfo.spanX;
        int cellVSpan = cellInfo == null ? 1 : cellInfo.spanY;

        return ((CellLayout) getChildAt(mCurrentScreen)).acceptChildDrop(x - xOffset, y - yOffset,
                cellHSpan, cellVSpan, cellInfo == null ? null : cellInfo.cell);
    
voidaddApplicationShortcut(ApplicationInfo info, CellLayout.CellInfo cellInfo)

        addApplicationShortcut(info, cellInfo, false);
    
voidaddApplicationShortcut(ApplicationInfo info, CellLayout.CellInfo cellInfo, boolean insertAtFirst)

        final CellLayout layout = (CellLayout) getChildAt(cellInfo.screen);
        final int[] result = new int[2];

        layout.cellToPoint(cellInfo.cellX, cellInfo.cellY, result);
        onDropExternal(result[0], result[1], info, layout, insertAtFirst);
    
public voidaddFocusables(java.util.ArrayList views, int direction)

        if (mLauncher.isDrawerDown()) {
            final Folder openFolder = getOpenFolder();
            if (openFolder == null) {
                getChildAt(mCurrentScreen).addFocusables(views, direction);
                if (direction == View.FOCUS_LEFT) {
                    if (mCurrentScreen > 0) {
                        getChildAt(mCurrentScreen - 1).addFocusables(views, direction);
                    }
                } else if (direction == View.FOCUS_RIGHT){
                    if (mCurrentScreen < getChildCount() - 1) {
                        getChildAt(mCurrentScreen + 1).addFocusables(views, direction);
                    }
                }
            } else {
                openFolder.addFocusables(views, direction);
            }
        }
    
voidaddInCurrentScreen(android.view.View child, int x, int y, int spanX, int spanY)
Adds the specified child in the current screen. The position and dimension of the child are defined by x, y, spanX and spanY.

param
child The child to add in one of the workspace's screens.
param
x The X position of the child in the screen's grid.
param
y The Y position of the child in the screen's grid.
param
spanX The number of cells spanned horizontally by the child.
param
spanY The number of cells spanned vertically by the child.

        addInScreen(child, mCurrentScreen, x, y, spanX, spanY, false);
    
voidaddInCurrentScreen(android.view.View child, int x, int y, int spanX, int spanY, boolean insert)
Adds the specified child in the current screen. The position and dimension of the child are defined by x, y, spanX and spanY.

param
child The child to add in one of the workspace's screens.
param
x The X position of the child in the screen's grid.
param
y The Y position of the child in the screen's grid.
param
spanX The number of cells spanned horizontally by the child.
param
spanY The number of cells spanned vertically by the child.
param
insert When true, the child is inserted at the beginning of the children list.

        addInScreen(child, mCurrentScreen, x, y, spanX, spanY, insert);
    
voidaddInScreen(android.view.View child, int screen, int x, int y, int spanX, int spanY)
Adds the specified child in the specified screen. The position and dimension of the child are defined by x, y, spanX and spanY.

param
child The child to add in one of the workspace's screens.
param
screen The screen in which to add the child.
param
x The X position of the child in the screen's grid.
param
y The Y position of the child in the screen's grid.
param
spanX The number of cells spanned horizontally by the child.
param
spanY The number of cells spanned vertically by the child.

        addInScreen(child, screen, x, y, spanX, spanY, false);
    
voidaddInScreen(android.view.View child, int screen, int x, int y, int spanX, int spanY, boolean insert)
Adds the specified child in the specified screen. The position and dimension of the child are defined by x, y, spanX and spanY.

param
child The child to add in one of the workspace's screens.
param
screen The screen in which to add the child.
param
x The X position of the child in the screen's grid.
param
y The Y position of the child in the screen's grid.
param
spanX The number of cells spanned horizontally by the child.
param
spanY The number of cells spanned vertically by the child.
param
insert When true, the child is inserted at the beginning of the children list.

        if (screen < 0 || screen >= getChildCount()) {
            throw new IllegalStateException("The screen must be >= 0 and < " + getChildCount());
        }

        final CellLayout group = (CellLayout) getChildAt(screen);
        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
        if (lp == null) {
            lp = new CellLayout.LayoutParams(x, y, spanX, spanY);
        } else {
            lp.cellX = x;
            lp.cellY = y;
            lp.cellHSpan = spanX;
            lp.cellVSpan = spanY;
        }
        group.addView(child, insert ? 0 : -1, lp);
        if (!(child instanceof Folder)) {
            child.setOnLongClickListener(mLongClickListener);
        }
    
public voidaddView(android.view.View child, int index, LayoutParams params)

        if (!(child instanceof CellLayout)) {
            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
        }
        super.addView(child, index, params);
    
public voidaddView(android.view.View child)

        if (!(child instanceof CellLayout)) {
            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
        }
        super.addView(child);
    
public voidaddView(android.view.View child, int index)

        if (!(child instanceof CellLayout)) {
            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
        }
        super.addView(child, index);
    
public voidaddView(android.view.View child, int width, int height)

        if (!(child instanceof CellLayout)) {
            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
        }
        super.addView(child, width, height);
    
public voidaddView(android.view.View child, LayoutParams params)

        if (!(child instanceof CellLayout)) {
            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
        }
        super.addView(child, params);
    
voidaddWidget(android.view.View view, Widget widget)

        addInScreen(view, widget.screen, widget.cellX, widget.cellY, widget.spanX,
                widget.spanY, false);
    
voidaddWidget(android.view.View view, Widget widget, boolean insert)

        addInScreen(view, widget.screen, widget.cellX, widget.cellY, widget.spanX,
                widget.spanY, insert);
    
public booleanallowLongPress()

return
True is long presses are still allowed for the current touch

        return mAllowLongPress;
    
public voidcellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, android.graphics.RectF rect)
Computes a bounding rectangle for a range of cells

param
cellX X coordinate of upper left corner expressed as a cell position
param
cellY Y coordinate of upper left corner expressed as a cell position
param
cellHSpan Width in cells
param
cellVSpan Height in cells
param
rect Rectnagle into which to put the results

        ((CellLayout)getChildAt(mCurrentScreen)).cellToRect(cellX, cellY,
                cellHSpan, cellVSpan, rect);
    
voidclearChildrenCache()

        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final CellLayout layout = (CellLayout) getChildAt(i);
            layout.setChildrenDrawnWithCacheEnabled(false);
        }
    
public voidcomputeScroll()

        if (mScroller.computeScrollOffset()) {
            mScrollX = mScroller.getCurrX();
            mScrollY = mScroller.getCurrY();
            postInvalidate();
        } else if (mNextScreen != INVALID_SCREEN) {
            mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));
            Launcher.setScreen(mCurrentScreen);
            mNextScreen = INVALID_SCREEN;
            clearChildrenCache();
        }
    
protected voiddispatchDraw(android.graphics.Canvas canvas)

        boolean restore = false;

        // If the all apps drawer is open and the drawing region for the workspace
        // is contained within the drawer's bounds, we skip the drawing. This requires
        // the drawer to be fully opaque.
        if (mLauncher.isDrawerUp()) {
            final Rect clipBounds = mClipBounds;
            canvas.getClipBounds(clipBounds);
            clipBounds.offset(-mScrollX, -mScrollY);
            if (mDrawerBounds.contains(clipBounds)) {
                return;
            }
        } else if (mLauncher.isDrawerMoving()) {
            restore = true;
            canvas.save(Canvas.CLIP_SAVE_FLAG);

            final View view = mLauncher.getDrawerHandle();
            final int top = view.getTop() + view.getHeight();

            canvas.clipRect(mScrollX, top, mScrollX + mDrawerContentWidth,
                    top + mDrawerContentHeight, Region.Op.DIFFERENCE);
        }

        float x = mScrollX * mWallpaperOffset;
        if (x + mWallpaperWidth < mRight - mLeft) {
            x = mRight - mLeft - mWallpaperWidth;
        }

        canvas.drawBitmap(mWallpaper, x, (mBottom - mTop - mWallpaperHeight) / 2, mPaint);

        // ViewGroup.dispatchDraw() supports many features we don't need:
        // clip to padding, layout animation, animation listener, disappearing
        // children, etc. The following implementation attempts to fast-track
        // the drawing dispatch by drawing only what we know needs to be drawn.

        boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN;
        // If we are not scrolling or flinging, draw only the current screen
        if (fastDraw) {
            drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime());
        } else {
            final long drawingTime = getDrawingTime();
            // If we are flinging, draw only the current screen and the target screen
            if (mNextScreen >= 0 && mNextScreen < getChildCount() &&
                    Math.abs(mCurrentScreen - mNextScreen) == 1) {
                drawChild(canvas, getChildAt(mCurrentScreen), drawingTime);
                drawChild(canvas, getChildAt(mNextScreen), drawingTime);
            } else {
                // If we are scrolling, draw all of our children
                final int count = getChildCount();
                for (int i = 0; i < count; i++) {
                    drawChild(canvas, getChildAt(i), drawingTime);
                }
            }
        }

        if (restore) {
            canvas.restore();
        }
    
public booleandispatchUnhandledMove(android.view.View focused, int direction)

        if (direction == View.FOCUS_LEFT) {
            if (getCurrentScreen() > 0) {
                snapToScreen(getCurrentScreen() - 1);
                return true;
            }
        } else if (direction == View.FOCUS_RIGHT) {
            if (getCurrentScreen() < getChildCount() - 1) {
                snapToScreen(getCurrentScreen() + 1);
                return true;
            }
        }
        return super.dispatchUnhandledMove(focused, direction);
    
voidenableChildrenCache()

        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final CellLayout layout = (CellLayout) getChildAt(i);
            layout.setChildrenDrawnWithCacheEnabled(true);
            layout.setChildrenDrawingCacheEnabled(true);
        }
    
CellLayout.CellInfofindAllVacantCells(boolean[] occupied)

        CellLayout group = (CellLayout) getChildAt(mCurrentScreen);
        if (group != null) {
            return group.findAllVacantCells(occupied);
        }
        return null;
    
private SearchfindSearchWidget(CellLayout screen)
Find a search widget on the given screen

        final int count = screen.getChildCount();
        for (int i = 0; i < count; i++) {
            View v = screen.getChildAt(i);
            if (v instanceof Search) {
                return (Search) v;
            }
        }
        return null;
    
voidfitInCurrentScreen(android.view.View child, int spanX, int spanY)
Adds the specified child in the current screen. The position and dimension of the child are defined by x, y, spanX and spanY.

param
child The child to add in one of the workspace's screens.
param
spanX The number of cells spanned horizontally by the child.
param
spanY The number of cells spanned vertically by the child.

        fitInScreen(child, mCurrentScreen, spanX, spanY);
    
voidfitInScreen(android.view.View child, int screen, int spanX, int spanY)
Adds the specified child in the specified screen. The position and dimension of the child are defined by x, y, spanX and spanY.

param
child The child to add in one of the workspace's screens.
param
screen The screen in which to add the child.
param
spanX The number of cells spanned horizontally by the child.
param
spanY The number of cells spanned vertically by the child.

        if (screen < 0 || screen >= getChildCount()) {
            throw new IllegalStateException("The screen must be >= 0 and < " + getChildCount());
        }

        final CellLayout group = (CellLayout) getChildAt(screen);
        boolean vacant = group.getVacantCell(mTempCell, spanX, spanY);
        if (vacant) {
            group.addView(child,
                    new CellLayout.LayoutParams(mTempCell[0], mTempCell[1], spanX, spanY));
            child.setOnLongClickListener(mLongClickListener);
            if (!(child instanceof Folder)) {
                child.setOnLongClickListener(mLongClickListener);
            }
        }
    
private booleanfocusOnSearch(int screen)
Focuses on the search widget on the specified screen, if there is one. Also clears the current search selection so we don't

        CellLayout currentScreen = (CellLayout) getChildAt(screen);
        final Search searchWidget = findSearchWidget(currentScreen);
        if (searchWidget != null) {
            // This is necessary when focus on search is requested from the menu
            // If the workspace was not in touch mode before the menu is invoked
            // and the user clicks "Search" by touching the menu item, the following
            // happens:
            //
            // - We request focus from touch on the search widget
            // - The search widget gains focus
            // - The window focus comes back to Home's window
            // - The touch mode change is propagated to Home's window
            // - The search widget is not focusable in touch mode and ViewRoot
            //   clears its focus
            //
            // Forcing focusable in touch mode ensures the search widget will
            // keep the focus no matter what happens.
            //
            // Note: the search input field disables focusable in touch mode
            // after the window gets the focus back, see SearchAutoCompleteTextView
            final SearchAutoCompleteTextView input = searchWidget.getSearchInputField();
            input.setFocusableInTouchMode(true);
            input.showKeyboardOnNextFocus();

            if (isInTouchMode()) {
                searchWidget.requestFocusFromTouch();
            } else {
                searchWidget.requestFocus();
            }
            searchWidget.clearQuery();
            return true;
        }
        return false;
    
intgetCurrentScreen()
Returns the index of the currently displayed screen.

return
The index of the currently displayed screen.

        return mCurrentScreen;
    
public FoldergetFolderForTag(java.lang.Object tag)

        int screenCount = getChildCount();
        for (int screen = 0; screen < screenCount; screen++) {
            CellLayout currentScreen = ((CellLayout) getChildAt(screen));
            int count = currentScreen.getChildCount();
            for (int i = 0; i < count; i++) {
                View child = currentScreen.getChildAt(i);
                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
                if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
                    Folder f = (Folder) child;
                    if (f.getInfo() == tag) {
                        return f;
                    }
                }
            }
        }
        return null;
    
FoldergetOpenFolder()

return
The open folder on the current screen, or null if there is none

        CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen);
        int count = currentScreen.getChildCount();
        for (int i = 0; i < count; i++) {
            View child = currentScreen.getChildAt(i);
            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
            if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
                return (Folder) child;
            }
        }
        return null;
    
java.util.ArrayListgetOpenFolders()

        final int screens = getChildCount();
        ArrayList<Folder> folders = new ArrayList<Folder>(screens);

        for (int screen = 0; screen < screens; screen++) {
            CellLayout currentScreen = (CellLayout) getChildAt(screen);
            int count = currentScreen.getChildCount();
            for (int i = 0; i < count; i++) {
                View child = currentScreen.getChildAt(i);
                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
                if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
                    folders.add((Folder) child);
                    break;
                }
            }
        }

        return folders;
    
public intgetScreenForView(android.view.View v)

        int result = -1;
        if (v != null) {
            ViewParent vp = v.getParent();
            int count = getChildCount();
            for (int i = 0; i < count; i++) {
                if (vp == getChildAt(i)) {
                    return i;
                }
            }
        }
        return result;
    
booleangetVacantCell(int[] vacant, int spanX, int spanY)
Returns the coordinate of a vacant cell for the current screen.

        CellLayout group = (CellLayout) getChildAt(mCurrentScreen);
        if (group != null) {
            return group.getVacantCell(vacant, spanX, spanY);
        }
        return false;
    
public android.view.ViewgetViewForTag(java.lang.Object tag)

        int screenCount = getChildCount();
        for (int screen = 0; screen < screenCount; screen++) {
            CellLayout currentScreen = ((CellLayout) getChildAt(screen));
            int count = currentScreen.getChildCount();
            for (int i = 0; i < count; i++) {
                View child = currentScreen.getChildAt(i);
                if (child.getTag() == tag) {
                    return child;
                }
            }
        }
        return null;
    
private voidinitWorkspace()
Initializes various states for this workspace.

        mScroller = new Scroller(getContext());
        mCurrentScreen = mDefaultScreen;
        Launcher.setScreen(mCurrentScreen);

        mPaint = new Paint();
        mPaint.setDither(false);

        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
    
booleanisDefaultScreenShowing()

        return mCurrentScreen == mDefaultScreen;
    
voidloadWallpaper(android.graphics.Bitmap bitmap)
Set the background's wallpaper.

        mWallpaper = bitmap;
        mWallpaperLoaded = true;
        requestLayout();
        invalidate();
    
public voidlock()
Locks the SlidingDrawer so that touch events are ignores.

see
#unlock()

        mLocked = true;
    
voidmoveToDefaultScreen()

        snapToScreen(mDefaultScreen);
        getChildAt(mDefaultScreen).requestFocus();
    
public voidonDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, java.lang.Object dragInfo)

    
public voidonDragExit(DragSource source, int x, int y, int xOffset, int yOffset, java.lang.Object dragInfo)

    
public voidonDragOver(DragSource source, int x, int y, int xOffset, int yOffset, java.lang.Object dragInfo)

    
public voidonDrop(DragSource source, int x, int y, int xOffset, int yOffset, java.lang.Object dragInfo)

        final CellLayout cellLayout = (CellLayout) getChildAt(mCurrentScreen);
        if (source != this) {
            onDropExternal(x - xOffset, y - yOffset, dragInfo, cellLayout);
        } else {
            // Move internally
            if (mDragInfo != null) {
                final View cell = mDragInfo.cell;
                if (mCurrentScreen != mDragInfo.screen) {
                    final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                    originalCellLayout.removeView(cell);
                    cellLayout.addView(cell);
                }
                cellLayout.onDropChild(cell, x - xOffset, y - yOffset);

                final ItemInfo info = (ItemInfo)cell.getTag();
                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
                LauncherModel.moveItemInDatabase(mLauncher, info,
                        LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
            }
        }
    
public voidonDropCompleted(android.view.View target, boolean success)

        if (success){
            if (target != this && mDragInfo != null) {
                final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                cellLayout.removeView(mDragInfo.cell);
                final Object tag = mDragInfo.cell.getTag();
                Launcher.getModel().removeDesktopItem((ItemInfo) tag);
            }
        } else {
            if (mDragInfo != null) {
                final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                cellLayout.onDropAborted(mDragInfo.cell);
            }
        }

        mDragInfo = null;
    
private voidonDropExternal(int x, int y, java.lang.Object dragInfo, CellLayout cellLayout)

        onDropExternal(x, y, dragInfo, cellLayout, false);
    
private voidonDropExternal(int x, int y, java.lang.Object dragInfo, CellLayout cellLayout, boolean insertAtFirst)

        // Drag from somewhere else
        ItemInfo info = (ItemInfo) dragInfo;

        View view;

        switch (info.itemType) {
        case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
        case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
            if (info.container == NO_ID) {
                // Came from all apps -- make a copy
                info = new ApplicationInfo((ApplicationInfo) info);
            }
            view = mLauncher.createShortcut(R.layout.application, cellLayout,
                    (ApplicationInfo) info);
            break;
        case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
            view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
                    (ViewGroup) getChildAt(mCurrentScreen), ((UserFolderInfo) info));
            break;
        default:
            throw new IllegalStateException("Unknown item type: " + info.itemType);
        }

        cellLayout.addView(view, insertAtFirst ? 0 : -1);
        view.setOnLongClickListener(mLongClickListener);
        cellLayout.onDropChild(view, x, y);
        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();

        final LauncherModel model = Launcher.getModel();
        model.addDesktopItem(info);
        LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
                LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
    
public booleanonInterceptTouchEvent(android.view.MotionEvent ev)

        if (mLocked || !mLauncher.isDrawerDown()) {
            return true;
        }

        /*
         * This method JUST determines whether we want to intercept the motion.
         * If we return true, onTouchEvent will be called and we do the actual
         * scrolling there.
         */

        /*
         * Shortcut the most recurring case: the user is in the dragging
         * state and he is moving his finger.  We want to intercept this
         * motion.
         */
        final int action = ev.getAction();
        if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {
            return true;
        }

        final float x = ev.getX();
        final float y = ev.getY();

        switch (action) {
            case MotionEvent.ACTION_MOVE:
                /*
                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
                 * whether the user has moved far enough from his original down touch.
                 */

                /*
                 * Locally do absolute value. mLastMotionX is set to the y value
                 * of the down event.
                 */
                final int xDiff = (int) Math.abs(x - mLastMotionX);
                final int yDiff = (int) Math.abs(y - mLastMotionY);

                final int touchSlop = mTouchSlop;
                boolean xMoved = xDiff > touchSlop;
                boolean yMoved = yDiff > touchSlop;
                
                if (xMoved || yMoved) {
                    
                    if (xMoved) {
                        // Scroll if the user moved far enough along the X axis
                        mTouchState = TOUCH_STATE_SCROLLING;
                        enableChildrenCache();
                    }
                    // Either way, cancel any pending longpress
                    if (mAllowLongPress) {
                        mAllowLongPress = false;
                        // Try canceling the long press. It could also have been scheduled
                        // by a distant descendant, so use the mAllowLongPress flag to block
                        // everything
                        final View currentScreen = getChildAt(mCurrentScreen);
                        currentScreen.cancelLongPress();
                    }
                }
                break;

            case MotionEvent.ACTION_DOWN:
                // Remember location of down touch
                mLastMotionX = x;
                mLastMotionY = y;
                mAllowLongPress = true;

                /*
                 * If being flinged and user touches the screen, initiate drag;
                 * otherwise don't.  mScroller.isFinished should be false when
                 * being flinged.
                 */
                mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
                break;

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                // Release the drag
                clearChildrenCache();
                mTouchState = TOUCH_STATE_REST;
                mAllowLongPress = false;
                break;
        }

        /*
         * The only time we want to intercept motion events is if we are in the
         * drag mode.
         */
        return mTouchState != TOUCH_STATE_REST;
    
protected voidonLayout(boolean changed, int left, int top, int right, int bottom)

        int childLeft = 0;

        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != View.GONE) {
                final int childWidth = child.getMeasuredWidth();
                child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
                childLeft += childWidth;
            }
        }
    
protected voidonMeasure(int widthMeasureSpec, int heightMeasureSpec)

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        final int width = MeasureSpec.getSize(widthMeasureSpec);
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");
        }

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");
        }

        // The children are given the same width and height as the workspace
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
        }

        if (mWallpaperLoaded) {
            mWallpaperLoaded = false;
            mWallpaper = Utilities.centerToFit(mWallpaper, width,
                    MeasureSpec.getSize(heightMeasureSpec), getContext());
            mWallpaperWidth = mWallpaper.getWidth();
            mWallpaperHeight = mWallpaper.getHeight();
        }

        final int wallpaperWidth = mWallpaperWidth;
        mWallpaperOffset = wallpaperWidth > width ? (count * width - wallpaperWidth) /
                ((count - 1) * (float) width) : 1.0f;

        if (mFirstLayout) {
            scrollTo(mCurrentScreen * width, 0);
            mFirstLayout = false;
        }
    
protected booleanonRequestFocusInDescendants(int direction, android.graphics.Rect previouslyFocusedRect)

        if (mLauncher.isDrawerDown()) {
            final Folder openFolder = getOpenFolder();
            if (openFolder != null) {
                return openFolder.requestFocus(direction, previouslyFocusedRect);
            } else {
                int focusableScreen;
                if (mNextScreen != INVALID_SCREEN) {
                    focusableScreen = mNextScreen;
                } else {
                    focusableScreen = mCurrentScreen;
                }
                getChildAt(focusableScreen).requestFocus(direction, previouslyFocusedRect);
            }
        }
        return false;
    
protected voidonRestoreInstanceState(android.os.Parcelable state)

        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        if (savedState.currentScreen != -1) {
            mCurrentScreen = savedState.currentScreen;
            Launcher.setScreen(mCurrentScreen);
        }
    
protected android.os.ParcelableonSaveInstanceState()

        final SavedState state = new SavedState(super.onSaveInstanceState());
        state.currentScreen = mCurrentScreen;
        return state;
    
public booleanonTouchEvent(android.view.MotionEvent ev)

        if (mLocked || !mLauncher.isDrawerDown()) {
            return true;
        }

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(ev);

        final int action = ev.getAction();
        final float x = ev.getX();

        switch (action) {
        case MotionEvent.ACTION_DOWN:
            /*
             * If being flinged and user touches, stop the fling. isFinished
             * will be false if being flinged.
             */
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }

            // Remember where the motion event started
            mLastMotionX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            if (mTouchState == TOUCH_STATE_SCROLLING) {
                // Scroll to follow the motion event
                final int deltaX = (int) (mLastMotionX - x);
                mLastMotionX = x;

                if (deltaX < 0) {
                    if (mScrollX > 0) {
                        scrollBy(Math.max(-mScrollX, deltaX), 0);
                    }
                } else if (deltaX > 0) {
                    final int availableToScroll = getChildAt(getChildCount() - 1).getRight() -
                            mScrollX - getWidth();
                    if (availableToScroll > 0) {
                        scrollBy(Math.min(availableToScroll, deltaX), 0);
                    }
                }
            }
            break;
        case MotionEvent.ACTION_UP:
            if (mTouchState == TOUCH_STATE_SCROLLING) {
                final VelocityTracker velocityTracker = mVelocityTracker;
                velocityTracker.computeCurrentVelocity(1000);
                int velocityX = (int) velocityTracker.getXVelocity();

                if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
                    // Fling hard enough to move left
                    snapToScreen(mCurrentScreen - 1);
                } else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) {
                    // Fling hard enough to move right
                    snapToScreen(mCurrentScreen + 1);
                } else {
                    snapToDestination();
                }

                if (mVelocityTracker != null) {
                    mVelocityTracker.recycle();
                    mVelocityTracker = null;
                }
            }
            mTouchState = TOUCH_STATE_REST;
            break;
        case MotionEvent.ACTION_CANCEL:
            mTouchState = TOUCH_STATE_REST;
        }

        return true;
    
voidremoveShortcutsForPackage(java.lang.String packageName)

        final ArrayList<View> childrenToRemove = new ArrayList<View>();
        final LauncherModel model = Launcher.getModel();
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final CellLayout layout = (CellLayout) getChildAt(i);
            int childCount = layout.getChildCount();
            childrenToRemove.clear();
            for (int j = 0; j < childCount; j++) {
                final View view = layout.getChildAt(j);
                Object tag = view.getTag();
                if (tag instanceof ApplicationInfo) {
                    ApplicationInfo info = (ApplicationInfo) tag;
                    // We need to check for ACTION_MAIN otherwise getComponent() might
                    // return null for some shortcuts (for instance, for shortcuts to
                    // web pages.)
                    final Intent intent = info.intent;
                    final ComponentName name = intent.getComponent();
                    if (Intent.ACTION_MAIN.equals(intent.getAction()) &&
                            name != null && packageName.equals(name.getPackageName())) {
                        model.removeDesktopItem(info);
                        LauncherModel.deleteItemFromDatabase(mLauncher, info);
                        childrenToRemove.add(view);
                    }
                }
            }
            childCount = childrenToRemove.size();
            for (int j = 0; j < childCount; j++) {
                layout.removeViewInLayout(childrenToRemove.get(j));
            }
            if (childCount > 0) {
                layout.requestLayout();
                layout.invalidate();
            }
        }
    
public booleanrequestChildRectangleOnScreen(android.view.View child, android.graphics.Rect rectangle, boolean immediate)

        int screen = indexOfChild(child);
        if (screen != mCurrentScreen || !mScroller.isFinished()) {
            if (!mLauncher.isWorkspaceLocked()) {
                snapToScreen(screen);
            }
            return true;
        }
        return false;
    
public voidscrollLeft()

        if (mNextScreen == INVALID_SCREEN && mCurrentScreen > 0 && mScroller.isFinished()) {
            snapToScreen(mCurrentScreen - 1);
        }
    
public voidscrollRight()

        if (mNextScreen == INVALID_SCREEN && mCurrentScreen < getChildCount() -1 &&
                mScroller.isFinished()) {
            snapToScreen(mCurrentScreen + 1);
        }
    
public voidsetAllowLongPress(boolean allowLongPress)
Set true to allow long-press events to be triggered, usually checked by {@link Launcher} to accept or block dpad-initiated long-presses.

        mAllowLongPress = allowLongPress;
    
voidsetCurrentScreen(int currentScreen)
Sets the current screen.

param
currentScreen

        mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));
        scrollTo(mCurrentScreen * getWidth(), 0);
        invalidate();
    
public voidsetDragger(DragController dragger)

        mDragger = dragger;
    
voidsetLauncher(Launcher launcher)

        mLauncher = launcher;
    
public voidsetOnLongClickListener(OnLongClickListener l)
Registers the specified listener on each screen contained in this workspace.

param
l The listener used to respond to long clicks.

        mLongClickListener = l;
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).setOnLongClickListener(l);
        }
    
voidshowDefaultScreen()
Shows the default screen (defined by the firstScreen attribute in XML.)

        setCurrentScreen(mDefaultScreen);
    
private voidsnapToDestination()

        final int screenWidth = getWidth();
        final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;

        snapToScreen(whichScreen);
    
voidsnapToScreen(int whichScreen)

        enableChildrenCache();

        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
        boolean changingScreens = whichScreen != mCurrentScreen;
        
        mNextScreen = whichScreen;
        
        View focusedChild = getFocusedChild();
        if (focusedChild != null && changingScreens && focusedChild == getChildAt(mCurrentScreen)) {
            focusedChild.clearFocus();
        }
        
        final int newX = whichScreen * getWidth();
        final int delta = newX - mScrollX;
        mScroller.startScroll(mScrollX, 0, delta, 0, Math.abs(delta) * 2);
        invalidate();
    
public booleansnapToSearch()
Snap to the nearest screen with a search widget and give it focus

return
True if a search widget was found

        // The screen we are searching
        int current = mCurrentScreen;
        
        // first position scanned so far
        int first = current;

        // last position scanned so far
        int last = current;

        // True if we should move down on the next iteration
        boolean next = false;

        // True when we have looked at the first item in the data
        boolean hitFirst;

        // True when we have looked at the last item in the data
        boolean hitLast;
        
        final int count = getChildCount();

        while (true) {
            if (focusOnSearch(current)) {
                return true;
            }

            hitLast = last == count - 1;
            hitFirst = first == 0;

            if (hitLast && hitFirst) {
                // Looked at everything
                break;
            }

            if (hitFirst || (next && !hitLast)) {
                // Either we hit the top, or we are trying to move down
                last++;
                current = last;
                // Try going up next time
                next = false;
            } else {
                // Either we hit the bottom, or we are trying to move up
                first--;
                current = first;
                // Try going down next time
                next = true;
            }

        }
        return false;
    
voidstartDrag(CellLayout.CellInfo cellInfo)

        View child = cellInfo.cell;
        
        // Make sure the drag was started by a long press as opposed to a long click.
        // Note that Search takes focus when clicked rather than entering touch mode
        if (!child.isInTouchMode() && !(child instanceof Search)) {
            return;
        }
        
        mDragInfo = cellInfo;
        mDragInfo.screen = mCurrentScreen;
        
        CellLayout current = ((CellLayout) getChildAt(mCurrentScreen));

        current.onDragChild(child);
        mDragger.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE);
        invalidate();
    
public voidunlock()
Unlocks the SlidingDrawer so that touch events are processed.

see
#lock()

        mLocked = false;
    
voidupdateShortcutsForPackage(java.lang.String packageName)

        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final CellLayout layout = (CellLayout) getChildAt(i);
            int childCount = layout.getChildCount();
            for (int j = 0; j < childCount; j++) {
                final View view = layout.getChildAt(j);
                Object tag = view.getTag();
                if (tag instanceof ApplicationInfo) {
                    ApplicationInfo info = (ApplicationInfo) tag;
                    // We need to check for ACTION_MAIN otherwise getComponent() might
                    // return null for some shortcuts (for instance, for shortcuts to
                    // web pages.)
                    final Intent intent = info.intent;
                    final ComponentName name = intent.getComponent();
                    if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
                            Intent.ACTION_MAIN.equals(intent.getAction()) && name != null &&
                            packageName.equals(name.getPackageName())) {

                        final Drawable icon = Launcher.getModel().getApplicationInfoIcon(
                                mLauncher.getPackageManager(), info);
                        if (icon != null && icon != info.icon) {
                            info.icon.setCallback(null);
                            info.icon = Utilities.createIconThumbnail(icon, mContext);
                            info.filtered = true;
                            ((TextView) view).setCompoundDrawablesWithIntrinsicBounds(null,
                                    info.icon, null, null);
                        }
                    }
                }
            }
        }