Merge "Remove hack to enable INFO logs"
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index c2fd3ec..a66b5c8 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -50,8 +50,10 @@
 import android.text.util.Rfc822Token;
 import android.text.util.Rfc822Tokenizer;
 import android.util.SparseArray;
+import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.View.MeasureSpec;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.Checkable;
@@ -153,6 +155,9 @@
     private Folder mDisplayedFolder;
     private boolean mPriorityMarkersEnabled;
     private int mAnimatedHeight = -1;
+    private boolean mCheckboxesEnabled;
+    private CheckForTap mPendingCheckForTap;
+    private CheckForLongPress mPendingCheckForLongPress;
     private static Bitmap MORE_FOLDERS;
 
     static {
@@ -356,11 +361,24 @@
     }
 
     public void bind(Cursor cursor, ViewMode viewMode, ConversationSelectionSet set,
-            Folder folder) {
+            Folder folder, boolean checkboxesEnabled) {
         mViewMode = viewMode;
         mHeader = ConversationItemViewModel.forCursor(cursor);
         mSelectedConversationSet = set;
         mDisplayedFolder = folder;
+        mCheckboxesEnabled = checkboxesEnabled;
+        setContentDescription(mHeader.getContentDescription(mContext));
+        requestLayout();
+    }
+
+
+    public void bind(Conversation conversation, ViewMode viewMode, ConversationSelectionSet set,
+            Folder folder, boolean checkboxesEnabled) {
+        mViewMode = viewMode;
+        mHeader = ConversationItemViewModel.forConversation(conversation);
+        mSelectedConversationSet = set;
+        mDisplayedFolder = folder;
+        mCheckboxesEnabled = checkboxesEnabled;
         setContentDescription(mHeader.getContentDescription(mContext));
         requestLayout();
     }
@@ -456,7 +474,7 @@
 
         boolean isUnread = mHeader.unread;
 
-        final boolean checkboxEnabled = true;
+        final boolean checkboxEnabled = mCheckboxesEnabled;
         if (mHeader.checkboxVisible != checkboxEnabled) {
             mHeader.checkboxVisible = checkboxEnabled;
         }
@@ -990,19 +1008,22 @@
      * Toggle the check mark on this view and update the conversation
      */
     public void toggleCheckMark() {
-        mChecked = !mChecked;
-        Conversation conv = mHeader.conversation;
-        // Set the list position of this item in the conversation
-        conv.position = mChecked ? ((ListView)getParent()).getPositionForView(this)
-                : Conversation.NO_POSITION;
-        if (mSelectedConversationSet != null) {
-            mSelectedConversationSet.toggle(this, conv);
+        if (mHeader != null && mHeader.conversation != null) {
+            mChecked = !mChecked;
+            Conversation conv = mHeader.conversation;
+            // Set the list position of this item in the conversation
+            ListView listView = (ListView)getParent();
+            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();
     }
 
     /**
@@ -1036,6 +1057,14 @@
     }
 
     /**
+     * Cancel any potential tap handling on this view.
+     */
+    public void cancelTap() {
+        removeCallbacks(mPendingCheckForTap);
+        removeCallbacks(mPendingCheckForLongPress);
+    }
+
+    /**
      * ConversationItemView is given the first chance to handle touch events.
      */
     @Override
@@ -1051,11 +1080,17 @@
                 // to bubble to the swipe handler, we need to return that all
                 // down events are handled.
                 handled = true;
+                // TODO (mindyp) Debounce
+                if (mPendingCheckForTap == null) {
+                    mPendingCheckForTap = new CheckForTap();
+                }
+                postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                 break;
             case MotionEvent.ACTION_CANCEL:
                 mDownEvent = false;
                 break;
             case MotionEvent.ACTION_UP:
+                cancelTap();
                 if (mDownEvent) {
                     // ConversationItemView gets the first chance to handle up
                     // events if there was a down event and there was no move
@@ -1066,13 +1101,17 @@
                     if (isTouchInCheckmark(x, y)) {
                         // Touch on the check mark
                         toggleCheckMark();
+                        handled = true;
                     } else if (isTouchInStar(x, y)) {
                         // Touch on the star
                         toggleStar();
+                        handled = true;
                     } else {
-                        ListView list = (ListView)getParent();
-                        int pos = list.getPositionForView(this);
-                        list.performItemClick(this, pos, mHeader.conversation.id);
+                        ListView list = (ListView) getParent();
+                        if (!isChecked()) {
+                            int pos = list.getPositionForView(this);
+                            list.performItemClick(this, pos, mHeader.conversation.id);
+                        }
                     }
                     handled = true;
                 } else {
@@ -1092,6 +1131,36 @@
     }
 
     /**
+     * Return if this item should respond to long clicks.
+     */
+    @Override
+    public boolean isLongClickable() {
+        return true;
+    }
+
+    final class CheckForTap implements Runnable {
+        public void run() {
+            // refreshDrawableState();
+            final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
+            final boolean longClickable = isLongClickable();
+
+            if (longClickable) {
+                if (mPendingCheckForLongPress == null) {
+                    mPendingCheckForLongPress = new CheckForLongPress();
+                }
+                postDelayed(mPendingCheckForLongPress, longPressTimeout);
+            }
+        }
+    }
+
+    private class CheckForLongPress implements Runnable {
+        public void run() {
+            ConversationItemView.this.toggleCheckMark();
+            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+        }
+    }
+
+    /**
      * Grow the height of the item and fade it in when bringing a conversation
      * back from a destructive action.
      *
@@ -1134,4 +1203,4 @@
         return mHeader != null && mHeader.conversation != null ?
                 mHeader.conversation.position : -1;
     }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/mail/browse/ConversationItemViewModel.java b/src/com/android/mail/browse/ConversationItemViewModel.java
index b80490d..aef180d 100644
--- a/src/com/android/mail/browse/ConversationItemViewModel.java
+++ b/src/com/android/mail/browse/ConversationItemViewModel.java
@@ -131,11 +131,15 @@
     }
 
     static ConversationItemViewModel forCursor(Cursor cursor) {
+        return forConversation(new Conversation(cursor));
+    }
+
+
+    static ConversationItemViewModel forConversation(Conversation conv) {
         ConversationItemViewModel header = new ConversationItemViewModel();
-        if (cursor != null) {
+        if (conv != null) {
             header.faded = false;
             header.checkboxVisible = true;
-            Conversation conv = new Conversation(cursor);
             header.conversation = conv;
             header.starred = conv.starred;
             header.unread = !conv.read;
@@ -289,4 +293,4 @@
         return context.getString(R.string.content_description, conversation.subject,
                 conversation.snippet);
     }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java
index eb3f42a..6744fb8 100644
--- a/src/com/android/mail/compose/ComposeActivity.java
+++ b/src/com/android/mail/compose/ComposeActivity.java
@@ -1550,10 +1550,15 @@
                 break;
         }
         MessageModification.putDraftType(values, draftType);
-        if (refMessage != null && !TextUtils.isEmpty(refMessage.bodyHtml)) {
+        if (refMessage != null) {
+            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
+                MessageModification.putBodyHtml(values, fullBody.toString());
+            }
+            if (!TextUtils.isEmpty(refMessage.bodyText)) {
+                MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString());
+            }
+        } else {
             MessageModification.putBodyHtml(values, fullBody.toString());
-        }
-        if (refMessage != null && !TextUtils.isEmpty(refMessage.bodyText)) {
             MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString());
         }
         MessageModification.putAttachments(values, attachments);
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index fb45614..bb907c8 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -834,6 +834,7 @@
                 mAccount = ((Account) intent.getParcelableExtra(Utils.EXTRA_ACCOUNT));
                 mActionBarView.setAccount(mAccount);
                 fetchSearchFolder(intent);
+                restartOptionalLoader(LOADER_ACCOUNT_SETTINGS, null /* args */);
             }
         }
 
diff --git a/src/com/android/mail/ui/AnimatedAdapter.java b/src/com/android/mail/ui/AnimatedAdapter.java
index 0e0ea2e..bce9620 100644
--- a/src/com/android/mail/ui/AnimatedAdapter.java
+++ b/src/com/android/mail/ui/AnimatedAdapter.java
@@ -33,6 +33,7 @@
 import com.android.mail.providers.Account;
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.Folder;
+import com.android.mail.providers.Settings;
 import com.android.mail.providers.UIProvider;
 import com.android.mail.ui.UndoBarView.OnUndoCancelListener;
 import com.android.mail.utils.LogUtils;
@@ -56,13 +57,15 @@
     private boolean mShowFooter;
     private Folder mFolder;
     private final ListView mListView;
+    private Settings mCachedSettings;
     /**
      * Used only for debugging.
      */
     private static final String LOG_TAG = new LogUtils().getLogTag();
 
     public AnimatedAdapter(Context context, int textViewResourceId, ConversationCursor cursor,
-            ConversationSelectionSet batch, Account account, ViewMode viewMode, ListView listView) {
+            ConversationSelectionSet batch, Account account, Settings settings, ViewMode viewMode,
+            ListView listView) {
         // Use FLAG_REGISTER_CONTENT_OBSERVER to ensure special ConversationCursor notifications
         // (triggered by UI actions) cause any connected ListView to redraw.
         super(context, textViewResourceId, cursor, UIProvider.CONVERSATION_PROJECTION, null,
@@ -73,6 +76,7 @@
         mViewMode = viewMode;
         mShowFooter = false;
         mListView = listView;
+        mCachedSettings = settings;
     }
 
     @Override
@@ -106,8 +110,8 @@
     @Override
     public void bindView(View view, Context context, Cursor cursor) {
         if (!isPositionAnimating(view) && !isPositionFooter(view)) {
-            ((ConversationItemView) view).bind(cursor, mViewMode,
-                    mBatchConversations, mFolder);
+            ((ConversationItemView) view).bind(cursor, mViewMode, mBatchConversations, mFolder,
+                    mCachedSettings != null ? !mCachedSettings.hideCheckboxes : false);
         }
     }
 
@@ -236,7 +240,9 @@
             // The undo animation consists of fading in the conversation that
             // had been destroyed.
             ConversationItemView convView = (ConversationItemView) super.getView(position, null,
-                    parent);
+                    mListView);
+            convView.bind(conversation, mViewMode, mBatchConversations, mFolder,
+                    mCachedSettings != null ? !mCachedSettings.hideCheckboxes : false);
             convView.startUndoAnimation(mViewMode, this);
             return convView;
         } else {
@@ -346,4 +352,4 @@
     public void setFolder(Folder folder) {
         mFolder = folder;
     }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/mail/ui/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java
index a689c54..c892576 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -213,7 +213,7 @@
 
         mListAdapter = new AnimatedAdapter(mActivity.getApplicationContext(), -1,
                 getConversationListCursor(), mActivity.getSelectedSet(), mAccount,
-                mActivity.getViewMode(), mListView);
+                mActivity.getSettings(), mActivity.getViewMode(), mListView);
         mFooterView = (ConversationListFooterView) LayoutInflater.from(
                 mActivity.getActivityContext()).inflate(R.layout.conversation_list_footer_view,
                 null);
diff --git a/src/com/android/mail/ui/SwipeHelper.java b/src/com/android/mail/ui/SwipeHelper.java
index b660804..96715ad 100644
--- a/src/com/android/mail/ui/SwipeHelper.java
+++ b/src/com/android/mail/ui/SwipeHelper.java
@@ -205,6 +205,7 @@
                         float currY = ev.getY();
                         if (Math.abs(currY - mLastY) > mScrollSlop) {
                             mLastY = ev.getY();
+                            mCurrView.cancelTap();
                             return false;
                         }
                     }
@@ -350,6 +351,11 @@
         if (!mDragging) {
             return false;
         }
+        // If this item is being dragged, cancel any tap handlers/ events/
+        // actions for this item.
+        if (mCurrView != null) {
+            mCurrView.cancelTap();
+        }
         mVelocityTracker.addMovement(ev);
         final int action = ev.getAction();
         switch (action) {
@@ -448,4 +454,4 @@
 
         ConversationSelectionSet getSelectionSet();
     }
-}
+}
\ No newline at end of file