/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.and.DragListView;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
public class TouchListView extends ListView {
private ImageView mDragView;
private WindowManager mWindowManager;
private WindowManager.LayoutParams mWindowParams;
/**
* At which position is the item currently being dragged. Note that this
* takes in to account header items.
*/
private int mDragPos;
/**
* At which position was the item being dragged originally
*/
private int mSrcDragPos;
private int mDragPointX; // at what x offset inside the item did the user grab it
private int mDragPointY; // at what y offset inside the item did the user grab it
private int mXOffset; // the difference between screen coordinates and coordinates in this view
private int mYOffset; // the difference between screen coordinates and coordinates in this view
private DragListener mDragListener;
private DropListener mDropListener;
private RemoveListener mRemoveListener;
private int mUpperBound;
private int mLowerBound;
private int mHeight;
private GestureDetector mGestureDetector;
private static final int FLING = 0;
private static final int SLIDE = 1;
private static final int TRASH = 2;
private int mRemoveMode = -1;
private Rect mTempRect = new Rect();
private Bitmap mDragBitmap;
private final int mTouchSlop;
private int mItemHeightNormal;
private int mItemHeightExpanded;
private int mItemHeightHalf;
private Drawable mTrashcan;
public TouchListView(Context context) {
this(context, null);
}
public TouchListView(Context context, AttributeSet attrs) {
super(context, attrs);
SharedPreferences pref = context.getSharedPreferences("Music", 3);
mRemoveMode = pref.getInt("deletemode", -1);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
Resources res = getResources();
mItemHeightNormal = res.getDimensionPixelSize(R.dimen.normal_height);
mItemHeightHalf = mItemHeightNormal / 2;
mItemHeightExpanded = res.getDimensionPixelSize(R.dimen.expanded_height);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mRemoveListener != null && mGestureDetector == null) {
if (mRemoveMode == FLING) {
mGestureDetector = new GestureDetector(getContext(), new SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (mDragView != null) {
if (velocityX > 1000) {
Rect r = mTempRect;
mDragView.getDrawingRect(r);
if ( e2.getX() > r.right * 2 / 3) {
// fast fling right with release near the right edge of the screen
stopDragging();
mRemoveListener.remove(mSrcDragPos);
unExpandViews(true);
}
}
// flinging while dragging should have no effect
return true;
}
return false;
}
});
}
}
if (mDragListener != null || mDropListener != null) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
int x = (int) ev.getX();
int y = (int) ev.getY();
int itemnum = pointToPosition(x, y);
if (itemnum == AdapterView.INVALID_POSITION) {
break;
}
ViewGroup item = (ViewGroup) getChildAt(itemnum - getFirstVisiblePosition());
mDragPointX = x - item.getLeft();
mDragPointY = y - item.getTop();
mXOffset = ((int)ev.getRawX()) - x;
mYOffset = ((int)ev.getRawY()) - y;
// The left side of the item is the grabber for dragging the item
if (x < 64) {
item.setDrawingCacheEnabled(true);
// Create a copy of the drawing cache so that it does not get recycled
// by the framework when the list tries to clean up memory
Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());
startDragging(bitmap, x, y);
mDragPos = itemnum;
mSrcDragPos = mDragPos;
mHeight = getHeight();
int touchSlop = mTouchSlop;
mUpperBound = Math.min(y - touchSlop, mHeight / 3);
mLowerBound = Math.max(y + touchSlop, mHeight * 2 /3);
return false;
}
stopDragging();
break;
}
}
return super.onInterceptTouchEvent(ev);
}
/*
* pointToPosition() doesn't consider invisible views, but we
* need to, so implement a slightly different version.
*/
private int myPointToPosition(int x, int y) {
if (y < 0) {
// when dragging off the top of the screen, calculate position
// by going back from a visible item
int pos = myPointToPosition(x, y + mItemHeightNormal);
if (pos > 0) {
return pos - 1;
}
}
Rect frame = mTempRect;
final int count = getChildCount();
for (int i = count - 1; i >= 0; i--) {
final View child = getChildAt(i);
child.getHitRect(frame);
if (frame.contains(x, y)) {
return getFirstVisiblePosition() + i;
}
}
return INVALID_POSITION;
}
private int getItemForPosition(int y) {
int adjustedy = y - mDragPointY - mItemHeightHalf;
int pos = myPointToPosition(0, adjustedy);
if (pos >= 0) {
if (pos <= mSrcDragPos) {
pos += 1;
}
} else if (adjustedy < 0) {
// this shouldn't happen anymore now that myPointToPosition deals
// with this situation
pos = 0;
}
return pos;
}
private void adjustScrollBounds(int y) {
if (y >= mHeight / 3) {
mUpperBound = mHeight / 3;
}