Launcher 桌面的3D转屏效果实现(2)- Camera rotate
上篇主要是通过人工方式给出所要变形的matrix,而这篇则借助于camera进行变换得到matrix直接应用到cellLayout中去,不多说了直接代码带解释
??? 转载请注明http://ishelf.iteye.com/admin/blogs/836955
?
?
?
??? workspace的变化如上篇一样,这里就是引进了一个camera通过它进行变换绕Y轴的旋转变换并得到其matrix就可以了。camera使用了opengl的变化操作,所要控制效果要比人为控制matrix好些,但总体显示效果差不多。
???? 从效率上将,如果机器支持3D加速,其速度要比2D快,不过差别也不是很大,本文做了以下一个比较
?
+ " (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.)
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 不错,谢谢分享!