Merge "Import translations. DO NOT MERGE" into ub-gmail-ur12-dev
diff --git a/src/com/android/mail/browse/ConversationCursor.java b/src/com/android/mail/browse/ConversationCursor.java
index 52b10d9..a5dbb5d 100644
--- a/src/com/android/mail/browse/ConversationCursor.java
+++ b/src/com/android/mail/browse/ConversationCursor.java
@@ -688,9 +688,11 @@
                             // cache entry
                             mDeletedCount--;
                             removed = true;
-                            LogUtils.d(LOG_TAG,
+                            LogUtils.i(LOG_TAG,
                                     "IN resetCursor, sDeletedCount decremented to: %d by %s",
-                                    mDeletedCount, key);
+                                    mDeletedCount,
+                                    (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) ? key
+                                            : "[redacted]");
                         }
                     }
                 } else {
@@ -2339,6 +2341,10 @@
         sb.append(mDeletedCount);
         sb.append(" mUnderlying=");
         sb.append(mUnderlyingCursor);
+        if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
+            sb.append(" mCacheMap=");
+            sb.append(mCacheMap);
+        }
         sb.append("}");
         return sb.toString();
     }
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 19a0314..0393436 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -3039,7 +3039,10 @@
     @Override
     public final void onRefreshRequired() {
         if (isAnimating() || isDragging()) {
-            LogUtils.i(ConversationCursor.LOG_TAG, "onRefreshRequired: delay until animating done");
+            final ConversationListFragment f = getConversationListFragment();
+            LogUtils.w(ConversationCursor.LOG_TAG,
+                    "onRefreshRequired: delay until animating done. cursor=%s adapter=%s",
+                    mConversationListCursor, (f != null) ? f.getAnimatedAdapter() : null);
             return;
         }
         // Refresh the query in the background
@@ -3099,6 +3102,11 @@
         if (!isAnimating()) {
             // Swap cursors
             mConversationListCursor.sync();
+        } else {
+            // (CLF guaranteed to be non-null due to check in isAnimating)
+            LogUtils.w(LOG_TAG,
+                    "AAC.onRefreshReady suppressing sync() due to animation. cursor=%s aa=%s",
+                    mConversationListCursor, getConversationListFragment().getAnimatedAdapter());
         }
         mTracker.onCursorUpdated();
         perhapsShowFirstSearchResult();
@@ -3159,6 +3167,10 @@
 
     @Override
     public void onAnimationEnd(AnimatedAdapter animatedAdapter) {
+        if (animatedAdapter != null) {
+            LogUtils.i(LOG_TAG, "AAC.onAnimationEnd. cursor=%s adapter=%s", mConversationListCursor,
+                    animatedAdapter);
+        }
         if (mConversationListCursor == null) {
             LogUtils.e(LOG_TAG, "null ConversationCursor in onAnimationEnd");
             return;
@@ -3461,7 +3473,8 @@
                 return null;
             }
             return new ConversationCursorLoader(mActivity, account,
-                    folder.conversationListUri, folder.name, ignoreInitialConversationLimit);
+                    folder.conversationListUri, folder.getTypeDescription(),
+                    ignoreInitialConversationLimit);
         }
 
         @Override
diff --git a/src/com/android/mail/ui/AnimatedAdapter.java b/src/com/android/mail/ui/AnimatedAdapter.java
index 2bbc6ce..811e636 100644
--- a/src/com/android/mail/ui/AnimatedAdapter.java
+++ b/src/com/android/mail/ui/AnimatedAdapter.java
@@ -973,6 +973,25 @@
                 || !mSwipeDeletingItems.isEmpty();
     }
 
+    /**
+     * Forcibly clear any internal state that would cause {@link #isAnimating()} to return true.
+     * Call this in times of desperation, when you really, really want to trash state and just
+     * start over.
+     */
+    public void clearAnimationState() {
+        if (!isAnimating()) {
+            return;
+        }
+
+        mUndoingItems.clear();
+        mSwipeUndoingItems.clear();
+        mFadeLeaveBehindItems.clear();
+        mDeletingItems.clear();
+        mSwipeDeletingItems.clear();
+        mAnimatingViews.clear();
+        LogUtils.w(LOG_TAG, "AA.clearAnimationState forcibly cleared state, this=%s", this);
+    }
+
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder("{");
@@ -991,6 +1010,10 @@
         sb.append(mFadeLeaveBehindItems);
         sb.append(" mLastDeletingItems=");
         sb.append(mLastDeletingItems);
+        sb.append(" mAnimatingViews=");
+        sb.append(mAnimatingViews);
+        sb.append(" mPendingDestruction=");
+        sb.append(mPendingDestruction);
         sb.append("}");
         return sb.toString();
     }
diff --git a/src/com/android/mail/ui/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java
index 6f057aa..8766c56 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -722,8 +722,14 @@
 
     public boolean isAnimating() {
         final AnimatedAdapter adapter = getAnimatedAdapter();
-        return (adapter != null && adapter.isAnimating()) ||
-                (mListView != null && mListView.isScrolling());
+        if (adapter != null && adapter.isAnimating()) {
+            return true;
+        }
+        final boolean isScrolling = (mListView != null && mListView.isScrolling());
+        if (isScrolling) {
+            LogUtils.i(LOG_TAG, "CLF.isAnimating=true due to scrolling");
+        }
+        return isScrolling;
     }
 
     private void clearChoicesAndActivated() {
@@ -1140,6 +1146,14 @@
 
         // This will call back to showSyncStatusBar():
         mActivity.getFolderController().requestFolderRefresh();
+
+        // Clear list adapter state out of an abundance of caution.
+        // There is a class of bugs where an animation that should have finished doesn't (maybe
+        // it didn't start, or it didn't finish), and the list gets stuck pretty much forever.
+        // Clearing the state here is in line with user expectation for 'refresh'.
+        getAnimatedAdapter().clearAnimationState();
+        // possibly act on the now-cleared state
+        mActivity.onAnimationEnd(mListAdapter);
     }
 
     /**