Launcher 圆桌面的3D转屏效果实现(2)- Camera rotate

Launcher 桌面的3D转屏效果实现(2)- Camera rotate

上篇主要是通过人工方式给出所要变形的matrix,而这篇则借助于camera进行变换得到matrix直接应用到cellLayout中去,不多说了直接代码带解释

    转载请注明http://ishelf.iteye.com/admin/blogs/836955

 

    @Override


    public void dispatchDraw(Canvas canvas) {
        long start_time = System.currentTimeMillis();
        startRotate(canvas, currentX, canvas.getWidth(), canvas.getHeight());
        super.dispatchDraw(canvas);
        canvas.restore();
        long end_time = System.currentTimeMillis();
        Log.d("CellLayout" + currentScrenn, (end_time - start_time) + " ms");
    }





    public void startRotate(Canvas mCanvas, float xCor, int width, int height) {
        boolean flag = true;
        if (isCurrentScrenn && xCor < 0) {
            xCor = width + xCor;
            flag = false;
        } else if (isCurrentScrenn && xCor >= 0) {
            // xCor = width - xCor;
        } else if (!isCurrentScrenn && xCor < 0) {
            xCor = width + xCor;
        } else if (!isCurrentScrenn && xCor >= 0) {
            flag = false;
        }
        if (xCor <= 0) {
            xCor = 10;
        }// the maximum left
        if (xCor > width) {
            xCor = width - 10;
        }// the maximum right
        float angle = 0;
        if (isBorder) {
            doDraw(mCanvas, width, height, angle, xCor);
        } else if (!flag) {
            angle = 90.0f - (xCor / (float) width) * 90.0f;
            doDraw(mCanvas, width, height, angle, xCor);
        } else {
            angle = -(xCor / (float) width) * 90.00f;
            doDraw(mCanvas, width, height, angle, xCor);
        }
    }

    private void doDraw(Canvas canvas, float width, float height, float angle, float cor) {
        canvas.save();
        mCamera.save();
        mCamera.rotateY(angle);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        // Log.w("CellLayout" + currentScrenn, angle + " __  " + mMatrix);
        if (angle < 0) {
            mMatrix.preTranslate(-width, -height * 0.5f);
            mMatrix.postTranslate(width, height * 0.5f);
        } else {
            mMatrix.preTranslate(0f, -height * 0.5f);
            mMatrix.postTranslate(0f, height * 0.5f);
        }
       canvas.concat(mMatrix);
        switch (currentScrenn) {
            case 0:
                mPaint.setColor(Color.RED);
                break;
            case 1:
                mPaint.setColor(Color.BLUE);
                break;
            case 2:
                mPaint.setColor(Color.YELLOW);
                break;
            case 3:
                mPaint.setColor(Color.CYAN);
                break;
            case 4:
                mPaint.setColor(Color.GREEN);
                break;
        }

       mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawRect(0, 0, width, height, mPaint);
    }


 

 

    workspace的变化如上篇一样,这里就是引进了一个camera通过它进行变换绕Y轴的旋转变换并得到其matrix就可以了。camera使用了opengl的变化操作,所要控制效果要比人为控制matrix好些,但总体显示效果差不多。

     从效率上将,如果机器支持3D加速,其速度要比2D快,不过差别也不是很大,本文做了以下一个比较

 

log-0-2D.txt  18.291666
log-0-3D.txt  7.9088144
log-1-2D.txt  22.92562
log-1-3D.txt  22.818924
log-2-2D.txt  29.503529
log-2-3D.txt  27.178694

 

     每一行的数值表示canvas画图的时间,单位为毫秒,测试数据的平均执行次数在1000次左右,文件名中的0表示第1屏,2表示第二屏。从上面的数据可以看出,基本上相差不大,人工基本上感觉不出来。之所以第一屏差距有些大可能是因为第一屏有左边界。补充下测试的机器是真机, 大家以后来去数码市场悄悄 O(∩_∩)O哈哈~

      以上只是demo,供以学习和讨论。欢迎大家给以指正

 

 

1 楼 gqdy365 2010-12-10  
不错,谢谢分享!
2 楼 wensefu 2011-04-07  
lz 可否发份完整代码压缩包给我研究研究 wensefu@foxmail.com 谢谢。你发的代码中一些变量的声明以及值的变化的地方 还有sepa方法木有。
3 楼 ishelf 2011-04-19  
wensefu 写道
lz 可否发份完整代码压缩包给我研究研究 wensefu@foxmail.com 谢谢。你发的代码中一些变量的声明以及值的变化的地方 还有sepa方法木有。

源码包是没有了,呵呵, 基本重点的都写出来了, 交流用了.....
4 楼 yangzhihui_1171 2011-07-04  
lz,能实现屏和屏的下方3个图标一起翻吗?就是其中一个屏和下方3个图标一起翻,或者是所有屏和下方3个图标一起翻。
5 楼 ishelf 2011-07-04  
yangzhihui_1171 写道
lz,能实现屏和屏的下方3个图标一起翻吗?就是其中一个屏和下方3个图标一起翻,或者是所有屏和下方3个图标一起翻。


这个翻转是针对workspace的,下方的三个图标是在另外一个布局中,需要单独做...
6 楼 yangzhihui_1171 2011-07-14  
lz,这桌面3D效果能只在Workspace.java里改吗?不要在CellLayout.java里改
7 楼 ishelf 2011-07-14  
CellLayout
yangzhihui_1171 写道
lz,这桌面3D效果能只在Workspace.java里改吗?不要在CellLayout.java里改

根据需要吧,其实都是正对canvas的一个变换
8 楼 yangzhihui_1171 2011-07-15  
lz,这是我改的workspace.java,我觉得改得不通用,在8寸机子(1280*768),3D效果不好,你帮我看看该怎么调。。。

public class Workspace extends ViewGroup implements DropTarget, DragSource, DragScroller {
    @SuppressWarnings({"UnusedDeclaration"})
    private static final String TAG = "Launcher.Workspace";
    private static final int INVALID_SCREEN = -1;
   
    /**
     * The velocity at which a fling gesture will cause us to snap to the next screen
     */
    private static final int SNAP_VELOCITY = 600;

    private final WallpaperManager mWallpaperManager;
   
    private int mDefaultScreen;

    private boolean mFirstLayout = true;

    private int mCurrentScreen;
    private int mNextScreen = INVALID_SCREEN;
    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;

    /**
     * CellInfo for the cell that is currently being dragged
     */
    private CellLayout.CellInfo mDragInfo;
   
    /**
     * Target drop area calculated during last acceptDrop call.
     */
    private int[] mTargetCell = null;

    private float mLastMotionX;
    private float mLastMotionY;
   
    private final static int TOUCH_STATE_REST = 0;
    private final static int TOUCH_STATE_SCROLLING = 1;

    private int mTouchState = TOUCH_STATE_REST;

    private OnLongClickListener mLongClickListener;

    private Launcher mLauncher;
    private IconCache mIconCache;
    private DragController mDragController;
   
   
//add by yzh for HTCpreview
    private static final int SENSE_OPENING = 1;
    private static final int SENSE_CLOSING = 2;
    private static final int SENSE_OPEN = 3;
    private static final int SENSE_CLOSED = 4;
    // sense zoom variables
    private boolean mSensemode = false;
    private boolean isAnimating = false;
    private long startTime;
    private int mStatus = SENSE_CLOSED;
    private final int mAnimationDuration = 400;
    private final int[][] distro = { {1}, {2}, {1, 2}, {2, 2},
    {2, 1, 2}, {2, 2, 2}, {2, 3, 2}, {3, 2, 3}, {3, 3, 3} };
    private float previewScale = 1;

    private Paint mPaint;
//end by yzh for HTCpreview
   
   
   
   
   
   
    /**
     * Cache of vacant cells, used during drag events and invalidated as needed.
     */
    private CellLayout.CellInfo mVacantCache = null;
   
    private int[] mTempCell = new int[2];
    private int[] mTempEstimate = new int[2];

    private boolean mAllowLongPress = true;

    private int mTouchSlop;
    private int mMaximumVelocity;
   
    private static final int INVALID_POINTER = -1;
   
   
  //------------------------add by yzh for 3D
public static Bitmap[] s = new Bitmap[5];
//这两个位图,转成3D效果
private int b1 = 0;
private int b2 = 0;

//定义图片的大小
//private float width = 320.0f;
//private float height = 438.0f;
    private Matrix mMatrix = new Matrix();

    //当前手在屏幕上的X坐标值,通过它判断2张图片要如何绘制
private float currentX=0.0f;

//判断拖动屏幕时的拖动方向,大于0为向右拖,小于0为向左拖
float mdirection=0.0f;
boolean flag = true;
//当你从左向右拖动,或从右向左拖动,需要一个标识
boolean flag1 = true;
boolean flag2 = true;
Drawable wallpaperDrawable = null;
Canvas mCanvas = new Canvas();

    private boolean isCurrentScreen;
    private boolean isBorder;
    private Camera mCamera = new Camera();
    private int currentScreen;
//------------------------end by yzh for 3D

    private int mActivePointerId = INVALID_POINTER;
   
    private Drawable mPreviousIndicator;
    private Drawable mNextIndicator;
   
    private static final float NANOTIME_DIV = 1000000000.0f;
    private static final float SMOOTHING_SPEED = 0.75f;
    private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
    private float mSmoothingTime;
    private float mTouchX;

    private WorkspaceOvershootInterpolator mScrollInterpolator;

    private static final float BASELINE_FLING_VELOCITY = 2500.f;
    private static final float FLING_VELOCITY_INFLUENCE = 0.4f;
   
    private static class WorkspaceOvershootInterpolator implements Interpolator {
        private static final float DEFAULT_TENSION = 1.3f;
        private float mTension;

        public WorkspaceOvershootInterpolator() {
            mTension = DEFAULT_TENSION;
        }
       
        public void setDistance(int distance) {
            mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;
        }

        public void disableSettle() {
            mTension = 0.f;
        }

        public float getInterpolation(float t) {
            // _o(t) = t * t * ((tension + 1) * t + tension)
            // o(t) = _o(t - 1) + 1
            t -= 1.0f;
            return t * t * ((mTension + 1) * t + mTension) + 1.0f;
        }
    }
   
    /**
     * Used to inflate the Workspace from XML.
     *
     * @param context The application's context.
     * @param attrs The attribtues set containing the Workspace's customization values.
     */
    public Workspace(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * 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.
     */
    public Workspace(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

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

        setHapticFeedbackEnabled(false);
        initWorkspace();
    }

    /**
     * Initializes various states for this workspace.
     */
    private void initWorkspace() {
        Context context = getContext();
        mScrollInterpolator = new WorkspaceOvershootInterpolator();
        mScroller = new Scroller(context, mScrollInterpolator);
        mCurrentScreen = mDefaultScreen;
        Launcher.setScreen(mCurrentScreen);
        LauncherApplication app = (LauncherApplication)context.getApplicationContext();
        mIconCache = app.getIconCache();
       
        //add by yzh for HTCpreview
        mPaint = new Paint();
    mPaint.setDither(false);
    //end by yzh for HTCpreview

        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
        mTouchSlop = configuration.getScaledTouchSlop();
        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
    }

    @Override
    public void addView(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);
    }

    @Override
    public void addView(View child) {
        if (!(child instanceof CellLayout)) {
            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
        }
        super.addView(child);
    }

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

    @Override
    public void addView(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);
    }

    @Override
    public void addView(View child, LayoutParams params) {
        if (!(child instanceof CellLayout)) {
            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
        }
        super.addView(child, params);
    }

    /**
     * @return The open folder on the current screen, or null if there is none
     */
    Folder getOpenFolder() {
        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;
    }

    ArrayList<Folder> getOpenFolders() {
        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;
    }

    boolean isDefaultScreenShowing() {
        return mCurrentScreen == mDefaultScreen;
    }

    /**
     * Returns the index of the currently displayed screen.
     *
     * @return The index of the currently displayed screen.
     */
    int getCurrentScreen() {
        return mCurrentScreen;
    }

    /**
     * Sets the current screen.
     *
     * @param currentScreen
     */
    void setCurrentScreen(int currentScreen) {
    Log.d(TAG,"setCurrentScreen------");
        if (!mScroller.isFinished()) mScroller.abortAnimation();
        clearVacantCache();
        mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));
        mPreviousIndicator.setLevel(mCurrentScreen);
        mNextIndicator.setLevel(mCurrentScreen);
        scrollTo(mCurrentScreen * getWidth(), 0);
        updateWallpaperOffset();
        invalidate();
    }

    /**
     * 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.
     */
    void addInCurrentScreen(View child, int x, int y, int spanX, int spanY) {
        addInScreen(child, mCurrentScreen, x, y, spanX, spanY, false);
    }

    /**
     * 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.
     */
    void addInCurrentScreen(View child, int x, int y, int spanX, int spanY, boolean insert) {
        addInScreen(child, mCurrentScreen, x, y, spanX, spanY, 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.
     */
    void addInScreen(View child, int screen, int x, int y, int spanX, int spanY) {
        addInScreen(child, screen, x, y, spanX, spanY, false);
    }

    /**
     * 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.
     */
    void addInScreen(View child, int screen, int x, int y, int spanX, int spanY, boolean insert) {
        if (screen < 0 || screen >= getChildCount()) {
            Log.e(TAG, "The screen must be >= 0 and < " + getChildCount()
                + " (was " + screen + "); skipping child");
            return;
        }

        clearVacantCache();

        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.setHapticFeedbackEnabled(false);
            child.setOnLongClickListener(mLongClickListener);
        }
        if (child instanceof DropTarget) {
            mDragController.addDropTarget((DropTarget)child);
        }
    }

    CellLayout.CellInfo findAllVacantCells(boolean[] occupied) {
        CellLayout group = (CellLayout) getChildAt(mCurrentScreen);
        if (group != null) {
            return group.findAllVacantCells(occupied, null);
        }
        return null;
    }

    private void clearVacantCache() {
        if (mVacantCache != null) {
            mVacantCache.clearVacantCells();
            mVacantCache = null;
        }
    }

    /**
     * Registers the specified listener on each screen contained in this workspace.
     *
     * @param l The listener used to respond to long clicks.
     */
    @Override
    public void setOnLongClickListener(OnLongClickListener l) {
        mLongClickListener = l;
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).setOnLongClickListener(l);
        }
    }

    private void updateWallpaperOffset() {
        updateWallpaperOffset(getChildAt(getChildCount() - 1).getRight() - (mRight - mLeft));
    }

    private void updateWallpaperOffset(int scrollRange) {
        IBinder token = getWindowToken();
        if (token != null) {
            mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 0 );
            mWallpaperManager.setWallpaperOffsets(getWindowToken(),
                    Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0);
        }
    }
   
    @Override
    public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
        mTouchX = x;
        mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
    }
   
    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            mTouchX = mScrollX = mScroller.getCurrX();
            mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
            mScrollY = mScroller.getCurrY();
            updateWallpaperOffset();
            postInvalidate();
        } else if (mNextScreen != INVALID_SCREEN) {
            mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));
            mPreviousIndicator.setLevel(mCurrentScreen);
            mNextIndicator.setLevel(mCurrentScreen);
            Launcher.setScreen(mCurrentScreen);
            mNextScreen = INVALID_SCREEN;
            clearChildrenCache();
        } else if (mTouchState == TOUCH_STATE_SCROLLING) {
            final float now = System.nanoTime() / NANOTIME_DIV;
            final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT);
            final float dx = mTouchX - mScrollX;
            mScrollX += dx * e;
            mSmoothingTime = now;

            // Keep generating points as long as we're more than 1px away from the target
            if (dx > 1.f || dx < -1.f) {
                updateWallpaperOffset();
                postInvalidate();
            }
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
    Log.d(TAG,"dispatchDraw");
        boolean restore = false;
        int restoreCount = 0;
mCanvas = canvas;//add by yzh for 3D

        // 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.

        if (!mSensemode) { // add by yzh for HTCpreview
       
        boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN;
       
        //add by yzh for 3D
        final long drawingTime = getDrawingTime();
final int count = getChildCount();

//The following method will make the screen shot for the 5 screens
for (int i = 0; i < count; i++) {
getChildAt(i).buildDrawingCache();
s[i]=getChildAt(i).getDrawingCache();
}
//end by yzh for 3D

        // If we are not scrolling or flinging, draw only the current screen
        if (fastDraw) {
        //add by yzh for 3D
scrollTo(mCurrentScreen * getWidth(), 0);

mCanvas.save();
mCanvas.translate(mScrollX, 0);
        doDraw(mCanvas,s[mCurrentScreen],
new float[] {0,0,mCanvas.getWidth(),0,mCanvas.getWidth(),mCanvas.getHeight(),0,mCanvas.getHeight()},
new float[] {0,0,mCanvas.getWidth(),0,mCanvas.getWidth(),mCanvas.getHeight(),0,mCanvas.getHeight()}
        );
        mCanvas.restore();
        //end by yzh for 3D
       
/*
//new add for test
((CellLayout) getChildAt(mCurrentScreen)).setDockBg(mLauncher.getDockbarCache()); */

           // drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime());
        } else {
            /*final long drawingTime = getDrawingTime();
            final float scrollPos = (float) mScrollX / getWidth();
            final int leftScreen = (int) scrollPos;
            final int rightScreen = leftScreen + 1;
           
          //new add for test
//             ((CellLayout) getChildAt(mCurrentScreen)).setDockBg(mLauncher.getDockbarCache());
           
            if (leftScreen >= 0) {
                drawChild(canvas, getChildAt(leftScreen), drawingTime);
            }
            if (scrollPos != leftScreen && rightScreen < getChildCount()) {
                drawChild(canvas, getChildAt(rightScreen), drawingTime);
            }*/
        if (mNextScreen >= 0 && mNextScreen < getChildCount() &&
                    Math.abs(mCurrentScreen - mNextScreen) == 1) {
                drawChild(mCanvas, getChildAt(mCurrentScreen), drawingTime);
                drawChild(mCanvas, getChildAt(mNextScreen), drawingTime);
        }
        }
        } else { // add by yzh for HTCpreview
        long currentTime;
        if (startTime == 0) {
    startTime = SystemClock.uptimeMillis();
    currentTime = 0;
        } else {
        currentTime = SystemClock.uptimeMillis() - startTime;
        }
        if (currentTime >= mAnimationDuration) {
    isAnimating = false;
    if (mStatus == SENSE_OPENING) {
        mStatus = SENSE_OPEN;
    } else if (mStatus == SENSE_CLOSING) {
        mStatus = SENSE_CLOSED;
        mSensemode = false;
        clearChildrenCache();
        postInvalidate();
    }
        } else {
        postInvalidate();
        }
    final int count = getChildCount();
    for (int i = 0; i < count; i++) {
    drawChildForHTC(canvas, getChildAt(i), getDrawingTime());
    }
    }
    //end yzh add for HTCpreview
       
    /* if (restore) {
        canvas.restoreToCount(restoreCount);
    }*/
       
       
//add by yzh for 3D
if(mTouchState == TOUCH_STATE_SCROLLING){
startRotate(mCanvas,currentX,mCanvas.getWidth(),mCanvas.getHeight());
        }
//end by yzh for 3D
    }
   
   

    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        computeScroll();
        mDragController.setWindowToken(getWindowToken());
    }

    @Override
    protected void onMeasure(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 (mFirstLayout) {
        Log.d(TAG,"onMeasure_mFirstLayout------------");
            setHorizontalScrollBarEnabled(false);
            scrollTo(mCurrentScreen * width, 0);
            setHorizontalScrollBarEnabled(true);
            updateWallpaperOffset(width * (getChildCount() - 1));
            mFirstLayout = false;
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    Log.d(TAG,"onLayout");
        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;
            }
        }
    }

    @Override
    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
        int screen = indexOfChild(child);
        if (screen != mCurrentScreen || !mScroller.isFinished()) {
            snapToScreen(screen);
            return true;
        }
        return false;
    }

    @Override
    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
        if (!mLauncher.isAllAppsVisible()) {
            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;
    }

    @Override
    public boolean dispatchUnhandledMove(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);
    }

    @Override
    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
        if (!mLauncher.isAllAppsVisible()) {
            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);
            }
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            if (mLauncher.isAllAppsVisible()) {
                return false;
            }
        }
        return super.dispatchTouchEvent(ev);
    }
   
//add by yzh for HTCpreview {
    private void findClickedPreview(float x, float y) {
for (int i = 0; i < getChildCount(); i++) {
    RectF tmp = getScaledChild(getChildAt(i));
    if (tmp.contains(x + getScrollX(), y + getScrollY())) {
if (mCurrentScreen != i) {
    mLauncher.dismissPreviews();
    snapToScreen(i);
    postInvalidate();
} else {
    mLauncher.dismissPreviews();
    postInvalidate();
}
    }
}
    }
//end by yzh for HTCpreview

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    // add by yzh for HTCpreview
    if (mStatus == SENSE_OPEN) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        findClickedPreview(ev.getX(), ev.getY());
        }
        return true;
    }
    // add by yzh for HTCpreview
   
        final boolean allAppsVisible = mLauncher.isAllAppsVisible();
        if (allAppsVisible) {
            return false; // We don't want the events.  Let them fall through to the all apps view.
        }

        /*
         * 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;
        }

        acquireVelocityTrackerAndAddMovement(ev);
       
        switch (action & MotionEvent.ACTION_MASK) {
            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 pointerIndex = ev.findPointerIndex(mActivePointerId);
                final float x = ev.getX(pointerIndex);
                final float y = ev.getY(pointerIndex);
                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;
                        mLastMotionX = x;
                        mTouchX = mScrollX;
                        mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
                        enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);
                    }
                    // 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: {
                final float x = ev.getX();
                final float y = ev.getY();
                // Remember location of down touch
                mLastMotionX = x;

                mLastMotionY = y;
                mActivePointerId = ev.getPointerId(0);
                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:
               
                if (mTouchState != TOUCH_STATE_SCROLLING) {
                    final CellLayout currentScreen = (CellLayout)getChildAt(mCurrentScreen);
                    if (!currentScreen.lastDownOnOccupiedCell()) {
                        getLocationOnScreen(mTempCell);
                        // Send a tap to the wallpaper if the last down was on empty space
                        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                        mWallpaperManager.sendWallpaperCommand(getWindowToken(),
                                "android.wallpaper.tap",
                                mTempCell[0] + (int) ev.getX(pointerIndex),
                                mTempCell[1] + (int) ev.getY(pointerIndex), 0, null);
                    }
                }
               
                // Release the drag
                clearChildrenCache();
                mTouchState = TOUCH_STATE_REST;
                mActivePointerId = INVALID_POINTER;
                mAllowLongPress = false;
                releaseVelocityTracker();
                break;
               
            case MotionEvent.ACTION_POINTER_UP:
                onSecondaryPointerUp(ev);
                break;
        }

        /*
         * The only time we want to intercept motion events is if we are in the
         * drag mode.
         */
        return mTouchState != TOUCH_STATE_REST;
    }
   
    private void onSecondaryPointerUp(MotionEvent ev) {
        final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
                MotionEvent.ACTION_POINTER_INDEX_SHIFT;
        final int pointerId = ev.getPointerId(pointerIndex);
        if (pointerId == mActivePointerId) {
            // This was our active pointer going up. Choose a new
            // active pointer and adjust accordingly.
            // TODO: Make this decision more intelligent.
            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
            mLastMotionX = ev.getX(newPointerIndex);
            mLastMotionY = ev.getY(newPointerIndex);
            mActivePointerId = ev.getPointerId(newPointerIndex);
            if (mVelocityTracker != null) {
                mVelocityTracker.clear();
            }
        }
    }

    /**
     * If one of our descendant views decides that it could be focused now, only
     * pass that along if it's on the current screen.
     *
     * This happens when live folders requery, and if they're off screen, they
     * end up calling requestFocus, which pulls it on screen.
     */
    @Override
    public void focusableViewAvailable(View focused) {
        View current = getChildAt(mCurrentScreen);
        View v = focused;
        while (true) {
            if (v == current) {
                super.focusableViewAvailable(focused);
                return;
            }
            if (v == this) {
                return;
            }
            ViewParent parent = v.getParent();
            if (parent instanceof View) {
                v = (View)v.getParent();
            } else {
                return;
            }
        }
    }

    void enableChildrenCache(int fromScreen, int toScreen) {
        if (fromScreen > toScreen) {
            final int temp = fromScreen;
            fromScreen = toScreen;
            toScreen = temp;
        }
       
        final int count = getChildCount();

        fromScreen = Math.max(fromScreen, 0);
        toScreen = Math.min(toScreen, count - 1);

        for (int i = fromScreen; i <= toScreen; i++) {
            final CellLayout layout = (CellLayout) getChildAt(i);
            layout.setChildrenDrawnWithCacheEnabled(true);
            layout.setChildrenDrawingCacheEnabled(true);
        }
    }

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

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        Log.d(TAG,"onTouchEvent");
        if (mLauncher.isAllAppsVisible() || mSensemode) {
            // Cancel any scrolling that is in progress.
           /* if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }
            snapToScreen(mCurrentScreen);*/
            //return false; // We don't want the events.  Let them fall through to the all apps view.
        return true;
        }

        acquireVelocityTrackerAndAddMovement(ev);

        final int action = ev.getAction();

        switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
        Log.d(TAG,"--onTouchEvent_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 = ev.getX();
           
            mActivePointerId = ev.getPointerId(0);
            if (mTouchState == TOUCH_STATE_SCROLLING) {
                enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);
            }
            break;
        case MotionEvent.ACTION_MOVE:
            if (mTouchState == TOUCH_STATE_SCROLLING) {

            Log.d(TAG,"--onTouchEvent_ACTION_MOVE--");
                // Scroll to follow the motion event
                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                final float x = ev.getX(pointerIndex);
                final float deltaX = mLastMotionX - x;
                mLastMotionX = x;

                if (deltaX < 0) {
                   /* if (mTouchX > 0) {
                        mTouchX += Math.max(-mTouchX, deltaX);
                        mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
                        invalidate();
                    }*/
               //add by yzh for 3D
if (mScrollX > 0) {
                    mdirection = 1;// move to right
                    }
//end by yzh for 3D
                } else if (deltaX > 0) {
                mdirection = -1;// move to left // add by yzh for 3D
               
                    final float availableToScroll = getChildAt(getChildCount() - 1).getRight() -
                            mTouchX - getWidth();
                    if (availableToScroll > 0) {
                      /*  mTouchX += Math.min(availableToScroll, deltaX);
                        mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
                        invalidate()*/;
                    }
                }
                /*else {
                    awakenScrollBars();
                }*/
                //add by yzh for 3D
                currentX=x;
        calculateRotate();
        //end by yzh for 3D
            }
            break;
        case MotionEvent.ACTION_UP:
            if (mTouchState == TOUCH_STATE_SCROLLING) {
            Log.d(TAG,"--onTouchEvent_ACTION_UP--");
           
            makeTargetScreen();// add by yzh for 3D
           
                final VelocityTracker velocityTracker = mVelocityTracker;
                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                final int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);
               
                final int screenWidth = getWidth();
                final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;
                final float scrolledPos = (float) mScrollX / screenWidth;
               
                if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
                    // Fling hard enough to move left.
                    // Don't fling across more than one screen at a time.
                  //  final int bound = scrolledPos < whichScreen ?
                   //         mCurrentScreen - 1 : mCurrentScreen;
                  //  snapToScreen(Math.min(whichScreen, bound), velocityX, true);
                } else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) {
                    // Fling hard enough to move right
                    // Don't fling across more than one screen at a time.
                  //  final int bound = scrolledPos > whichScreen ?
                  //          mCurrentScreen + 1 : mCurrentScreen;
                  //  snapToScreen(Math.max(whichScreen, bound), velocityX, true);
                } else {
                   // snapToScreen(whichScreen, 0, true);
                }
            }
            mTouchState = TOUCH_STATE_REST;
            mActivePointerId = INVALID_POINTER;
            releaseVelocityTracker();
            break;
        case MotionEvent.ACTION_CANCEL:
            if (mTouchState == TOUCH_STATE_SCROLLING) {
                final int screenWidth = getWidth();
                final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;
                snapToScreen(whichScreen, 0, true);
            }
            mTouchState = TOUCH_STATE_REST;
            mActivePointerId = INVALID_POINTER;
            releaseVelocityTracker();
            break;
        case MotionEvent.ACTION_POINTER_UP:
            onSecondaryPointerUp(ev);
            break;
        }

        return true;
    }
   
    private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(ev);
    }

    private void releaseVelocityTracker() {
        if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    void snapToScreen(int whichScreen) {
        snapToScreen(whichScreen, 0, false);
    }

    private void snapToScreen(int whichScreen, int velocity, boolean settle) {
    Log.d(TAG, "snapToScreen--");
        //if (!mScroller.isFinished()) return;

        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
       
        clearVacantCache();
        enableChildrenCache(mCurrentScreen, whichScreen);

        mNextScreen = whichScreen;

        mPreviousIndicator.setLevel(mNextScreen);
        mNextIndicator.setLevel(mNextScreen);

        View focusedChild = getFocusedChild();
        if (focusedChild != null && whichScreen != mCurrentScreen &&
                focusedChild == getChildAt(mCurrentScreen)) {
            focusedChild.clearFocus();
        }
       
        final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen));
        final int newX = whichScreen * getWidth();
        final int delta = newX - mScrollX;
        int duration = (screenDelta + 1) * 100;

        if (!mScroller.isFinished()) {
            mScroller.abortAnimation();
        }
       
        if (settle) {
            mScrollInterpolator.setDistance(screenDelta);
        } else {
            mScrollInterpolator.disableSettle();
        }
       
        velocity = Math.abs(velocity);
        if (velocity > 0) {
            duration += (duration / (velocity / BASELINE_FLING_VELOCITY))
                    * FLING_VELOCITY_INFLUENCE;
        } else {
            duration += 100;
        }

        awakenScrollBars(duration);
        mScroller.startScroll(mScrollX, 0, delta, 0, duration);
        invalidate();
    }

    void startDrag(CellLayout.CellInfo cellInfo) {
    Log.d(TAG,"000000000000000000000");
        View child = cellInfo.cell;
       
        // Make sure the drag was started by a long press as opposed to a long click.
        if (!child.isInTouchMode()) {
            return;
        }
       
        mDragInfo = cellInfo;
        mDragInfo.screen = mCurrentScreen;
       
        CellLayout current = ((CellLayout) getChildAt(mCurrentScreen));

        current.onDragChild(child);
        mDragController.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE);
        invalidate();
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        final SavedState state = new SavedState(super.onSaveInstanceState());
        state.currentScreen = mCurrentScreen;
        return state;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        if (savedState.currentScreen != -1) {
            mCurrentScreen = savedState.currentScreen;
            Launcher.setScreen(mCurrentScreen);
        }
    }

    void addApplicationShortcut(ShortcutInfo info, CellLayout.CellInfo cellInfo) {
        addApplicationShortcut(info, cellInfo, false);
    }

    void addApplicationShortcut(ShortcutInfo 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);
    }
   
//add by yzh for HTCpreview
    public void openSense(boolean open) {
//mScroller.abortAnimation();
int maxItemsPerRow = 0;
int distro_set = getChildCount() - 1;
int numRows = distro[distro_set].length;
for (int rows = 0; rows < distro[distro_set].length; rows++) {
    if (distro[distro_set][rows] > maxItemsPerRow) {
    maxItemsPerRow = distro[distro_set][rows];
    }
}
int maxPreviewHeight = (getMeasuredHeight() / numRows);
float w = getMeasuredWidth() / maxItemsPerRow;
int maxPreviewWidth = (int) w;
float scaleW = ((float) maxPreviewWidth / (float) getWidth());
float scaleH = ((float) maxPreviewHeight / (float) getHeight());
previewScale = (scaleW > scaleH) ? scaleH : scaleW;
if (previewScale >= 1)
    previewScale = .8f;

if (open) {
    mSensemode = true;
    isAnimating = true;
    mStatus = SENSE_OPENING;
    startTime = 0;
} else {
    mSensemode = true;
    isAnimating = true;
    mStatus = SENSE_CLOSING;
    startTime = 0;
}
    }

  //  @Override
    protected boolean drawChildForHTC(Canvas canvas, View child, long drawingTime) {
    int saveCount = canvas.save();
if (mSensemode) {
    if (isAnimating || mStatus == SENSE_OPEN) {
long currentTime = SystemClock.uptimeMillis() - startTime;
Rect r1 = new Rect(0, 0, child.getWidth(), child.getHeight());
RectF r2 = getScaledChild(child);
float x = 0;
float y = 0;
float width = 0;
float height = 0;
float alpha = 255;
if (mStatus == SENSE_OPENING) {
    alpha = easeOut(currentTime, 0, 100, mAnimationDuration);
    x = easeOut(currentTime, child.getLeft(), r2.left,
    mAnimationDuration);
    y = easeOut(currentTime, child.getTop(), r2.top,
    mAnimationDuration);
    width = easeOut(currentTime, child.getRight(), r2.right,
    mAnimationDuration);
    height = easeOut(currentTime, child.getBottom(), r2.bottom,
    mAnimationDuration);
} else if (mStatus == SENSE_CLOSING) {
    alpha = easeOut(currentTime, 100, 0, mAnimationDuration);
    x = easeOut(currentTime, r2.left, child.getLeft(),
    mAnimationDuration);
    y = easeOut(currentTime, r2.top, child.getTop(),
    mAnimationDuration);
    width = easeOut(currentTime, r2.right, child.getRight(),
    mAnimationDuration);
    height = easeOut(currentTime, r2.bottom, child.getBottom(),
    mAnimationDuration);
} else if (mStatus == SENSE_OPEN) {
    x = r2.left;
    y = r2.top;
    width = r2.right;
    height = r2.bottom;
    alpha = 100;
}
float scale = ((width - x) / r1.width());
canvas.save();
canvas.translate(x, y);
canvas.scale(scale, scale);
mPaint.setAlpha((int) alpha);
canvas.drawRoundRect(new RectF(r1.left + 5, r1.top + 5,
r1.right - 5, r1.bottom - 5), 15f, 15f, mPaint);
mPaint.setAlpha(255);
child.draw(canvas);
canvas.restore();
    } else {
child.draw(canvas);
    }
} else {
    super.drawChild(canvas, child, drawingTime);
}
canvas.restoreToCount(saveCount);
return true;
    }

    static float easeOut(float time, float begin, float end, float duration) {
float change = end - begin;
float value = change * ((time = time / duration - 1) * time * time + 1)
+ begin;
if (change > 0 && value > end)
    value = end;
if (change < 0 && value < end)
    value = end;
return value;
    }

    private RectF getScaledChild(View child) {
final int count = getChildCount();
final int width = getWidth();
final int height = getHeight();
int xpos = getScrollX();
int ypos = 0;

int distro_set = count - 1;
int childPos = 0;

int childWidth = (int) (width * previewScale);
int childHeight = (int) (height * previewScale);

final int topMargin = (height / 2)
- ((childHeight * distro[distro_set].length) / 2);
for (int rows = 0; rows < distro[distro_set].length; rows++) {
    final int leftMargin = (width / 2)
    - ((childWidth * distro[distro_set][rows]) / 2);
    for (int columns = 0; columns < distro[distro_set][rows]; columns++) {
if (childPos > getChildCount() - 1)
    break;
final View c = getChildAt(childPos);
if (child == c) {
    return new RectF(leftMargin + xpos, topMargin + ypos,
    leftMargin + xpos + childWidth, topMargin + ypos
    + childHeight);
} else {
    xpos += childWidth;
}
childPos++;
    }
    xpos = getScrollX();
    ypos += childHeight;
}
return new RectF();
    }
//end by yzh for HTCpreview

    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
            DragView dragView, Object dragInfo) {
        Log.d(TAG,"workspace_onDrop");
        final CellLayout cellLayout = getCurrentDropLayout();
       
        if (source != this) {
            onDropExternal(x - xOffset, y - yOffset, dragInfo, cellLayout);
        } else {
            // Move internally
            if (mDragInfo != null) {
                final View cell = mDragInfo.cell;
                int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen;               
                if (index != mDragInfo.screen) {
                    final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                    originalCellLayout.removeView(cell);
                    cellLayout.addView(cell);
                }
               
                mTargetCell = estimateDropCell(x - xOffset, y - yOffset,
                        mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout, mTargetCell);
                cellLayout.onDropChild(cell, mTargetCell);

                final ItemInfo info = (ItemInfo) cell.getTag();
                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
                LauncherModel.moveItemInDatabase(mLauncher, info,
                        LauncherSettings.Favorites.CONTAINER_DESKTOP, index, lp.cellX, lp.cellY);
            }
        }
    }

    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
            DragView dragView, Object dragInfo) {
        clearVacantCache();
    }

    public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
            DragView dragView, Object dragInfo) {
    }

    public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
            DragView dragView, Object dragInfo) {
        clearVacantCache();
    }

    private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout) {
        onDropExternal(x, y, dragInfo, cellLayout, false);
    }
   
    private void onDropExternal(int x, int y, 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 && info instanceof ApplicationInfo) {
                // Came from all apps -- make a copy
                info = new ShortcutInfo((ApplicationInfo)info);
            }
            view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo)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.setHapticFeedbackEnabled(false);
        view.setOnLongClickListener(mLongClickListener);
        if (view instanceof DropTarget) {
            mDragController.addDropTarget((DropTarget) view);
        }

        mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell);
        cellLayout.onDropChild(view, mTargetCell);
        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();

        LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
                LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
    }
   
    /**
     * Return the current {@link CellLayout}, correctly picking the destination
     * screen while a scroll is in progress.
     */
    private CellLayout getCurrentDropLayout() {
        int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen;
        return (CellLayout) getChildAt(index);
    }

    /**
     * {@inheritDoc}
     */
    public boolean acceptDrop(DragSource source, int x, int y,
            int xOffset, int yOffset, DragView dragView, Object dragInfo) {
        final CellLayout layout = getCurrentDropLayout();
        final CellLayout.CellInfo cellInfo = mDragInfo;
        final int spanX = cellInfo == null ? 1 : cellInfo.spanX;
        final int spanY = cellInfo == null ? 1 : cellInfo.spanY;

        if (mVacantCache == null) {
            final View ignoreView = cellInfo == null ? null : cellInfo.cell;
            mVacantCache = layout.findAllVacantCells(null, ignoreView);
        }

        return mVacantCache.findCellForSpan(mTempEstimate, spanX, spanY, false);
    }
   
    /**
     * {@inheritDoc}
     */
    public Rect estimateDropLocation(DragSource source, int x, int y,
            int xOffset, int yOffset, DragView dragView, Object dragInfo, Rect recycle) {
        final CellLayout layout = getCurrentDropLayout();
       
        final CellLayout.CellInfo cellInfo = mDragInfo;
        final int spanX = cellInfo == null ? 1 : cellInfo.spanX;
        final int spanY = cellInfo == null ? 1 : cellInfo.spanY;
        final View ignoreView = cellInfo == null ? null : cellInfo.cell;
       
        final Rect location = recycle != null ? recycle : new Rect();
       
        // Find drop cell and convert into rectangle
        int[] dropCell = estimateDropCell(x - xOffset, y - yOffset,
                spanX, spanY, ignoreView, layout, mTempCell);
       
        if (dropCell == null) {
            return null;
        }
       
        layout.cellToPoint(dropCell[0], dropCell[1], mTempEstimate);
        location.left = mTempEstimate[0];
        location.top = mTempEstimate[1];
       
        layout.cellToPoint(dropCell[0] + spanX, dropCell[1] + spanY, mTempEstimate);
        location.right = mTempEstimate[0];
        location.bottom = mTempEstimate[1];
       
        return location;
    }

    /**
     * Calculate the nearest cell where the given object would be dropped.
     */
    private int[] estimateDropCell(int pixelX, int pixelY,
            int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) {
        // Create vacant cell cache if none exists
        if (mVacantCache == null) {
            mVacantCache = layout.findAllVacantCells(null, ignoreView);
        }

        // Find the best target drop location
        return layout.findNearestVacantArea(pixelX, pixelY,
                spanX, spanY, mVacantCache, recycle);
    }
   
    void setLauncher(Launcher launcher) {
        mLauncher = launcher;
    }

    public void setDragController(DragController dragController) {
        mDragController = dragController;
    }

    public void onDropCompleted(View target, boolean success) {
        clearVacantCache();

        if (success){
            if (target != this && mDragInfo != null) {
                final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                cellLayout.removeView(mDragInfo.cell);
                if (mDragInfo.cell instanceof DropTarget) {
                    mDragController.removeDropTarget((DropTarget)mDragInfo.cell);
                }
                //final Object tag = mDragInfo.cell.getTag();
            }
        } else {
            if (mDragInfo != null) {
                final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                cellLayout.onDropAborted(mDragInfo.cell);
            }
        }

        mDragInfo = null;
    }

    public void scrollLeft() {
    Log.d(TAG,"scrollLeft");
        clearVacantCache();
        if (mScroller.isFinished()) {
            if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1);
        } else {
            if (mNextScreen > 0) snapToScreen(mNextScreen - 1);           
        }
    }

    public void scrollRight() {
    Log.d(TAG,"scrollRight");
        clearVacantCache();
        if (mScroller.isFinished()) {
            if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1);
        } else {
            if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1);           
        }
    }

    public int getScreenForView(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;
    }

    public Folder getFolderForTag(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;
    }

    public View getViewForTag(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;
    }

    /**
     * @return True is long presses are still allowed for the current touch
     */
    public boolean allowLongPress() {
        return mAllowLongPress;
    }
   
    /**
     * Set true to allow long-press events to be triggered, usually checked by
     * {@link Launcher} to accept or block dpad-initiated long-presses.
     */
    public void setAllowLongPress(boolean allowLongPress) {
        mAllowLongPress = allowLongPress;
    }

    void removeItems(final ArrayList<ApplicationInfo> apps) {
        final int count = getChildCount();
        final PackageManager manager = getContext().getPackageManager();
        final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext());

        final HashSet<String> packageNames = new HashSet<String>();
        final int appCount = apps.size();
        for (int i = 0; i < appCount; i++) {
            packageNames.add(apps.get(i).componentName.getPackageName());
        }

        for (int i = 0; i < count; i++) {
            final CellLayout layout = (CellLayout) getChildAt(i);

            // Avoid ANRs by treating each screen separately
            post(new Runnable() {
                public void run() {
                    final ArrayList<View> childrenToRemove = new ArrayList<View>();
                    childrenToRemove.clear();
       
                    int childCount = layout.getChildCount();
                    for (int j = 0; j < childCount; j++) {
                        final View view = layout.getChildAt(j);
                        Object tag = view.getTag();
       
                        if (tag instanceof ShortcutInfo) {
                            final ShortcutInfo info = (ShortcutInfo) tag;
                            final Intent intent = info.intent;
                            final ComponentName name = intent.getComponent();
       
                            if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
                                for (String packageName: packageNames) {
                                    if (packageName.equals(name.getPackageName())) {
                                        LauncherModel.deleteItemFromDatabase(mLauncher, info);
                                        childrenToRemove.add(view);
                                    }
                                }
                            }
                        } else if (tag instanceof UserFolderInfo) {
                            final UserFolderInfo info = (UserFolderInfo) tag;
                            final ArrayList<ShortcutInfo> contents = info.contents;
                            final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1);
                            final int contentsCount = contents.size();
                            boolean removedFromFolder = false;
       
                            for (int k = 0; k < contentsCount; k++) {
                                final ShortcutInfo appInfo = contents.get(k);
                                final Intent intent = appInfo.intent;
                                final ComponentName name = intent.getComponent();
       
                                if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
                                    for (String packageName: packageNames) {
                                        if (packageName.equals(name.getPackageName())) {
                                            toRemove.add(appInfo);
                                            LauncherModel.deleteItemFromDatabase(mLauncher, appInfo);
                                            removedFromFolder = true;
                                        }
                                    }
                                }
                            }
       
                            contents.removeAll(toRemove);
                            if (removedFromFolder) {
                                final Folder folder = getOpenFolder();
                                if (folder != null) folder.notifyDataSetChanged();
                            }
                        } else if (tag instanceof LiveFolderInfo) {
                            final LiveFolderInfo info = (LiveFolderInfo) tag;
                            final Uri uri = info.uri;
                            final ProviderInfo providerInfo = manager.resolveContentProvider(
                                    uri.getAuthority(), 0);

                            if (providerInfo != null) {
                                for (String packageName: packageNames) {
                                    if (packageName.equals(providerInfo.packageName)) {
                                        LauncherModel.deleteItemFromDatabase(mLauncher, info);
                                        childrenToRemove.add(view);                       
                                    }
                                }
                            }
                        } else if (tag instanceof LauncherAppWidgetInfo) {
                            final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag;
                            final AppWidgetProviderInfo provider =
                                    widgets.getAppWidgetInfo(info.appWidgetId);
                            if (provider != null) {
                                for (String packageName: packageNames) {
                                    if (packageName.equals(provider.provider.getPackageName())) {
                                        LauncherModel.deleteItemFromDatabase(mLauncher, info);
                                        childrenToRemove.add(view);                               
                                    }
                                }
                            }
                        }
                    }
       
                    childCount = childrenToRemove.size();
                    for (int j = 0; j < childCount; j++) {
                        View child = childrenToRemove.get(j);
                        layout.removeViewInLayout(child);
                        if (child instanceof DropTarget) {
                            mDragController.removeDropTarget((DropTarget)child);
                        }
                    }
       
                    if (childCount > 0) {
                        layout.requestLayout();
                        layout.invalidate();
                    }
                }
            });
        }
    }

    void updateShortcuts(ArrayList<ApplicationInfo> apps) {
        final PackageManager pm = mLauncher.getPackageManager();

        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 ShortcutInfo) {
                    ShortcutInfo info = (ShortcutInfo)tag;
                    // We need to check for ACTION_MAIN otherwise getComponent() might
                    // return null for some shortcuts (for instance, for shortcuts to
                    // web pages.)
                
9 楼 yangzhihui_1171 2011-07-15  
我的桌面3D效果,只改了workspace.java一个文件
10 楼 yangzhihui_1171 2011-07-15  
    void moveToDefaultScreen(boolean animate) {
    Log.d(TAG, "moveToDefaultScreen");
        if (animate) {
            snapToScreen(mDefaultScreen);
        } else {
            setCurrentScreen(mDefaultScreen);
        }
        getChildAt(mDefaultScreen).requestFocus();
    }

    void setIndicators(Drawable previous, Drawable next) {
        mPreviousIndicator = previous;
        mNextIndicator = next;
        previous.setLevel(mCurrentScreen);
        next.setLevel(mCurrentScreen);
    }

    public static class SavedState extends BaseSavedState {
        int currentScreen = -1;

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(Parcel in) {
            super(in);
            currentScreen = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(currentScreen);
        }

        public static final Parcelable.Creator<SavedState> CREATOR =
                new Parcelable.Creator<SavedState>() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }
   
    //------------------------------
    public void calculateRotate(){
Log.d(TAG,"calculateRotate");
    if(flag){
    //get the start drag point
    flag=false;
    //when start drag, only set the backgound one time
    wallpaperDrawable = mWallpaperManager.getFastDrawable();
getChildAt(0).setBackgroundDrawable(wallpaperDrawable);
getChildAt(1).setBackgroundDrawable(wallpaperDrawable);
getChildAt(2).setBackgroundDrawable(wallpaperDrawable);
getChildAt(3).setBackgroundDrawable(wallpaperDrawable);
getChildAt(4).setBackgroundDrawable(wallpaperDrawable);

for(int i = 0; i < 5; i++){
    getChildAt(i).buildDrawingCache();
    s[i] = getChildAt(i).getDrawingCache();
    }
    }
        //judge the direction
    if(mdirection>0){//finger move from left to right
if(flag1){
flag2=false;
if(mCurrentScreen==0){
b1=4;
b2=0;
}
if(mCurrentScreen==1){
b1=0;
b2=1;
}
if(mCurrentScreen==2){
b1=1;
b2=2;
}
if(mCurrentScreen==3){
b1=2;
b2=3;
}
if(mCurrentScreen==4){
b1=3;
b2=4;
}
}
}
if(mdirection<0){//finger move from right to left
if(flag2){
flag1=false;
if(mCurrentScreen==0){
b1=0;
b2=1;
}
if(mCurrentScreen==1){
b1=1;
b2=2;
}
if(mCurrentScreen==2){
b1=2;
b2=3;
}
if(mCurrentScreen==3){
b1=3;
b2=4;
}
if(mCurrentScreen==4){
b1=4;
b2=0;
}
}
}
        invalidate();
}
   
    public void startRotate(Canvas mCanvas,float xCor,int width,int height){
Log.d(TAG,"startRotate");

/*boolean flag = true;
    if(isCurrentScreen && xCor < 0){
    xCor = width + xCor;
    flag = false;
    }else if(isCurrentScreen && xCor >= 0){
    //xCor = width - xCor;
    }else if(!isCurrentScreen && xCor < 0){
    xCor = width + xCor;
    }else if(!isCurrentScreen && xCor >= 0){
    flag = false;
    }
    if(xCor <= 0){
    xCor = 10;
    }
    if(xCor > width){
    xCor = width - 10;
    }
    float angle = 0;
    if(isBorder){
    doDraw(mCanvas,width,height,angle,xCor);
    }else if(!flag){
    angle = 90.0f - (xCor / (float)width) * 90.0f;
    doDraw(mCanvas,width,height,angle,xCor);
    }else{
    angle = -(xCor / (float)width) * 90.0f;
    doDraw(mCanvas,width,height,angle,xCor);
    }*/




final float SPAN = 0.000424f;
//begin to draw
float f = xCor - 10;
if(f <= 0) {
f=0;
xCor=10;
}//the maximum left

float value = f * SPAN;
/* if(f > 300) {
// xCor = 310;
xCor = width;
value = 0.127225f;
}//the maximum right
*/

if(f > width){
xCor = f - width;
value = 0.127225f;
}
Log.d(TAG,"width=" + width + ",height=" + height + ",xCor=" + xCor +",f=" + f);


mCanvas.save();
mCanvas.drawColor(Color.BLACK);
mCanvas.translate(mScrollX, 0);
    doDraw(mCanvas,s[b1],
    new float[] {0,0,width,0,width,height,0,height},
    new float[] {0,height*(1/7.0f-value),xCor,0,xCor,height,0,height*(6/7.0f+value)}
    );

    doDraw(mCanvas,s[b2],
    new float[] {0,0,width,0,width,height,0,height},
                new float[] {xCor,0,width,height*(1/64.0f+value),width,height*(63/64.0f-value), xCor,height}
    );
        mCanvas.restore();
}
   
   /* private void doDraw(Canvas canvas,float width,float height,float angle,float xCor){
    canvas.save();
    mCamera.save();
    mCamera.rotateY(angle);
    mCamera.getMatrix(mMatrix);
    mCamera.restore();
   
    //Log.d("CellLayout" + currentScreen, angle + " __  " + mMatrix);
    System.out.println("CellLayout="+currentScreen+ ",angle="+angle+",mMatrix=" + mMatrix);
    if(angle < 0){
    mMatrix.preTranslate(-width, -height * 0.5f);
    mMatrix.postTranslate(width, height * 0.5f);
    }else{
    mMatrix.preTranslate(0f, -height * 0.5f);
    mMatrix.postTranslate(0f, height * 0.5f);
    }
   
    canvas.concat(mMatrix);
    switch (currentScreen) {
    case 0: 
            mPaint.setColor(Color.RED); 
            break; 
        case 1: 
            mPaint.setColor(Color.BLUE); 
            break; 
        case 2: 
        mPaint.setAntiAlias(true);
            mPaint.setColor(Color.YELLOW);
            mPaint.setAlpha(80);
            break; 
        case 3: 
            mPaint.setColor(Color.CYAN); 
            break; 
        case 4: 
            mPaint.setColor(Color.GREEN); 
            break;
}
    mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    canvas.drawRect(0, 0, width, height, mPaint);
    }*/
   
   
   
    public void doDraw(Canvas canvas,Bitmap bp, float src[], float dst[]) {
    mCanvas.save();
        mMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1);
       
        mCanvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
       
        mCanvas.concat(mMatrix);
       
        mCanvas.drawBitmap(bp, 0, 0, null);
        mCanvas.restore();
       
       
}

public void makeTargetScreen(){
Log.d(TAG,"makeTargetScreen");
//use the wall paper as the background, if we
    //don't have these, when we change the wall paper
    //the wall paper won't be changed until we drag the workspace
    getChildAt(0).setBackgroundDrawable(null);
getChildAt(1).setBackgroundDrawable(null);
getChildAt(2).setBackgroundDrawable(null);
getChildAt(3).setBackgroundDrawable(null);
getChildAt(4).setBackgroundDrawable(null);

    if(mdirection > 0 && flag1){//finger move from left to right
    //we can use whether the currentX > or < 160.0f to know how to change the screen
    if(mCurrentScreen >= 1){//if current screen is the second or third screen
    if(currentX > getWidth()/2.0f)
    mCurrentScreen = mCurrentScreen - 1;
    }else if(mCurrentScreen == 0){
    mCurrentScreen = 4;
    }
    }
    if(mdirection < 0 && flag2){//finger move from right to left
    if(mCurrentScreen <= 1){//if current screen is the first or second screen 
    if(currentX < getWidth()/2.0f)
    mCurrentScreen = mCurrentScreen + 1;
    }
    else if(mCurrentScreen == 2){
    mCurrentScreen = 3;
    }
    else if(mCurrentScreen == 3){
    mCurrentScreen = 4;
    }   
    else if(mCurrentScreen == 4){
    mCurrentScreen = 0;
    }
    }
    flag=true;
    flag1=true;
    flag2=true;
}
   
   
   
}
11 楼 烧伤的火柴 2012-02-08  
不错,谢谢分享!