summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJin Cao <jinyan@google.com>2014-10-16 14:11:40 -0700
committerJin Cao <jinyan@google.com>2014-10-16 20:07:31 -0700
commit0532b0edb999c6e131bfd1f2e1eccefed049ba49 (patch)
tree6653e7f415f05fed2256f37fe924407768e60718 /src
parentf91f88efa3854159f4814af1042a30d4ffbe7027 (diff)
downloadandroid_packages_apps_UnifiedEmail-0532b0edb999c6e131bfd1f2e1eccefed049ba49.tar.gz
android_packages_apps_UnifiedEmail-0532b0edb999c6e131bfd1f2e1eccefed049ba49.tar.bz2
android_packages_apps_UnifiedEmail-0532b0edb999c6e131bfd1f2e1eccefed049ba49.zip
Programmatically set selected state to correspond to peeking conv
I can't simply rely on ListView#setSelection to programmatically set the selected item because setSelection only caches the selection internally if the view is currently in touch mode. Thus, in touch modes, isSelected() will *always* return false for an item in listview. In order to know what's the current selected item, I keep track of the selected position that corresponds EXACTLY to the listview's selected position. Again, I can't use ListView#getSelectedItemPosition because it will always return INVALID_POSITION in touch mode. I change the selected position whenever a child calls setSelected() or we programmatically call setSelected. I tried using onItemSelectedListener. However, the listener's callback is called after the selected state is changed AND the re-draw happened, so the UI gets inconsistent since the selected state didn't properly update during the re-draw. When we programmatically select an item that's visible on the screen, we have to use ListView#setSelectionFromTop and pass in the current y value since the default behavior is to scroll such that the selected item is at the very top. Also, another caveat is that I am now saving the ConversationItemView's position in the adapter when the adapter binds data to it. I find that this approach is much more dependable than using ListView#getPositionForView because sometimes (for reasons beyond me) in ConversationItemView#setSelected the listview ONLY HAS ONE CHILD (even though on the device I can see a full list), thus getPositionForView will return index 0 since it thinks it's the only child.. I have no clue, so I'm saving the position myself instead. b/18015875 Change-Id: I11897056fc9fa630eb4019532b1fd4cf41c7486a
Diffstat (limited to 'src')
-rw-r--r--src/com/android/mail/browse/ConversationItemView.java50
-rw-r--r--src/com/android/mail/browse/SwipeableConversationItemView.java5
-rw-r--r--src/com/android/mail/ui/AnimatedAdapter.java8
-rw-r--r--src/com/android/mail/ui/ConversationListFragment.java47
-rw-r--r--src/com/android/mail/ui/SwipeableListView.java21
-rw-r--r--src/com/android/mail/ui/TwoPaneController.java4
6 files changed, 118 insertions, 17 deletions
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 5f1dbd29b..65cf5ce33 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -58,6 +58,7 @@ import android.view.View;
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 @@ public class ConversationItemView extends View
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 @@ public class ConversationItemView extends View
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 @@ public class ConversationItemView extends View
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 @@ public class ConversationItemView extends View
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 @@ public class ConversationItemView extends View
}
// 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 @@ public class ConversationItemView extends View
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 10657f4f1..9db966906 100644
--- a/src/com/android/mail/browse/SwipeableConversationItemView.java
+++ b/src/com/android/mail/browse/SwipeableConversationItemView.java
@@ -56,9 +56,10 @@ public class SwipeableConversationItemView extends FrameLayout implements Toggle
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 83dd9f317..c44d5bb32 100644
--- a/src/com/android/mail/ui/AnimatedAdapter.java
+++ b/src/com/android/mail/ui/AnimatedAdapter.java
@@ -374,12 +374,12 @@ public class AnimatedAdapter extends SimpleCursorAdapter {
}
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;
}
@@ -550,7 +550,7 @@ public class AnimatedAdapter extends SimpleCursorAdapter {
((SwipeableConversationItemView) convertView).reset();
}
final View v = createConversationItemView((SwipeableConversationItemView) convertView,
- mContext, conv);
+ mContext, conv, position);
Utils.traceEndSection();
return v;
}
@@ -784,7 +784,7 @@ public class AnimatedAdapter extends SimpleCursorAdapter {
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 c72d225f0..d80cdf9ad 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -491,6 +491,14 @@ public final class ConversationListFragment extends Fragment implements
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 @@ public final class ConversationListFragment extends Fragment implements
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 fb5198ba1..b8406b3d8 100644
--- a/src/com/android/mail/ui/SwipeableListView.java
+++ b/src/com/android/mail/ui/SwipeableListView.java
@@ -72,6 +72,8 @@ public class SwipeableListView extends ListView implements Callback, OnScrollLis
private SwipeListener mSwipeListener;
+ private int mSelectedPosition = ListView.INVALID_POSITION;
+
// Instantiated through view inflation
@SuppressWarnings("unused")
public SwipeableListView(Context context) {
@@ -406,6 +408,25 @@ public class SwipeableListView extends ListView implements Callback, OnScrollLis
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 cce227a28..75d1290bd 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -650,10 +650,10 @@ public final class TwoPaneController extends AbstractActivityController implemen
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);
}