PagedViewWithDraggableItems.java revision 304dcde0e301c2f1a0b2bdc80ea8617930691b6e
172b079e4031f42729056e999c20bf87281798eb9Michael Jurka/* 272b079e4031f42729056e999c20bf87281798eb9Michael Jurka * Copyright (C) 2010 The Android Open Source Project 372b079e4031f42729056e999c20bf87281798eb9Michael Jurka * 472b079e4031f42729056e999c20bf87281798eb9Michael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 572b079e4031f42729056e999c20bf87281798eb9Michael Jurka * you may not use this file except in compliance with the License. 672b079e4031f42729056e999c20bf87281798eb9Michael Jurka * You may obtain a copy of the License at 772b079e4031f42729056e999c20bf87281798eb9Michael Jurka * 872b079e4031f42729056e999c20bf87281798eb9Michael Jurka * http://www.apache.org/licenses/LICENSE-2.0 972b079e4031f42729056e999c20bf87281798eb9Michael Jurka * 1072b079e4031f42729056e999c20bf87281798eb9Michael Jurka * Unless required by applicable law or agreed to in writing, software 1172b079e4031f42729056e999c20bf87281798eb9Michael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 1272b079e4031f42729056e999c20bf87281798eb9Michael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1372b079e4031f42729056e999c20bf87281798eb9Michael Jurka * See the License for the specific language governing permissions and 1472b079e4031f42729056e999c20bf87281798eb9Michael Jurka * limitations under the License. 1572b079e4031f42729056e999c20bf87281798eb9Michael Jurka */ 1672b079e4031f42729056e999c20bf87281798eb9Michael Jurka 1772b079e4031f42729056e999c20bf87281798eb9Michael Jurkapackage com.android.launcher2; 1872b079e4031f42729056e999c20bf87281798eb9Michael Jurka 1972b079e4031f42729056e999c20bf87281798eb9Michael Jurkaimport android.content.Context; 2072b079e4031f42729056e999c20bf87281798eb9Michael Jurkaimport android.util.AttributeSet; 2172b079e4031f42729056e999c20bf87281798eb9Michael Jurkaimport android.view.MotionEvent; 2272b079e4031f42729056e999c20bf87281798eb9Michael Jurkaimport android.view.View; 2372b079e4031f42729056e999c20bf87281798eb9Michael Jurka 2472b079e4031f42729056e999c20bf87281798eb9Michael Jurka 2572b079e4031f42729056e999c20bf87281798eb9Michael Jurka/* Class that does most of the work of enabling dragging items out of a PagedView by performing a 2672b079e4031f42729056e999c20bf87281798eb9Michael Jurka * vertical drag. Used by both CustomizePagedView and AllAppsPagedView. 2772b079e4031f42729056e999c20bf87281798eb9Michael Jurka * Subclasses must do the following: 2872b079e4031f42729056e999c20bf87281798eb9Michael Jurka * * call setDragSlopeThreshold after making an instance of the PagedViewWithDraggableItems 2972b079e4031f42729056e999c20bf87281798eb9Michael Jurka * * call child.setOnLongClickListener(this) and child.setOnTouchListener(this) on all children 3072b079e4031f42729056e999c20bf87281798eb9Michael Jurka * (good place to do it is in syncPageItems) 3172b079e4031f42729056e999c20bf87281798eb9Michael Jurka * * override beginDragging(View) (but be careful to call super.beginDragging(View) 3272b079e4031f42729056e999c20bf87281798eb9Michael Jurka * 3372b079e4031f42729056e999c20bf87281798eb9Michael Jurka */ 3472b079e4031f42729056e999c20bf87281798eb9Michael Jurkapublic abstract class PagedViewWithDraggableItems extends PagedView 3572b079e4031f42729056e999c20bf87281798eb9Michael Jurka implements View.OnLongClickListener, View.OnTouchListener { 3672b079e4031f42729056e999c20bf87281798eb9Michael Jurka private View mLastTouchedItem; 3772b079e4031f42729056e999c20bf87281798eb9Michael Jurka private boolean mIsDragging; 3872b079e4031f42729056e999c20bf87281798eb9Michael Jurka private float mDragSlopeThreshold; 3972b079e4031f42729056e999c20bf87281798eb9Michael Jurka 4072b079e4031f42729056e999c20bf87281798eb9Michael Jurka public PagedViewWithDraggableItems(Context context) { 4172b079e4031f42729056e999c20bf87281798eb9Michael Jurka super(context, null); 4272b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 4372b079e4031f42729056e999c20bf87281798eb9Michael Jurka 4472b079e4031f42729056e999c20bf87281798eb9Michael Jurka public PagedViewWithDraggableItems(Context context, AttributeSet attrs) { 4572b079e4031f42729056e999c20bf87281798eb9Michael Jurka super(context, attrs, 0); 4672b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 4772b079e4031f42729056e999c20bf87281798eb9Michael Jurka 4872b079e4031f42729056e999c20bf87281798eb9Michael Jurka public PagedViewWithDraggableItems(Context context, AttributeSet attrs, int defStyle) { 4972b079e4031f42729056e999c20bf87281798eb9Michael Jurka super(context, attrs, defStyle); 5072b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 5172b079e4031f42729056e999c20bf87281798eb9Michael Jurka 5272b079e4031f42729056e999c20bf87281798eb9Michael Jurka protected boolean beginDragging(View v) { 53304dcde0e301c2f1a0b2bdc80ea8617930691b6eWinson Chung boolean wasDragging = mIsDragging; 5472b079e4031f42729056e999c20bf87281798eb9Michael Jurka mIsDragging = true; 55304dcde0e301c2f1a0b2bdc80ea8617930691b6eWinson Chung return !wasDragging; 5672b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 5772b079e4031f42729056e999c20bf87281798eb9Michael Jurka 587d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung protected void cancelDragging() { 597d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung mIsDragging = false; 607d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung mLastTouchedItem = null; 617d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung } 627d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung 637d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung private void handleTouchEvent(MotionEvent ev) { 6472b079e4031f42729056e999c20bf87281798eb9Michael Jurka final int action = ev.getAction(); 6572b079e4031f42729056e999c20bf87281798eb9Michael Jurka switch (action & MotionEvent.ACTION_MASK) { 6672b079e4031f42729056e999c20bf87281798eb9Michael Jurka case MotionEvent.ACTION_DOWN: 677d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung cancelDragging(); 6872b079e4031f42729056e999c20bf87281798eb9Michael Jurka break; 6972b079e4031f42729056e999c20bf87281798eb9Michael Jurka case MotionEvent.ACTION_MOVE: 7072b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging) { 7172b079e4031f42729056e999c20bf87281798eb9Michael Jurka determineDraggingStart(ev); 7272b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 7372b079e4031f42729056e999c20bf87281798eb9Michael Jurka break; 7472b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 7572b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 7672b079e4031f42729056e999c20bf87281798eb9Michael Jurka 7772b079e4031f42729056e999c20bf87281798eb9Michael Jurka @Override 787d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung public boolean onInterceptTouchEvent(MotionEvent ev) { 797d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung handleTouchEvent(ev); 807d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung return super.onInterceptTouchEvent(ev); 8172b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 8272b079e4031f42729056e999c20bf87281798eb9Michael Jurka 8372b079e4031f42729056e999c20bf87281798eb9Michael Jurka @Override 8472b079e4031f42729056e999c20bf87281798eb9Michael Jurka public boolean onTouchEvent(MotionEvent ev) { 857d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung handleTouchEvent(ev); 8672b079e4031f42729056e999c20bf87281798eb9Michael Jurka return super.onTouchEvent(ev); 8772b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 8872b079e4031f42729056e999c20bf87281798eb9Michael Jurka 8972b079e4031f42729056e999c20bf87281798eb9Michael Jurka @Override 907d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung public boolean onTouch(View v, MotionEvent event) { 917d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung mLastTouchedItem = v; 927d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung return false; 937d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung } 947d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung 957d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung @Override 9672b079e4031f42729056e999c20bf87281798eb9Michael Jurka public boolean onLongClick(View v) { 9772b079e4031f42729056e999c20bf87281798eb9Michael Jurka // Return early if this is not initiated from a touch 9872b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (!v.isInTouchMode()) return false; 9972b079e4031f42729056e999c20bf87281798eb9Michael Jurka // Return early if we are still animating the pages 10072b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (mNextPage != INVALID_PAGE) return false; 10172b079e4031f42729056e999c20bf87281798eb9Michael Jurka return beginDragging(v); 10272b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 10372b079e4031f42729056e999c20bf87281798eb9Michael Jurka 10472b079e4031f42729056e999c20bf87281798eb9Michael Jurka 10572b079e4031f42729056e999c20bf87281798eb9Michael Jurka /* 10672b079e4031f42729056e999c20bf87281798eb9Michael Jurka * Determines if we should change the touch state to start scrolling after the 10772b079e4031f42729056e999c20bf87281798eb9Michael Jurka * user moves their touch point too far. 10872b079e4031f42729056e999c20bf87281798eb9Michael Jurka */ 10972b079e4031f42729056e999c20bf87281798eb9Michael Jurka protected void determineScrollingStart(MotionEvent ev) { 11072b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (!mIsDragging) super.determineScrollingStart(ev); 11172b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 11272b079e4031f42729056e999c20bf87281798eb9Michael Jurka 11372b079e4031f42729056e999c20bf87281798eb9Michael Jurka /* 11472b079e4031f42729056e999c20bf87281798eb9Michael Jurka * Determines if we should change the touch state to start dragging after the 11572b079e4031f42729056e999c20bf87281798eb9Michael Jurka * user moves their touch point far enough. 11672b079e4031f42729056e999c20bf87281798eb9Michael Jurka */ 11772b079e4031f42729056e999c20bf87281798eb9Michael Jurka protected void determineDraggingStart(MotionEvent ev) { 11872b079e4031f42729056e999c20bf87281798eb9Michael Jurka /* 11972b079e4031f42729056e999c20bf87281798eb9Michael Jurka * Locally do absolute value. mLastMotionX is set to the y value 12072b079e4031f42729056e999c20bf87281798eb9Michael Jurka * of the down event. 12172b079e4031f42729056e999c20bf87281798eb9Michael Jurka */ 12272b079e4031f42729056e999c20bf87281798eb9Michael Jurka final int pointerIndex = ev.findPointerIndex(mActivePointerId); 12372b079e4031f42729056e999c20bf87281798eb9Michael Jurka final float x = ev.getX(pointerIndex); 12472b079e4031f42729056e999c20bf87281798eb9Michael Jurka final float y = ev.getY(pointerIndex); 12572b079e4031f42729056e999c20bf87281798eb9Michael Jurka final int xDiff = (int) Math.abs(x - mLastMotionX); 12672b079e4031f42729056e999c20bf87281798eb9Michael Jurka final int yDiff = (int) Math.abs(y - mLastMotionY); 12772b079e4031f42729056e999c20bf87281798eb9Michael Jurka 12872b079e4031f42729056e999c20bf87281798eb9Michael Jurka final int touchSlop = mTouchSlop; 12972b079e4031f42729056e999c20bf87281798eb9Michael Jurka boolean yMoved = yDiff > touchSlop; 13072b079e4031f42729056e999c20bf87281798eb9Michael Jurka boolean isUpwardMotion = (yDiff / (float) xDiff) > mDragSlopeThreshold; 13172b079e4031f42729056e999c20bf87281798eb9Michael Jurka 13272b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (isUpwardMotion && yMoved && mLastTouchedItem != null) { 13372b079e4031f42729056e999c20bf87281798eb9Michael Jurka // Drag if the user moved far enough along the Y axis 13472b079e4031f42729056e999c20bf87281798eb9Michael Jurka beginDragging(mLastTouchedItem); 13572b079e4031f42729056e999c20bf87281798eb9Michael Jurka 13672b079e4031f42729056e999c20bf87281798eb9Michael Jurka // Cancel any pending long press 13772b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (mAllowLongPress) { 13872b079e4031f42729056e999c20bf87281798eb9Michael Jurka mAllowLongPress = false; 13972b079e4031f42729056e999c20bf87281798eb9Michael Jurka // Try canceling the long press. It could also have been scheduled 14072b079e4031f42729056e999c20bf87281798eb9Michael Jurka // by a distant descendant, so use the mAllowLongPress flag to block 14172b079e4031f42729056e999c20bf87281798eb9Michael Jurka // everything 14272b079e4031f42729056e999c20bf87281798eb9Michael Jurka final View currentPage = getPageAt(mCurrentPage); 14372b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (currentPage != null) { 14472b079e4031f42729056e999c20bf87281798eb9Michael Jurka currentPage.cancelLongPress(); 14572b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 14672b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 14772b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 14872b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 14972b079e4031f42729056e999c20bf87281798eb9Michael Jurka 15072b079e4031f42729056e999c20bf87281798eb9Michael Jurka public void setDragSlopeThreshold(float dragSlopeThreshold) { 15172b079e4031f42729056e999c20bf87281798eb9Michael Jurka mDragSlopeThreshold = dragSlopeThreshold; 15272b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 15372b079e4031f42729056e999c20bf87281798eb9Michael Jurka} 154