am 8a819016: am bd16ec75: Merge "Programmatically set selected state to correspond to peeking conv" into ub-gmail-ur14-dev

* commit '8a8190167285f35ae1c68d3b1471e9a2a964b29e':
  Programmatically set selected state to correspond to peeking conv
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 5f1dbd2..65cf5ce 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -58,6 +58,7 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.animation.DecelerateInterpolator;
+import android.widget.ListView;
 import android.widget.TextView;
 
 import com.android.mail.R;
@@ -126,7 +127,7 @@
     private static Bitmap STATE_FORWARDED;
     private static Bitmap STATE_REPLIED_AND_FORWARDED;
     private static Bitmap STATE_CALENDAR_INVITE;
-    private static Drawable VISIBLE_CONVERSATION_HIGHLIGHT;
+    private static Drawable FOCUSED_CONVERSATION_HIGHLIGHT;
 
     private static String sSendersSplitToken;
     private static String sElidedPaddingToken;
@@ -196,6 +197,7 @@
     private final TextView mSubjectTextView;
     private final TextView mSnippetTextView;
     private int mGadgetMode;
+    private int mAdapterPosition = ListView.INVALID_POSITION;
 
     private static int sFoldersMaxCount;
     private static TextAppearanceSpan sSubjectTextUnreadSpan;
@@ -431,7 +433,7 @@
                     BitmapFactory.decodeResource(res, R.drawable.ic_badge_reply_forward_holo_light);
             STATE_CALENDAR_INVITE =
                     BitmapFactory.decodeResource(res, R.drawable.ic_badge_invite_holo_light);
-            VISIBLE_CONVERSATION_HIGHLIGHT = res.getDrawable(
+            FOCUSED_CONVERSATION_HIGHLIGHT = res.getDrawable(
                     R.drawable.visible_conversation_highlight);
 
             // Initialize colors.
@@ -470,8 +472,9 @@
             final ConversationCheckedSet set, final Folder folder,
             final int checkboxOrSenderImage,
             final boolean swipeEnabled, final boolean importanceMarkersEnabled,
-            final boolean showChevronsEnabled, final AnimatedAdapter adapter) {
+            final boolean showChevronsEnabled, final AnimatedAdapter adapter, int position) {
         Utils.traceBeginSection("CIVC.bind");
+        mAdapterPosition = position;
         bind(ConversationItemViewModel.forConversation(mAccount.getEmailAddress(), conversation),
                 activity, null /* conversationItemAreaClickListener */,
                 set, folder, checkboxOrSenderImage, swipeEnabled, importanceMarkersEnabled,
@@ -1273,19 +1276,49 @@
         }
 
         // The focused bar
-        if (isSelected() || isActivated()) {
-            final int w = VISIBLE_CONVERSATION_HIGHLIGHT.getIntrinsicWidth();
+        final SwipeableListView listView = getListView();
+        if (listView != null && listView.isPositionSelected(getViewPosition())) {
+            final int w = FOCUSED_CONVERSATION_HIGHLIGHT.getIntrinsicWidth();
             final boolean isRtl = ViewUtils.isViewRtl(this);
             // This bar is on the right side of the conv list if it's RTL
-            VISIBLE_CONVERSATION_HIGHLIGHT.setBounds(
+            FOCUSED_CONVERSATION_HIGHLIGHT.setBounds(
                     (isRtl) ? getWidth() - w : 0, 0,
                     (isRtl) ? getWidth() : w, getHeight());
-            VISIBLE_CONVERSATION_HIGHLIGHT.draw(canvas);
+            FOCUSED_CONVERSATION_HIGHLIGHT.draw(canvas);
         }
 
         Utils.traceEndSection();
     }
 
+    @Override
+    public void setSelected(boolean selected) {
+        // We catch the selected event here instead of using ListView#setOnItemSelectedListener
+        // because when the framework changes selection due to keyboard events, it sets the selected
+        // state, re-draw the affected views, and then call onItemSelected. That approach won't work
+        // because the view won't know about the new selected position during the re-draw.
+        if (selected) {
+            final SwipeableListView listView = getListView();
+            if (listView != null) {
+                listView.setSelectedPosition(getViewPosition());
+            }
+        }
+        super.setSelected(selected);
+    }
+
+    private int getViewPosition() {
+        if (mAdapterPosition != ListView.INVALID_POSITION) {
+            return mAdapterPosition;
+        } else {
+            final ListView listView = getListView();
+            final int position = listView != null ?
+                    listView.getPositionForView(this) : ListView.INVALID_POSITION;
+            LogUtils.e(LOG_TAG,
+                    "ConversationItemView didn't set position, using listview's position: %d",
+                    position);
+            return position;
+        }
+    }
+
     private void drawSendersImage(final Canvas canvas) {
         if (!mSendersImageView.isFlipping()) {
             final boolean showSenders = !mChecked;
@@ -1372,8 +1405,7 @@
             final SwipeableListView listView = getListView();
 
             try {
-                conv.position = mChecked && listView != null ? listView.getPositionForView(this)
-                        : Conversation.NO_POSITION;
+                conv.position = mChecked ? getViewPosition() : Conversation.NO_POSITION;
             } catch (final NullPointerException e) {
                 // TODO(skennedy) Remove this if we find the root cause b/9527863
             }
diff --git a/src/com/android/mail/browse/SwipeableConversationItemView.java b/src/com/android/mail/browse/SwipeableConversationItemView.java
index 10657f4..9db9669 100644
--- a/src/com/android/mail/browse/SwipeableConversationItemView.java
+++ b/src/com/android/mail/browse/SwipeableConversationItemView.java
@@ -56,9 +56,10 @@
             final ConversationCheckedSet set, final Folder folder,
             final int checkboxOrSenderImage, boolean swipeEnabled,
             final boolean importanceMarkersEnabled, final boolean showChevronsEnabled,
-            final AnimatedAdapter animatedAdapter) {
+            final AnimatedAdapter animatedAdapter, final int position) {
         mConversationItemView.bind(conversation, activity, set, folder, checkboxOrSenderImage,
-                swipeEnabled, importanceMarkersEnabled, showChevronsEnabled, animatedAdapter);
+                swipeEnabled, importanceMarkersEnabled, showChevronsEnabled, animatedAdapter,
+                position);
     }
 
     public void startUndoAnimation(AnimatorListener listener, boolean swipe) {
diff --git a/src/com/android/mail/ui/AnimatedAdapter.java b/src/com/android/mail/ui/AnimatedAdapter.java
index 2b38d27..86a3658 100644
--- a/src/com/android/mail/ui/AnimatedAdapter.java
+++ b/src/com/android/mail/ui/AnimatedAdapter.java
@@ -380,12 +380,12 @@
     }
 
     public View createConversationItemView(SwipeableConversationItemView view, Context context,
-            Conversation conv) {
+            Conversation conv, int position) {
         if (view == null) {
             view = new SwipeableConversationItemView(context, mAccount);
         }
         view.bind(conv, mActivity, mBatchConversations, mFolder, getCheckboxSetting(),
-                mSwipeEnabled, mImportanceMarkersEnabled, mShowChevronsEnabled, this);
+                mSwipeEnabled, mImportanceMarkersEnabled, mShowChevronsEnabled, this, position);
         return view;
     }
 
@@ -556,7 +556,7 @@
             ((SwipeableConversationItemView) convertView).reset();
         }
         final View v = createConversationItemView((SwipeableConversationItemView) convertView,
-                mContext, conv);
+                mContext, conv, position);
         Utils.traceEndSection();
         return v;
     }
@@ -790,7 +790,7 @@
                 position, null, parent);
         view.reset();
         view.bind(conversation, mActivity, mBatchConversations, mFolder, getCheckboxSetting(),
-                mSwipeEnabled, mImportanceMarkersEnabled, mShowChevronsEnabled, this);
+                mSwipeEnabled, mImportanceMarkersEnabled, mShowChevronsEnabled, this, position);
         mAnimatingViews.put(conversation.id, view);
         return view;
     }
diff --git a/src/com/android/mail/ui/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java
index c72d225..d80cdf9 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -491,6 +491,14 @@
         sb.append(mListAdapter);
         sb.append(" folder=");
         sb.append(mViewContext.folder);
+        if (mListView != null) {
+            sb.append(" selectedPos=");
+            sb.append(mListView.getSelectedPosition());
+            sb.append(" listSelectedPos=");
+            sb.append(mListView.getSelectedItemPosition());
+            sb.append(" isListInTouchMode=");
+            sb.append(mListView.isInTouchMode());
+        }
         sb.append("}");
         return sb.toString();
     }
@@ -874,6 +882,45 @@
 
         final int position = cursorPosition + mListAdapter.getPositionOffset(cursorPosition);
         setRawActivated(position, different);
+        setRawSelected(position);
+    }
+
+    /**
+     * Set the selected conversation (used by the framework to indicate current focus in the list).
+     * @param cursorPosition The position of the conversation in the cursor (as opposed to
+     * in the list)
+     */
+    public void setSelected(final int cursorPosition) {
+        if (mListView.getChoiceMode() == ListView.CHOICE_MODE_NONE) {
+            return;
+        }
+
+        final int position = cursorPosition + mListAdapter.getPositionOffset(cursorPosition);
+        setRawSelected(position);
+    }
+
+    /**
+     * Set the selected conversation (used by the framework to indicate current focus in the list).
+     * @param position The position of the item in the list
+     */
+    private void setRawSelected(final int position) {
+        final View selectedView = mListView.getChildAt(
+                position - mListView.getFirstVisiblePosition());
+        // Don't do anything if the view is already selected.
+        if (!(selectedView != null && selectedView.isSelected())) {
+            final int firstVisible = mListView.getFirstVisiblePosition();
+            final int lastVisible = mListView.getLastVisiblePosition();
+            // Check if the view is off the screen
+            if (selectedView == null || position < firstVisible || position > lastVisible) {
+                mListView.setSelection(position);
+            } else {
+                // If the view is on screen, we call setSelectionFromTop with a top offset. This
+                // prevents the list from stupidly scrolling the item to the top because
+                // setSelection calls setSelectionFromTop with y = 0.
+                mListView.setSelectionFromTop(position, selectedView.getTop());
+            }
+            mListView.setSelectedPosition(position);
+        }
     }
 
     /**
diff --git a/src/com/android/mail/ui/SwipeableListView.java b/src/com/android/mail/ui/SwipeableListView.java
index fb5198b..b8406b3 100644
--- a/src/com/android/mail/ui/SwipeableListView.java
+++ b/src/com/android/mail/ui/SwipeableListView.java
@@ -72,6 +72,8 @@
 
     private SwipeListener mSwipeListener;
 
+    private int mSelectedPosition = ListView.INVALID_POSITION;
+
     // Instantiated through view inflation
     @SuppressWarnings("unused")
     public SwipeableListView(Context context) {
@@ -406,6 +408,25 @@
         return mScrolling;
     }
 
+    /**
+     * Set the currently selected (focused by the list view) position.
+     */
+    public void setSelectedPosition(int position) {
+        if (position == ListView.INVALID_POSITION) {
+            return;
+        }
+
+        mSelectedPosition = position;
+    }
+
+    public boolean isPositionSelected(int position) {
+        return mSelectedPosition != ListView.INVALID_POSITION && mSelectedPosition == position;
+    }
+
+    public int getSelectedPosition() {
+        return mSelectedPosition;
+    }
+
     @Override
     public void cancelDismissCounter() {
         AnimatedAdapter adapter = getAnimatedAdapter();
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index abcb9a5..2af141a 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -650,10 +650,10 @@
         super.setCurrentConversation(conversation);
 
         final ConversationListFragment convList = getConversationListFragment();
-        if (convList != null && conversation != null) {
+        if (different && convList != null && conversation != null) {
             if (mCurrentConversationJustPeeking) {
                 convList.clearChoicesAndActivated();
-                // TODO: set the list highlight to this new item
+                convList.setSelected(conversation.position);
             } else {
                 convList.setActivated(conversation.position, different);
             }