PagedViewWithDraggableItems.java revision 36a62fe917be0a2520c457f985075fb5d3d09d1c
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; 3894569f47c2fe3c2e04e993379d36e0597925e19fWinson Chung private boolean mIsDragEnabled; 3972b079e4031f42729056e999c20bf87281798eb9Michael Jurka private float mDragSlopeThreshold; 40fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen private Launcher mLauncher; 4172b079e4031f42729056e999c20bf87281798eb9Michael Jurka 4272b079e4031f42729056e999c20bf87281798eb9Michael Jurka public PagedViewWithDraggableItems(Context context) { 43fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen this(context, null); 4472b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 4572b079e4031f42729056e999c20bf87281798eb9Michael Jurka 4672b079e4031f42729056e999c20bf87281798eb9Michael Jurka public PagedViewWithDraggableItems(Context context, AttributeSet attrs) { 47fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen this(context, attrs, 0); 4872b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 4972b079e4031f42729056e999c20bf87281798eb9Michael Jurka 5072b079e4031f42729056e999c20bf87281798eb9Michael Jurka public PagedViewWithDraggableItems(Context context, AttributeSet attrs, int defStyle) { 5172b079e4031f42729056e999c20bf87281798eb9Michael Jurka super(context, attrs, defStyle); 52fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen mLauncher = (Launcher) context; 5372b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 5472b079e4031f42729056e999c20bf87281798eb9Michael Jurka 5572b079e4031f42729056e999c20bf87281798eb9Michael Jurka protected boolean beginDragging(View v) { 56304dcde0e301c2f1a0b2bdc80ea8617930691b6eWinson Chung boolean wasDragging = mIsDragging; 5772b079e4031f42729056e999c20bf87281798eb9Michael Jurka mIsDragging = true; 58304dcde0e301c2f1a0b2bdc80ea8617930691b6eWinson Chung return !wasDragging; 5972b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 6072b079e4031f42729056e999c20bf87281798eb9Michael Jurka 617d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung protected void cancelDragging() { 627d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung mIsDragging = false; 637d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung mLastTouchedItem = null; 6494569f47c2fe3c2e04e993379d36e0597925e19fWinson Chung mIsDragEnabled = false; 657d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung } 667d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung 677d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung private void handleTouchEvent(MotionEvent ev) { 6872b079e4031f42729056e999c20bf87281798eb9Michael Jurka final int action = ev.getAction(); 6972b079e4031f42729056e999c20bf87281798eb9Michael Jurka switch (action & MotionEvent.ACTION_MASK) { 7072b079e4031f42729056e999c20bf87281798eb9Michael Jurka case MotionEvent.ACTION_DOWN: 717d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung cancelDragging(); 7294569f47c2fe3c2e04e993379d36e0597925e19fWinson Chung mIsDragEnabled = true; 7372b079e4031f42729056e999c20bf87281798eb9Michael Jurka break; 7472b079e4031f42729056e999c20bf87281798eb9Michael Jurka case MotionEvent.ACTION_MOVE: 7594569f47c2fe3c2e04e993379d36e0597925e19fWinson Chung if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging && mIsDragEnabled) { 7672b079e4031f42729056e999c20bf87281798eb9Michael Jurka determineDraggingStart(ev); 7772b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 7872b079e4031f42729056e999c20bf87281798eb9Michael Jurka break; 7972b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 8072b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 8172b079e4031f42729056e999c20bf87281798eb9Michael Jurka 8272b079e4031f42729056e999c20bf87281798eb9Michael Jurka @Override 837d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung public boolean onInterceptTouchEvent(MotionEvent ev) { 847d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung handleTouchEvent(ev); 857d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung return super.onInterceptTouchEvent(ev); 8672b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 8772b079e4031f42729056e999c20bf87281798eb9Michael Jurka 8872b079e4031f42729056e999c20bf87281798eb9Michael Jurka @Override 8972b079e4031f42729056e999c20bf87281798eb9Michael Jurka public boolean onTouchEvent(MotionEvent ev) { 907d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung handleTouchEvent(ev); 9172b079e4031f42729056e999c20bf87281798eb9Michael Jurka return super.onTouchEvent(ev); 9272b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 9372b079e4031f42729056e999c20bf87281798eb9Michael Jurka 9472b079e4031f42729056e999c20bf87281798eb9Michael Jurka @Override 957d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung public boolean onTouch(View v, MotionEvent event) { 967d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung mLastTouchedItem = v; 9794569f47c2fe3c2e04e993379d36e0597925e19fWinson Chung mIsDragEnabled = true; 987d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung return false; 997d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung } 1007d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung 1017d1fcbc409015a46219f088c6d5edbd8ab5012f8Winson Chung @Override 10272b079e4031f42729056e999c20bf87281798eb9Michael Jurka public boolean onLongClick(View v) { 10372b079e4031f42729056e999c20bf87281798eb9Michael Jurka // Return early if this is not initiated from a touch 10472b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (!v.isInTouchMode()) return false; 10572b079e4031f42729056e999c20bf87281798eb9Michael Jurka // Return early if we are still animating the pages 10672b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (mNextPage != INVALID_PAGE) return false; 107fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen // When we have exited all apps or are in transition, disregard long clicks 108fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen if (!mLauncher.isAllAppsCustomizeOpen() || 109fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen mLauncher.getWorkspace().isSwitchingState()) return false; 11036a62fe917be0a2520c457f985075fb5d3d09d1cWinson Chung // Return if global dragging is not enabled 11136a62fe917be0a2520c457f985075fb5d3d09d1cWinson Chung if (!mLauncher.isDraggingEnabled()) return false; 112fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen 11372b079e4031f42729056e999c20bf87281798eb9Michael Jurka return beginDragging(v); 11472b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 11572b079e4031f42729056e999c20bf87281798eb9Michael Jurka 11672b079e4031f42729056e999c20bf87281798eb9Michael Jurka /* 11772b079e4031f42729056e999c20bf87281798eb9Michael Jurka * Determines if we should change the touch state to start scrolling after the 11872b079e4031f42729056e999c20bf87281798eb9Michael Jurka * user moves their touch point too far. 11972b079e4031f42729056e999c20bf87281798eb9Michael Jurka */ 12072b079e4031f42729056e999c20bf87281798eb9Michael Jurka protected void determineScrollingStart(MotionEvent ev) { 12172b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (!mIsDragging) super.determineScrollingStart(ev); 12272b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 12372b079e4031f42729056e999c20bf87281798eb9Michael Jurka 12472b079e4031f42729056e999c20bf87281798eb9Michael Jurka /* 12572b079e4031f42729056e999c20bf87281798eb9Michael Jurka * Determines if we should change the touch state to start dragging after the 12672b079e4031f42729056e999c20bf87281798eb9Michael Jurka * user moves their touch point far enough. 12772b079e4031f42729056e999c20bf87281798eb9Michael Jurka */ 12872b079e4031f42729056e999c20bf87281798eb9Michael Jurka protected void determineDraggingStart(MotionEvent ev) { 12972b079e4031f42729056e999c20bf87281798eb9Michael Jurka /* 13072b079e4031f42729056e999c20bf87281798eb9Michael Jurka * Locally do absolute value. mLastMotionX is set to the y value 13172b079e4031f42729056e999c20bf87281798eb9Michael Jurka * of the down event. 13272b079e4031f42729056e999c20bf87281798eb9Michael Jurka */ 13372b079e4031f42729056e999c20bf87281798eb9Michael Jurka final int pointerIndex = ev.findPointerIndex(mActivePointerId); 13472b079e4031f42729056e999c20bf87281798eb9Michael Jurka final float x = ev.getX(pointerIndex); 13572b079e4031f42729056e999c20bf87281798eb9Michael Jurka final float y = ev.getY(pointerIndex); 13672b079e4031f42729056e999c20bf87281798eb9Michael Jurka final int xDiff = (int) Math.abs(x - mLastMotionX); 13772b079e4031f42729056e999c20bf87281798eb9Michael Jurka final int yDiff = (int) Math.abs(y - mLastMotionY); 13872b079e4031f42729056e999c20bf87281798eb9Michael Jurka 13972b079e4031f42729056e999c20bf87281798eb9Michael Jurka final int touchSlop = mTouchSlop; 14072b079e4031f42729056e999c20bf87281798eb9Michael Jurka boolean yMoved = yDiff > touchSlop; 14172b079e4031f42729056e999c20bf87281798eb9Michael Jurka boolean isUpwardMotion = (yDiff / (float) xDiff) > mDragSlopeThreshold; 14272b079e4031f42729056e999c20bf87281798eb9Michael Jurka 14372b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (isUpwardMotion && yMoved && mLastTouchedItem != null) { 14472b079e4031f42729056e999c20bf87281798eb9Michael Jurka // Drag if the user moved far enough along the Y axis 14572b079e4031f42729056e999c20bf87281798eb9Michael Jurka beginDragging(mLastTouchedItem); 14672b079e4031f42729056e999c20bf87281798eb9Michael Jurka 14772b079e4031f42729056e999c20bf87281798eb9Michael Jurka // Cancel any pending long press 14872b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (mAllowLongPress) { 14972b079e4031f42729056e999c20bf87281798eb9Michael Jurka mAllowLongPress = false; 15072b079e4031f42729056e999c20bf87281798eb9Michael Jurka // Try canceling the long press. It could also have been scheduled 15172b079e4031f42729056e999c20bf87281798eb9Michael Jurka // by a distant descendant, so use the mAllowLongPress flag to block 15272b079e4031f42729056e999c20bf87281798eb9Michael Jurka // everything 15372b079e4031f42729056e999c20bf87281798eb9Michael Jurka final View currentPage = getPageAt(mCurrentPage); 15472b079e4031f42729056e999c20bf87281798eb9Michael Jurka if (currentPage != null) { 15572b079e4031f42729056e999c20bf87281798eb9Michael Jurka currentPage.cancelLongPress(); 15672b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 15772b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 15872b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 15972b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 16072b079e4031f42729056e999c20bf87281798eb9Michael Jurka 16172b079e4031f42729056e999c20bf87281798eb9Michael Jurka public void setDragSlopeThreshold(float dragSlopeThreshold) { 16272b079e4031f42729056e999c20bf87281798eb9Michael Jurka mDragSlopeThreshold = dragSlopeThreshold; 16372b079e4031f42729056e999c20bf87281798eb9Michael Jurka } 1642313eff05b8f52e72ebe06c589c419941fa019d6Patrick Dubroy 1652313eff05b8f52e72ebe06c589c419941fa019d6Patrick Dubroy @Override 1662313eff05b8f52e72ebe06c589c419941fa019d6Patrick Dubroy protected void onDetachedFromWindow() { 16794569f47c2fe3c2e04e993379d36e0597925e19fWinson Chung cancelDragging(); 1682313eff05b8f52e72ebe06c589c419941fa019d6Patrick Dubroy super.onDetachedFromWindow(); 1692313eff05b8f52e72ebe06c589c419941fa019d6Patrick Dubroy } 1701afedc379f8271b9bf86a8d887c3c020d5e59214Winson Chung 1711afedc379f8271b9bf86a8d887c3c020d5e59214Winson Chung /** Show the scrolling indicators when we move the page */ 1721afedc379f8271b9bf86a8d887c3c020d5e59214Winson Chung protected void onPageBeginMoving() { 1731afedc379f8271b9bf86a8d887c3c020d5e59214Winson Chung showScrollingIndicator(false); 1741afedc379f8271b9bf86a8d887c3c020d5e59214Winson Chung } 1751afedc379f8271b9bf86a8d887c3c020d5e59214Winson Chung protected void onPageEndMoving() { 1761afedc379f8271b9bf86a8d887c3c020d5e59214Winson Chung hideScrollingIndicator(false); 1771afedc379f8271b9bf86a8d887c3c020d5e59214Winson Chung } 17872b079e4031f42729056e999c20bf87281798eb9Michael Jurka} 179