Merge "If the size is 0, dont show anything." into jb-ub-mail
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7fc9f0b..aa6693b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -555,9 +555,9 @@
<!-- Shown in a toast to acknowledge always showing images for a sender [CHAR LIMIT=100] -->
<string name="always_show_images_toast">Pictures from this sender will be shown automatically.</string>
<!-- Display format of an email recipient, displayed in expanded message details [CHAR LIMIT=10] -->
- <string name="address_display_format"><xliff:g id="name">%1$s</xliff:g> <<xliff:g id="email">%2$s</xliff:g>></string>
+ <string name="address_display_format"><xliff:g id="name">%1$s</xliff:g> <xliff:g id="email">%2$s</xliff:g></string>
<!-- Display format of an email sender if the message has a via domain set, displayed in expanded message details [CHAR LIMIT=15] -->
- <string name="address_display_format_with_via_domain"><xliff:g id="name">%1$s</xliff:g> <<xliff:g id="email">%2$s</xliff:g>> via <xliff:g id="via_domain">%3$s</xliff:g></string>
+ <string name="address_display_format_with_via_domain"><xliff:g id="name">%1$s</xliff:g> <xliff:g id="email">%2$s</xliff:g> via <xliff:g id="via_domain">%3$s</xliff:g></string>
<!-- Displayed for one second after user saves message as draft [CHAR LIMIT=50]-->
<string name="message_saved">Message saved as draft.</string>
<!-- Displayed for one second while message is being sent [CHAR LIMIT=50]-->
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 53251d7..edbc3b2 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -21,6 +21,8 @@
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.content.ClipData;
+import android.content.ClipData.Item;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
@@ -30,6 +32,7 @@
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.Typeface;
@@ -48,6 +51,7 @@
import android.text.style.StyleSpan;
import android.util.SparseArray;
import android.view.Gravity;
+import android.view.DragEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -71,6 +75,7 @@
import com.android.mail.ui.SwipeableListView;
import com.android.mail.ui.ViewMode;
import com.android.mail.utils.LogTag;
+import com.android.mail.utils.LogUtils;
import com.android.mail.utils.Utils;
import com.google.common.annotations.VisibleForTesting;
@@ -106,7 +111,6 @@
private static String sSendersSplitToken;
private static String sElidedPaddingToken;
- private static String sEllipsis;
// Static colors.
private static int sDefaultTextColor;
@@ -160,6 +164,8 @@
private boolean mPriorityMarkersEnabled;
private boolean mCheckboxesEnabled;
private boolean mSwipeEnabled;
+ private int mLastTouchX;
+ private int mLastTouchY;
private AnimatedAdapter mAdapter;
private int mAnimatedHeight = -1;
private String mAccount;
@@ -372,7 +378,6 @@
// Initialize static color.
sSendersSplitToken = res.getString(R.string.senders_split_token);
sElidedPaddingToken = res.getString(R.string.elided_padding_token);
- sEllipsis = res.getString(R.string.ellipsis);
sAnimatingBackgroundColor = res.getColor(R.color.animating_item_background_color);
sSendersTextViewTopPadding = res.getDimensionPixelSize
(R.dimen.senders_textview_top_padding);
@@ -1172,23 +1177,26 @@
* Toggle the check mark on this view and update the conversation
*/
public void toggleCheckMark() {
- if (mHeader != null && mHeader.conversation != null) {
- mChecked = !mChecked;
- Conversation conv = mHeader.conversation;
- // Set the list position of this item in the conversation
- ListView listView = getListView();
- conv.position = mChecked && listView != null ? listView.getPositionForView(this)
- : Conversation.NO_POSITION;
- if (mSelectedConversationSet != null) {
- mSelectedConversationSet.toggle(this, conv);
+ ViewMode mode = mActivity.getViewMode();
+ if (!mTabletDevice || !mode.isListMode()) {
+ if (mHeader != null && mHeader.conversation != null) {
+ mChecked = !mChecked;
+ Conversation conv = mHeader.conversation;
+ // Set the list position of this item in the conversation
+ ListView listView = getListView();
+ conv.position = mChecked && listView != null ? listView.getPositionForView(this)
+ : Conversation.NO_POSITION;
+ if (mSelectedConversationSet != null) {
+ mSelectedConversationSet.toggle(this, conv);
+ }
+ // We update the background after the checked state has changed
+ // now that we have a selected background asset. Setting the background
+ // usually waits for a layout pass, but we don't need a full layout,
+ // just an update to the background.
+ requestLayout();
}
- // We update the background after the checked state has changed now
- // that
- // we have a selected background asset. Setting the background
- // usually
- // waits for a layout pass, but we don't need a full layout, just an
- // update to the background.
- requestLayout();
+ } else {
+ beginDragMode();
}
}
@@ -1243,6 +1251,8 @@
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
+ mLastTouchX = x;
+ mLastTouchY = y;
if (!mSwipeEnabled) {
return onTouchEventNoSwipe(event);
}
@@ -1298,29 +1308,26 @@
}
private boolean onTouchEventNoSwipe(MotionEvent event) {
- boolean handled = true;
+ boolean handled = false;
int x = (int) event.getX();
int y = (int) event.getY();
+ mLastTouchX = x;
+ mLastTouchY = y;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownEvent = true;
- // In order to allow the down event and subsequent move events
- // to bubble to the swipe handler, we need to return that all
- // down events are handled.
- handled = isTouchInCheckmark(x, y) || isTouchInStar(x, y);
+ if (isTouchInCheckmark(x, y) || isTouchInStar(x, y)) {
+ handled = true;
+ }
break;
+
case MotionEvent.ACTION_CANCEL:
mDownEvent = false;
break;
+
case MotionEvent.ACTION_UP:
if (mDownEvent) {
- // ConversationItemView gets the first chance to handle up
- // events if there was a down event and there was no move
- // event in between. In this case, ConversationItemView
- // received the down event, and then an up event in the
- // same location (+/- slop). Treat this as a click on the
- // view or on a specific part of the view.
if (isTouchInCheckmark(x, y)) {
// Touch on the check mark
toggleCheckMark();
@@ -1329,16 +1336,15 @@
toggleStar();
}
handled = true;
- } else {
- // There was no down event that this view was made aware of,
- // therefore it cannot handle it.
- handled = false;
}
break;
}
- // Let View try to handle it as well.
- return handled || super.onTouchEvent(event);
+ if (!handled) {
+ handled = super.onTouchEvent(event);
+ }
+
+ return handled;
}
/**
@@ -1491,4 +1497,105 @@
public View getSwipeableView() {
return this;
}
+
+ /**
+ * Select the current conversation.
+ */
+ private void selectConversation() {
+ if (!mSelectedConversationSet.containsKey(mHeader.conversation.id)) {
+ mChecked = !mChecked;
+ Conversation conv = mHeader.conversation;
+ // Set the list position of this item in the conversation
+ ListView listView = getListView();
+ conv.position = mChecked && listView != null ? listView.getPositionForView(this)
+ : Conversation.NO_POSITION;
+ if (mSelectedConversationSet != null) {
+ mSelectedConversationSet.toggle(this, conv);
+ }
+ }
+ }
+
+ /**
+ * Begin drag mode. Keep the conversation selected (NOT toggle selection) and start drag.
+ */
+ private void beginDragMode() {
+ selectConversation();
+
+ // Clip data has form: [conversations_uri, conversationId1,
+ // maxMessageId1, label1, conversationId2, maxMessageId2, label2, ...]
+ final int count = mSelectedConversationSet.size();
+ String description = Utils.formatPlural(mContext, R.plurals.move_conversation, count);
+
+ final ClipData data = ClipData.newUri(mContext.getContentResolver(), description,
+ Conversation.MOVE_CONVERSATIONS_URI);
+ for (Conversation conversation : mSelectedConversationSet.values()) {
+ data.addItem(new Item(String.valueOf(conversation.position)));
+ }
+ // Protect against non-existent views: only happens for monkeys
+ final int width = this.getWidth();
+ final int height = this.getHeight();
+ final boolean isDimensionNegative = (width < 0) || (height < 0);
+ if (isDimensionNegative) {
+ LogUtils.e(LOG_TAG, "ConversationItemView: dimension is negative: "
+ + "width=%d, height=%d", width, height);
+ return;
+ }
+ mActivity.startDragMode();
+ // Start drag mode
+ startDrag(data, new ShadowBuilder(this, count, mLastTouchX, mLastTouchY), null, 0);
+ }
+
+ /**
+ * Handles the drag event.
+ *
+ * @param event the drag event to be handled
+ */
+ @Override
+ public boolean onDragEvent(DragEvent event) {
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_ENDED:
+ mActivity.stopDragMode();
+ return true;
+ }
+ return false;
+ }
+
+ private class ShadowBuilder extends DragShadowBuilder {
+ private final Drawable mBackground;
+
+ private final View mView;
+ private final String mDragDesc;
+ private final int mTouchX;
+ private final int mTouchY;
+ private int mDragDescX;
+ private int mDragDescY;
+
+ public ShadowBuilder(View view, int count, int touchX, int touchY) {
+ super(view);
+ mView = view;
+ mBackground = mView.getResources().getDrawable(R.drawable.list_pressed_holo);
+ mDragDesc = Utils.formatPlural(mView.getContext(), R.plurals.move_conversation, count);
+ mTouchX = touchX;
+ mTouchY = touchY;
+ }
+
+ @Override
+ public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
+ int width = mView.getWidth();
+ int height = mView.getHeight();
+ mDragDescX = mCoordinates.sendersX;
+ mDragDescY = getPadding(height, mCoordinates.subjectFontSize)
+ - mCoordinates.subjectAscent;
+ shadowSize.set(width, height);
+ shadowTouchPoint.set(mTouchX, mTouchY);
+ }
+
+ @Override
+ public void onDrawShadow(Canvas canvas) {
+ mBackground.setBounds(0, 0, mView.getWidth(), mView.getHeight());
+ mBackground.draw(canvas);
+ sPaint.setTextSize(mCoordinates.subjectFontSize);
+ canvas.drawText(mDragDesc, mDragDescX, mDragDescY, sPaint);
+ }
+ }
}
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 63cdbd5..efc4019 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -251,6 +251,7 @@
// will just run the next time the user opens the app.
private AsyncTask<String, Void, Void> mEnableShareIntents;
private Folder mFolderListFolder;
+ private boolean mIsDragHappening;
public static final String SYNC_ERROR_DIALOG_FRAGMENT_TAG = "SyncErrorDialogFragment";
public AbstractActivityController(MailActivity activity, ViewMode viewMode) {
@@ -1927,7 +1928,7 @@
@Override
public final void onRefreshRequired() {
- if (isAnimating()) {
+ if (isAnimating() || isDragging()) {
LogUtils.d(LOG_TAG, "onRefreshRequired: delay until animating done");
return;
}
@@ -1937,6 +1938,29 @@
}
}
+ @Override
+ public void startDragMode() {
+ mIsDragHappening = true;
+ }
+
+ @Override
+ public void stopDragMode() {
+ mIsDragHappening = false;
+ if (mConversationListCursor.isRefreshReady()) {
+ LogUtils.d(LOG_TAG, "Stopped animating: try sync");
+ onRefreshReady();
+ }
+
+ if (mConversationListCursor.isRefreshRequired()) {
+ LogUtils.d(LOG_TAG, "Stopped animating: refresh");
+ mConversationListCursor.refresh();
+ }
+ }
+
+ private boolean isDragging() {
+ return mIsDragHappening;
+ }
+
private boolean isAnimating() {
boolean isAnimating = false;
ConversationListFragment convListFragment = getConversationListFragment();
diff --git a/src/com/android/mail/ui/ActivityController.java b/src/com/android/mail/ui/ActivityController.java
index 524ad76..59d6776 100644
--- a/src/com/android/mail/ui/ActivityController.java
+++ b/src/com/android/mail/ui/ActivityController.java
@@ -308,4 +308,14 @@
* Handles the animation end of the animated adapter.
*/
void onAnimationEnd(AnimatedAdapter animatedAdapter);
+
+ /**
+ * Called when the user has started a drag/ drop gesture.
+ */
+ void startDragMode();
+
+ /**
+ * Called when the user has ended drag/drop.
+ */
+ void stopDragMode();
}
diff --git a/src/com/android/mail/ui/ControllableActivity.java b/src/com/android/mail/ui/ControllableActivity.java
index d4046a6..63d3318 100644
--- a/src/com/android/mail/ui/ControllableActivity.java
+++ b/src/com/android/mail/ui/ControllableActivity.java
@@ -105,4 +105,8 @@
* @return
*/
AccountController getAccountController();
+
+ void startDragMode();
+
+ void stopDragMode();
}
diff --git a/src/com/android/mail/ui/FolderSelectionActivity.java b/src/com/android/mail/ui/FolderSelectionActivity.java
index 1843d65..c698e6d 100644
--- a/src/com/android/mail/ui/FolderSelectionActivity.java
+++ b/src/com/android/mail/ui/FolderSelectionActivity.java
@@ -341,4 +341,14 @@
public void onFooterViewLoadMoreClick(Folder folder) {
// Unsupported
}
+
+ @Override
+ public void startDragMode() {
+ // Unsupported
+ }
+
+ @Override
+ public void stopDragMode() {
+ // Unsupported
+ }
}
diff --git a/src/com/android/mail/ui/MailActivity.java b/src/com/android/mail/ui/MailActivity.java
index 0418f8d..4a4c80c 100644
--- a/src/com/android/mail/ui/MailActivity.java
+++ b/src/com/android/mail/ui/MailActivity.java
@@ -423,4 +423,14 @@
public void onFooterViewLoadMoreClick(Folder folder) {
mController.onFooterViewLoadMoreClick(folder);
}
+
+ @Override
+ public void startDragMode() {
+ mController.startDragMode();
+ }
+
+ @Override
+ public void stopDragMode() {
+ mController.stopDragMode();
+ }
}