Merge "Import translations. DO NOT MERGE" into jb-ub-mail
diff --git a/res/drawable-hdpi/default_image.9.png b/res/drawable-hdpi/default_image.9.png
index 1514f6f..cccd75e 100644
--- a/res/drawable-hdpi/default_image.9.png
+++ b/res/drawable-hdpi/default_image.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_read_holo.9.png b/res/drawable-hdpi/list_read_holo.9.png
index a77b602..a04c062 100644
--- a/res/drawable-hdpi/list_read_holo.9.png
+++ b/res/drawable-hdpi/list_read_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/default_image.9.png b/res/drawable-mdpi/default_image.9.png
index 55d9f66..ac257dc 100644
--- a/res/drawable-mdpi/default_image.9.png
+++ b/res/drawable-mdpi/default_image.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_read_holo.9.png b/res/drawable-mdpi/list_read_holo.9.png
index 1898e61..fc9bb9d 100644
--- a/res/drawable-mdpi/list_read_holo.9.png
+++ b/res/drawable-mdpi/list_read_holo.9.png
Binary files differ
diff --git a/res/drawable-sw600dp-hdpi/list_read_holo.9.png b/res/drawable-sw600dp-hdpi/list_read_holo.9.png
index 2c47f2a..b4712a0 100644
--- a/res/drawable-sw600dp-hdpi/list_read_holo.9.png
+++ b/res/drawable-sw600dp-hdpi/list_read_holo.9.png
Binary files differ
diff --git a/res/drawable-sw600dp-mdpi/list_read_holo.9.png b/res/drawable-sw600dp-mdpi/list_read_holo.9.png
index 1b0fcaf..34e6052 100644
--- a/res/drawable-sw600dp-mdpi/list_read_holo.9.png
+++ b/res/drawable-sw600dp-mdpi/list_read_holo.9.png
Binary files differ
diff --git a/res/drawable-sw600dp-xhdpi/list_read_holo.9.png b/res/drawable-sw600dp-xhdpi/list_read_holo.9.png
index 09adb87..176e2d0 100644
--- a/res/drawable-sw600dp-xhdpi/list_read_holo.9.png
+++ b/res/drawable-sw600dp-xhdpi/list_read_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/default_image.9.png b/res/drawable-xhdpi/default_image.9.png
index 2771ff1..4b80f6c 100644
--- a/res/drawable-xhdpi/default_image.9.png
+++ b/res/drawable-xhdpi/default_image.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_read_holo.9.png b/res/drawable-xhdpi/list_read_holo.9.png
index 2c7b691..0f14404 100644
--- a/res/drawable-xhdpi/list_read_holo.9.png
+++ b/res/drawable-xhdpi/list_read_holo.9.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_mail.png b/res/mipmap-xhdpi/ic_launcher_mail.png
index 48247ce..6e1c194 100644
--- a/res/mipmap-xhdpi/ic_launcher_mail.png
+++ b/res/mipmap-xhdpi/ic_launcher_mail.png
Binary files differ
diff --git a/res/values/dimen.xml b/res/values/dimen.xml
index 610b73b..d211baf 100644
--- a/res/values/dimen.xml
+++ b/res/values/dimen.xml
@@ -99,4 +99,6 @@
<dimen name="toast_bar_bottom_margin_in_conversation">24dip</dimen>
<dimen name="undo_animation_offset">360dp</dimen>
<dimen name="wait_padding">16dp</dimen>
+ <dimen name="senders_textview_top_padding">-4dp</dimen>
+ <dimen name="senders_textview_height">30dp</dimen>
</resources>
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/AttachmentActionHandler.java b/src/com/android/mail/browse/AttachmentActionHandler.java
index d3028d3..5b3025f 100644
--- a/src/com/android/mail/browse/AttachmentActionHandler.java
+++ b/src/com/android/mail/browse/AttachmentActionHandler.java
@@ -125,8 +125,9 @@
private void showDownloadingDialog() {
mViewProgressDialog = new ProgressDialog(mContext);
mViewProgressDialog.setTitle(R.string.fetching_attachment);
- mViewProgressDialog.setMessage(mContext.getResources().getString(R.string.please_wait));
+ mViewProgressDialog.setMessage(mAttachment.name);
mViewProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ mViewProgressDialog.setIndeterminate(true);
mViewProgressDialog.setMax(mAttachment.size);
mViewProgressDialog.setOnDismissListener(this);
mViewProgressDialog.setOnCancelListener(this);
@@ -156,7 +157,11 @@
if (isProgressDialogVisible()) {
mViewProgressDialog.setProgress(mAttachment.downloadedSize);
- mViewProgressDialog.setIndeterminate(!showProgress);
+
+ // We don't want the progress bar to switch back to indeterminate mode after
+ // have been in determinate progress mode.
+ final boolean indeterminate = !showProgress && mViewProgressDialog.isIndeterminate();
+ mViewProgressDialog.setIndeterminate(indeterminate);
if (!mAttachment.isDownloading()) {
mViewProgressDialog.dismiss();
diff --git a/src/com/android/mail/browse/ConversationCursor.java b/src/com/android/mail/browse/ConversationCursor.java
index 5ba886d..107ef3a 100644
--- a/src/com/android/mail/browse/ConversationCursor.java
+++ b/src/com/android/mail/browse/ConversationCursor.java
@@ -231,6 +231,11 @@
@Override
protected void onPostExecute(Void param) {
synchronized(mCacheMapLock) {
+ // If cursor got closed (e.g. reset loader) in the meantime, cancel the refresh
+ if (isClosed()) {
+ onCancelled();
+ return;
+ }
mRequeryCursor = mCursor;
// Make sure window is full
mRequeryCursor.getCount();
@@ -790,7 +795,7 @@
}
}
return true;
- } else if ((mPosition - pos) > pos) {
+ } else if ((pos >= 0) && (mPosition - pos) > pos) {
// Optimization if it's easier to move forward to position instead of backward
// STOPSHIP (Remove logging)
LogUtils.i(TAG, "*** Move from %d to %d, starting from first", mPosition, pos);
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 3aab551..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;
@@ -47,10 +50,15 @@
import android.text.style.ForegroundColorSpan;
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;
+import android.view.ViewGroup.LayoutParams;
import android.view.animation.DecelerateInterpolator;
import android.widget.ListView;
+import android.widget.TextView;
import com.android.mail.R;
import com.android.mail.browse.ConversationItemViewModel.SenderFragment;
@@ -67,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;
@@ -102,7 +111,6 @@
private static String sSendersSplitToken;
private static String sElidedPaddingToken;
- private static String sEllipsis;
// Static colors.
private static int sDefaultTextColor;
@@ -156,12 +164,16 @@
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;
private ControllableActivity mActivity;
private CharacterStyle mActivatedTextSpan;
private int mBackgroundOverride = -1;
+ private static int sSendersTextViewTopPadding;
+ private static int sSendersTextViewHeight;
private static ForegroundColorSpan sActivatedTextSpan;
private static Bitmap sDateBackgroundAttachment;
private static Bitmap sDateBackgroundNoAttachment;
@@ -366,8 +378,11 @@
// 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);
+ sSendersTextViewHeight = res.getDimensionPixelSize
+ (R.dimen.senders_textview_height);
}
}
@@ -585,11 +600,19 @@
} else {
mHeader.styledSendersString.removeSpan(mActivatedTextSpan);
}
+ mHeader.sendersTextView = getSendersTextView();
+ }
+
+ private TextView getSendersTextView() {
+ TextView sendersTextView = new TextView(mContext);
+ sendersTextView.setMaxLines(1);
+ sendersTextView.setEllipsize(TextUtils.TruncateAt.END);
+ sendersTextView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
int length = (int) sPaint.measureText(mHeader.styledSendersString.toString());
- mHeader.sendersDisplayLayout = new StaticLayout(mHeader.styledSendersString, 0,
- mHeader.styledSendersString.length(), sPaint,
- length,
- Alignment.ALIGN_NORMAL, 1, 0, true, TextUtils.TruncateAt.END, length);
+ sendersTextView.setText(mHeader.styledSendersString, TextView.BufferType.SPANNABLE);
+ sendersTextView.setWidth(length);
+ return sendersTextView;
}
private CharacterStyle getActivatedTextSpan() {
@@ -962,21 +985,24 @@
// Senders.
boolean isUnread = mHeader.unread;
// Old style senders; apply text colors/ sizes/ styling.
- if (mHeader.senderFragments.size() > 0) {
+ canvas.save();
+ if (mHeader.sendersDisplayLayout != null) {
sPaint.setTextSize(mCoordinates.sendersFontSize);
sPaint.setTypeface(SendersView.getTypeface(isUnread));
- int sendersColor = getFontColor(isUnread ? sSendersTextColorUnread
- : sSendersTextColorRead);
- sPaint.setColor(sendersColor);
+ sPaint.setColor(getFontColor(isUnread ? sSendersTextColorUnread
+ : sSendersTextColorRead));
+ canvas.translate(mCoordinates.sendersX,
+ mCoordinates.sendersY + mHeader.sendersDisplayLayout.getTopPadding());
+ mHeader.sendersDisplayLayout.draw(canvas);
} else {
- sPaint.setTextSize(mCoordinates.sendersFontSize);
+ canvas.translate(mCoordinates.sendersX,
+ mCoordinates.sendersY + sSendersTextViewTopPadding);
+ mHeader.sendersTextView.layout(0, 0, mSendersWidth, sSendersTextViewHeight);
+ mHeader.sendersTextView.draw(canvas);
}
- canvas.save();
- canvas.translate(mCoordinates.sendersX,
- mCoordinates.sendersY + mHeader.sendersDisplayLayout.getTopPadding());
- mHeader.sendersDisplayLayout.draw(canvas);
canvas.restore();
+
// Subject.
sPaint.setTextSize(mCoordinates.subjectFontSize);
sPaint.setTypeface(Typeface.DEFAULT);
@@ -1151,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();
}
}
@@ -1222,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);
}
@@ -1277,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();
@@ -1308,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;
}
/**
@@ -1470,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/browse/ConversationItemViewModel.java b/src/com/android/mail/browse/ConversationItemViewModel.java
index 44227e3..22d17a8 100644
--- a/src/com/android/mail/browse/ConversationItemViewModel.java
+++ b/src/com/android/mail/browse/ConversationItemViewModel.java
@@ -33,6 +33,7 @@
import android.text.style.CharacterStyle;
import android.util.LruCache;
import android.util.Pair;
+import android.widget.TextView;
import com.android.mail.R;
import com.android.mail.providers.Conversation;
@@ -130,6 +131,8 @@
private String mContentDescription;
+ public TextView sendersTextView;
+
/**
* Returns the view model for a conversation. If the model doesn't exist for this conversation
* null is returned. Note: this should only be called from the UI thread.
diff --git a/src/com/android/mail/browse/ConversationPagerController.java b/src/com/android/mail/browse/ConversationPagerController.java
index 1c14a02..e68030a 100644
--- a/src/com/android/mail/browse/ConversationPagerController.java
+++ b/src/com/android/mail/browse/ConversationPagerController.java
@@ -186,6 +186,8 @@
* {@link #hide()}.
*/
public void stopListening() {
- mPagerAdapter.setActivityController(null);
+ if (mPagerAdapter != null) {
+ mPagerAdapter.setActivityController(null);
+ }
}
}
diff --git a/src/com/android/mail/browse/SelectedConversationsActionMenu.java b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
index 39654d1..6496f67 100644
--- a/src/com/android/mail/browse/SelectedConversationsActionMenu.java
+++ b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
@@ -116,7 +116,7 @@
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
boolean handled = true;
// If the user taps a new menu item, commit any existing destructive actions.
- mListView.commitDestructiveActions();
+ mListView.commitDestructiveActions(true);
switch (item.getItemId()) {
case R.id.delete:
performDestructiveAction(R.id.delete);
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index e1671c0..30a29b5 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) {
@@ -389,6 +390,11 @@
LogUtils.d(LOG_TAG, "AbstractActivityController.switchAccount(): mAccount = %s",
mAccount.uri);
cancelRefreshTask();
+ // If we are currently listening to changes in conversation, the account switch is going to
+ // make us do a lot of un-necessary work. Let's stop listening to changes.
+ if (mPagerController != null) {
+ mPagerController.stopListening();
+ }
updateSettings();
if (shouldReloadInbox) {
loadAccountInbox();
@@ -417,6 +423,9 @@
}
});
}
+ if (accountChanged) {
+ commitDestructiveActions(false);
+ }
switchAccount(account, accountChanged);
}
}
@@ -467,6 +476,9 @@
@Override
public void onFolderChanged(Folder folder) {
+ if (!Objects.equal(mFolder, folder)) {
+ commitDestructiveActions(false);
+ }
changeFolder(folder, null);
}
@@ -526,6 +538,11 @@
mFolder = folder;
mActionBarView.setFolder(mFolder);
+ // Stop listening to changes to the previous folder.
+ if (mPagerController != null) {
+ mPagerController.stopListening();
+ }
+
// Only when we switch from one folder to another do we want to restart the
// folder and conversation list loaders (to trigger onCreateLoader).
// The first time this runs when the activity is [re-]initialized, we want to re-use the
@@ -690,7 +707,7 @@
final Collection<Conversation> target = Conversation.listOf(mCurrentConversation);
final Settings settings = (mAccount == null) ? null : mAccount.settings;
// The user is choosing a new action; commit whatever they had been doing before.
- commitDestructiveActions();
+ commitDestructiveActions(true);
switch (id) {
case R.id.archive: {
final boolean showDialog = (settings != null && settings.confirmArchive);
@@ -1100,7 +1117,7 @@
// this themselves?
// Commit any destructive undoable actions the user may have performed.
- commitDestructiveActions();
+ commitDestructiveActions(true);
// We don't want to invalidate the options menu when switching to
// conversation
@@ -1114,10 +1131,10 @@
return mDestroyed;
}
- private void commitDestructiveActions() {
- ConversationListFragment fragment = this.getConversationListFragment();
+ private void commitDestructiveActions(boolean animate) {
+ ConversationListFragment fragment = getConversationListFragment();
if (fragment != null) {
- fragment.commitDestructiveActions();
+ fragment.commitDestructiveActions(animate);
}
}
@@ -1917,7 +1934,7 @@
@Override
public final void onRefreshRequired() {
- if (isAnimating()) {
+ if (isAnimating() || isDragging()) {
LogUtils.d(LOG_TAG, "onRefreshRequired: delay until animating done");
return;
}
@@ -1927,6 +1944,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();
@@ -2048,7 +2088,7 @@
*/
protected void disableCabMode() {
// Commit any previous destructive actions when entering/ exiting CAB mode.
- commitDestructiveActions();
+ commitDestructiveActions(true);
if (mCabActionMenu != null) {
mCabActionMenu.deactivate();
}
@@ -2059,7 +2099,7 @@
*/
protected void enableCabMode() {
// Commit any previous destructive actions when entering/ exiting CAB mode.
- commitDestructiveActions();
+ commitDestructiveActions(true);
if (mCabActionMenu != null) {
mCabActionMenu.activate();
}
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/AnimatedAdapter.java b/src/com/android/mail/ui/AnimatedAdapter.java
index 2cdbea6..73dfca8 100644
--- a/src/com/android/mail/ui/AnimatedAdapter.java
+++ b/src/com/android/mail/ui/AnimatedAdapter.java
@@ -356,11 +356,15 @@
return mListView;
}
- public void commitLeaveBehindItems() {
+ public void commitLeaveBehindItems(boolean animate) {
// Remove any previously existing leave behinds.
boolean changed = false;
if (hasLeaveBehinds()) {
- mLeaveBehindItem.dismiss();
+ if (animate) {
+ mLeaveBehindItem.dismiss();
+ } else {
+ mLeaveBehindItem.commit();
+ }
changed = true;
}
if (!mLastDeletingItems.isEmpty()) {
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/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java
index cede3e7..c6d4328 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -639,9 +639,9 @@
}
}
- public void commitDestructiveActions() {
+ public void commitDestructiveActions(boolean animate) {
if (mListView != null) {
- mListView.commitDestructiveActions();
+ mListView.commitDestructiveActions(animate);
}
}
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/MailActionBarView.java b/src/com/android/mail/ui/MailActionBarView.java
index 0ba9bd4..b5f8060 100644
--- a/src/com/android/mail/ui/MailActionBarView.java
+++ b/src/com/android/mail/ui/MailActionBarView.java
@@ -405,6 +405,11 @@
setStandardMode();
mFolderView.setVisibility(View.VISIBLE);
break;
+ case ViewMode.WAITING_FOR_ACCOUNT_INITIALIZATION:
+ // We want the user to be able to switch accounts while waiting for an account
+ // to sync.
+ showNavList();
+ break;
}
return false;
}
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();
+ }
}
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 27b0b5d..75b3575 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -112,6 +112,10 @@
@Override
public void resetActionBarIcon() {
final int mode = mViewMode.getMode();
+ // If the viewmode is not set, preserve existing icon.
+ if (mode == ViewMode.UNKNOWN) {
+ return;
+ }
if (!inInbox(mAccount, mConvListContext)
|| mode == ViewMode.SEARCH_RESULTS_LIST
|| mode == ViewMode.SEARCH_RESULTS_CONVERSATION
@@ -439,10 +443,8 @@
}
if (isTransactionIdValid(mLastConversationListTransactionId)) {
mActivity.getFragmentManager().popBackStack(mLastConversationListTransactionId, 0);
- resetActionBarIcon();
} else if (isTransactionIdValid(mLastInboxConversationListTransactionId)) {
mActivity.getFragmentManager().popBackStack(mLastInboxConversationListTransactionId, 0);
- resetActionBarIcon();
onFolderChanged(mInbox);
} else {
// TODO: revisit if this block is necessary
diff --git a/src/com/android/mail/ui/SwipeableListView.java b/src/com/android/mail/ui/SwipeableListView.java
index a6bf55c..745cd37 100644
--- a/src/com/android/mail/ui/SwipeableListView.java
+++ b/src/com/android/mail/ui/SwipeableListView.java
@@ -162,10 +162,10 @@
// Call this whenever a new action is taken; this forces a commit of any
// existing destructive actions.
- public void commitDestructiveActions() {
+ public void commitDestructiveActions(boolean animate) {
final AnimatedAdapter adapter = getAnimatedAdapter();
if (adapter != null) {
- adapter.commitLeaveBehindItems();
+ adapter.commitLeaveBehindItems(animate);
}
}
@@ -297,7 +297,7 @@
boolean handled = super.performItemClick(view, pos, id);
// Commit any existing destructive actions when the user selects a
// conversation to view.
- commitDestructiveActions();
+ commitDestructiveActions(true);
return handled;
}
@@ -310,7 +310,7 @@
public void onScrollStateChanged(AbsListView view, int state) {
if (state == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL
|| state == OnScrollListener.SCROLL_STATE_FLING) {
- commitDestructiveActions();
+ commitDestructiveActions(true);
}
}
}
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 506b0a0..953c2a5 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -229,6 +229,10 @@
@Override
public void resetActionBarIcon() {
+ // If the viewmode is not set, preserve existing icon.
+ if (mViewMode.getMode() == ViewMode.UNKNOWN) {
+ return;
+ }
if (mViewMode.isListMode()) {
mActionBarView.removeBackButton();
} else {
diff --git a/src/com/android/mail/utils/AttachmentUtils.java b/src/com/android/mail/utils/AttachmentUtils.java
index ff9339b..2ab5767 100644
--- a/src/com/android/mail/utils/AttachmentUtils.java
+++ b/src/com/android/mail/utils/AttachmentUtils.java
@@ -41,7 +41,9 @@
* depending on its size.
*/
public static String convertToHumanReadableSize(Context context, long size) {
- if (size < KILO) {
+ if (size == 0) {
+ return "";
+ } if (size < KILO) {
return size + context.getString(R.string.bytes);
} else if (size < MEGA) {
return (size / KILO) + context.getString(R.string.kilobytes);