Correct drag & drop mechanics; implement multiple selection

* This CL brings drag&drop move in line with the current document
  describing its functionality in the Email app

Bug: 3135124

TODO: Assets and proper creation of the drag thumbnail based on
  those assets
TODO: Review long-press behavior re: press on subject vs sender

Change-Id: I6e1ee1a1f055feb041a0338f2f5c775a88620595
This commit is contained in:
Marc Blank 2010-11-04 12:15:32 -07:00
parent 138abe82e6
commit bad09c18d9
3 changed files with 99 additions and 100 deletions

View File

@ -30,19 +30,9 @@
android:layout_height="match_parent"
android:layout_centerVertical="true"
/>
<ImageView
android:id="@+id/handle"
android:layout_toRightOf="@id/chip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="10dip"
android:paddingRight="5dip"
android:src="@drawable/drag_handle"
/>
<ImageView
android:id="@+id/selected"
android:layout_toRightOf="@id/handle"
android:layout_toRightOf="@id/chip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"

View File

@ -24,34 +24,47 @@ import com.android.email.Utility;
import com.android.email.Utility.ListStateSaver;
import com.android.email.data.MailboxAccountLoader;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.Message;
import com.android.email.service.MailService;
import android.app.Activity;
import android.app.ListFragment;
import android.app.LoaderManager;
import android.content.ClipData;
import android.content.ContentUris;
import android.content.Context;
import android.content.Loader;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextPaint;
import android.util.Log;
import android.view.ActionMode;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.DragThumbnailBuilder;
import android.view.View.OnDragListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import java.security.InvalidParameterException;
import java.util.HashSet;
@ -75,7 +88,7 @@ import java.util.Set;
*/
public class MessageListFragment extends ListFragment
implements OnItemClickListener, OnItemLongClickListener, MessagesAdapter.Callback,
MoveMessageToDialog.Callback {
MoveMessageToDialog.Callback, OnDragListener {
private static final String BUNDLE_LIST_STATE = "MessageListFragment.state.listState";
private static final String BUNDLE_KEY_SELECTED_MESSAGE_ID
= "messageListFragment.state.listState.selected_message_id";
@ -425,9 +438,89 @@ public class MessageListFragment extends ListFragment
}
}
// This is tentative drag & drop UI
// STOPSHIP this entire class needs to be rewritten based on the actual UI design
private static class ThumbnailBuilder extends DragThumbnailBuilder {
private static Drawable sBackground;
private static TextPaint sPaint;
// TODO Get actual dimention from UI
private static final int mWidth = 250;
private final int mHeight;
private String mDragDesc;
private float mDragDescX;
private float mDragDescY;
public ThumbnailBuilder(View view, int count) {
super(view);
Resources resources = view.getResources();
// TODO Get actual dimension from UI
mHeight = view.getHeight();
mDragDesc = resources.getQuantityString(R.plurals.move_messages, count, count);
mDragDescX = 60;
// Use height of this font??
mDragDescY = view.getHeight() / 2;
if (sBackground == null) {
sBackground = resources.getDrawable(R.drawable.drag_background_holo);
sBackground.setBounds(0, 0, mWidth, view.getHeight());
sPaint = new TextPaint();
sPaint.setTypeface(Typeface.DEFAULT_BOLD);
sPaint.setTextSize(18);
}
}
@Override
public void onProvideThumbnailMetrics(Point thumbnailSize, Point thumbnailTouchPoint) {
thumbnailSize.set(mWidth, (int) mHeight);
thumbnailTouchPoint.set((int) 20, (int) mHeight / 2);
}
@Override
public void onDrawThumbnail(Canvas canvas) {
super.onDrawThumbnail(canvas);
sBackground.draw(canvas);
canvas.drawText(mDragDesc, mDragDescX, mDragDescY, sPaint);
}
}
public boolean onDrag(View view, DragEvent event) {
switch(event.getAction()) {
case DragEvent.ACTION_DRAG_ENDED:
if (event.getResult()) {
finishSelectionMode();
}
break;
}
return false;
}
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (view != mListFooterView) {
toggleSelection((MessageListItem) view);
MessageListItem listItem = (MessageListItem)view;
if (!mListAdapter.isSelected(listItem)) {
toggleSelection(listItem);
}
// Create ClipData with the Uri of the message we're long clicking
ClipData data = ClipData.newUri(mActivity.getContentResolver(),
MessageListItem.MESSAGE_LIST_ITEMS_CLIP_LABEL, null,
Message.CONTENT_URI.buildUpon()
.appendPath(Long.toString(listItem.mMessageId))
.appendQueryParameter(
EmailProvider.MESSAGE_URI_PARAMETER_MAILBOX_ID,
Long.toString(mMailboxId))
.build());
Set<Long> selectedMessageIds = mListAdapter.getSelectedSet();
int size = selectedMessageIds.size();
// Add additional Uri's for any other selected messages
for (Long messageId: selectedMessageIds) {
if (messageId.longValue() != listItem.mMessageId) {
data.addItem(new ClipData.Item(
ContentUris.withAppendedId(Message.CONTENT_URI, messageId)));
}
}
// Start dragging now
listItem.setOnDragListener(this);
listItem.startDrag(data, new ThumbnailBuilder(listItem, size), false);
return true;
}
return false;

View File

@ -17,22 +17,10 @@
package com.android.email.activity;
import com.android.email.R;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.EmailContent.Message;
import android.content.ClipData;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
/**
@ -41,7 +29,6 @@ import android.widget.RelativeLayout;
* 2. It handles internal clicks such as the checkbox or the favorite star
*/
public class MessageListItem extends RelativeLayout {
private static final String TAG = "MessageListItem";
// Note: messagesAdapter directly fiddles with these fields.
/* package */ long mMessageId;
/* package */ long mMailboxId;
@ -53,7 +40,6 @@ public class MessageListItem extends RelativeLayout {
private boolean mDownEvent;
private boolean mCachedViewPositions;
private int mDragRight = -1;
private int mCheckRight;
private int mStarLeft;
@ -86,59 +72,6 @@ public class MessageListItem extends RelativeLayout {
mCachedViewPositions = false;
}
// This is tentative drag & drop UI
// STOPSHIP this entire class needs to be rewritten based on the actual UI design
private static class ThumbnailBuilder extends DragThumbnailBuilder {
private static Drawable sBackground;
private static TextPaint sPaint;
private View mView;
private static final int mWidth = 250;
private final Bitmap mDragHandle;
private final float mDragHandleX;
private final float mDragHandleY;
private String mDragDesc;
private float mDragDescX;
private float mDragDescY;
public ThumbnailBuilder(View view, int count) {
super(view);
Resources resources = view.getResources();
mView = view;
mDragHandle = BitmapFactory.decodeResource(resources, R.drawable.drag_handle);
mDragHandleY = view.getHeight() - (mDragHandle.getHeight() / 2);
View handleView = view.findViewById(R.id.handle);
mDragHandleX = handleView.getLeft() + handleView.getPaddingLeft();
mDragDesc = resources.getQuantityString(R.plurals.move_messages, count, count);
mDragDescX = handleView.getRight() + 50;
// Use height of this font??
mDragDescY = view.getHeight() / 2;
if (sBackground == null) {
sBackground = resources.getDrawable(R.drawable.drag_background_holo);
sBackground.setBounds(0, 0, mWidth, view.getHeight());
sPaint = new TextPaint();
sPaint.setTypeface(Typeface.DEFAULT_BOLD);
sPaint.setTextSize(18);
}
}
@Override
public void onProvideThumbnailMetrics(Point thumbnailSize, Point thumbnailTouchPoint) {
//float width = mView.getWidth();
float height = mView.getHeight();
thumbnailSize.set(mWidth, (int) height);
thumbnailTouchPoint.set((int) mDragHandleX, (int) mDragHandleY / 2);
}
@Override
public void onDrawThumbnail(Canvas canvas) {
super.onDrawThumbnail(canvas);
sBackground.draw(canvas);
canvas.drawBitmap(mDragHandle, mDragHandleX, mDragHandleY, sPaint);
canvas.drawText(mDragDesc, mDragDescX, mDragDescY, sPaint);
}
}
/**
* Overriding this method allows us to "catch" clicks in the checkbox or star
* and process them accordingly.
@ -152,10 +85,6 @@ public class MessageListItem extends RelativeLayout {
final float paddingScale = getContext().getResources().getDisplayMetrics().density;
final int checkPadding = (int) ((CHECKMARK_PAD * paddingScale) + 0.5);
final int starPadding = (int) ((STAR_PAD * paddingScale) + 0.5);
View dragHandle = findViewById(R.id.handle);
if (dragHandle != null) {
mDragRight = dragHandle.getRight();
}
mCheckRight = findViewById(R.id.selected).getRight() + checkPadding;
mStarLeft = findViewById(R.id.favorite).getLeft() - starPadding;
mCachedViewPositions = true;
@ -163,20 +92,7 @@ public class MessageListItem extends RelativeLayout {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (touchX < mDragRight) {
Context context = getContext();
// Drag
ClipData data = ClipData.newUri(context.getContentResolver(),
MessageListItem.MESSAGE_LIST_ITEMS_CLIP_LABEL, null,
Message.CONTENT_URI.buildUpon()
.appendPath(Long.toString(mMessageId))
.appendQueryParameter(
EmailProvider.MESSAGE_URI_PARAMETER_MAILBOX_ID,
Long.toString(mMailboxId))
.build());
startDrag(data, new ThumbnailBuilder(this, 1), false);
handled = true;
} else {
if (touchX < mCheckRight) {
mDownEvent = true;
if ((touchX < mCheckRight) || (touchX > mStarLeft)) {
handled = true;