From 5b317924c7c764954870501d99bfc57a243f6319 Mon Sep 17 00:00:00 2001 From: Jin Cao Date: Tue, 5 Aug 2014 17:28:28 -0700 Subject: [KBNav TL] Basic navigation in TL Support basic keyboard navigation in TL. CV is not implemented so interaction between TL and CV once you open a conversation is not guaranteed. On TL, left arrow goes to minidrawer/drawer, right arrow goes to CV if open, up/down works as expected, TAB goes to ComposeBtn. On drawer, up/down as expected, right goes to TL, TAB goes to ComposeBtn. On ComposeBtn, left/up/TAB goes back to TL, right/down does nothing. Currently no way of accessing the action bar menu because I don't know what id to set to focus. b/16636060 Change-Id: Ia9bae322e41a53beed20702fba301fbfd9100aa3 Conflicts: src/com/android/mail/ui/ConversationListFragment.java --- .../android/mail/ui/ConversationListFragment.java | 43 +++++++++++++++++----- src/com/android/mail/ui/FolderListFragment.java | 1 + src/com/android/mail/ui/TwoPaneController.java | 17 ++++++++- 3 files changed, 50 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/com/android/mail/ui/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java index 84d46c3b9..9192de24d 100644 --- a/src/com/android/mail/ui/ConversationListFragment.java +++ b/src/com/android/mail/ui/ConversationListFragment.java @@ -19,14 +19,14 @@ package com.android.mail.ui; import android.animation.LayoutTransition; import android.app.Activity; -import android.app.ListFragment; +import android.app.Fragment; import android.app.LoaderManager; -import android.content.Context; import android.content.res.Resources; import android.database.DataSetObserver; import android.os.Bundle; import android.os.Handler; import android.os.Parcelable; +import android.support.annotation.IdRes; import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -74,9 +74,9 @@ import static android.view.View.OnKeyListener; /** * The conversation list UI component. */ -public final class ConversationListFragment extends ListFragment implements +public final class ConversationListFragment extends Fragment implements OnItemLongClickListener, ModeChangeListener, ListItemSwipedListener, OnRefreshListener, - SwipeListener, OnKeyListener { + SwipeListener, OnKeyListener, AdapterView.OnItemClickListener { /** Key used to pass data to {@link ConversationListFragment}. */ private static final String CONVERSATION_LIST_KEY = "conversation-list"; /** Key used to keep track of the scroll state of the list. */ @@ -155,6 +155,8 @@ public final class ConversationListFragment extends ListFragment implements // True if NO DATA has returned, false if we either partially or fully loaded the data private boolean mInitialCursorLoading; + private @IdRes int mNextFocusLeftId; + /** Duration, in milliseconds, of the CAB mode (peek icon) animation. */ private static long sSelectionModeAnimationDuration = -1; @@ -448,13 +450,17 @@ public final class ConversationListFragment extends ListFragment implements mLoadingView = rootView.findViewById(R.id.background_view); mLoadingView.setVisibility(View.GONE); mLoadingView.findViewById(R.id.loading_progress).setVisibility(View.VISIBLE); - mListView = (SwipeableListView) rootView.findViewById(android.R.id.list); + mListView = (SwipeableListView) rootView.findViewById(R.id.conversation_list_view); mListView.setHeaderDividersEnabled(false); mListView.setOnItemLongClickListener(this); mListView.enableSwipe(mAccount.supportsCapability(AccountCapabilities.UNDO)); mListView.setListItemSwipedListener(this); mListView.setSwipeListener(this); mListView.setOnKeyListener(this); + mListView.setOnItemClickListener(this); + if (mNextFocusLeftId != 0) { + mListView.setNextFocusLeftId(mNextFocusLeftId); + } // enable animateOnLayout (equivalent of setLayoutTransition) only for >=JB (b/14302062) if (Utils.isRunningJellybeanOrLater()) { @@ -584,7 +590,7 @@ public final class ConversationListFragment extends ListFragment implements * {@inheritDoc} */ @Override - public void onListItemClick(ListView l, View view, int position, long id) { + public void onItemClick(AdapterView adapterView, View view, int position, long id) { onListItemSelected(view, position); } @@ -710,6 +716,15 @@ public final class ConversationListFragment extends ListFragment implements if (mFooterView != null) { mFooterView.onViewModeChanged(newMode); } + + // Set default navigation + if (ViewMode.isListMode(newMode)) { + mListView.setNextFocusRightId(R.id.conversation_list_view); + mListView.requestFocus(); + } else if (ViewMode.isConversationMode(newMode)) { + // This would only happen in two_pane + mListView.setNextFocusRightId(R.id.conversation_pager); + } } public boolean isAnimating() { @@ -857,9 +872,8 @@ public final class ConversationListFragment extends ListFragment implements action.performAction(); } }; - final SwipeableListView listView = (SwipeableListView) getListView(); - if (listView.getSwipeAction() == actionId) { - if (!listView.destroyItems(conversations, listener)) { + if (mListView.getSwipeAction() == actionId) { + if (!mListView.destroyItems(conversations, listener)) { // The listView failed to destroy the items, perform the action manually LogUtils.e(LOG_TAG, "ConversationListFragment.requestDelete: " + "listView failed to destroy items."); @@ -1194,4 +1208,15 @@ public final class ConversationListFragment extends ListFragment implements private boolean isCursorReadyToShow() { return ConversationCursor.isCursorReadyToShow(getConversationListCursor()); } + + public ListView getListView() { + return mListView; + } + + public void setNextFocusLeftId(@IdRes int id) { + mNextFocusLeftId = id; + if (mListView != null) { + mListView.setNextFocusLeftId(mNextFocusLeftId); + } + } } diff --git a/src/com/android/mail/ui/FolderListFragment.java b/src/com/android/mail/ui/FolderListFragment.java index 17e1789e2..67bd14174 100644 --- a/src/com/android/mail/ui/FolderListFragment.java +++ b/src/com/android/mail/ui/FolderListFragment.java @@ -750,6 +750,7 @@ public class FolderListFragment extends ListFragment implements } else { mMiniDrawerView.setVisibility(View.INVISIBLE); mListView.setVisibility(View.VISIBLE); + mListView.requestFocus(); } } diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java index 781efa3d4..0f08cdfb6 100644 --- a/src/com/android/mail/ui/TwoPaneController.java +++ b/src/com/android/mail/ui/TwoPaneController.java @@ -23,6 +23,7 @@ import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Intent; import android.os.Bundle; +import android.support.annotation.IdRes; import android.support.annotation.LayoutRes; import android.support.v7.app.ActionBar; import android.view.View; @@ -109,11 +110,14 @@ public final class TwoPaneController extends AbstractActivityController implemen FragmentTransaction fragmentTransaction = mActivity.getFragmentManager().beginTransaction(); // Use cross fading animation. fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); - final Fragment conversationListFragment = + final ConversationListFragment conversationListFragment = ConversationListFragment.newInstance(mConvListContext); fragmentTransaction.replace(R.id.conversation_list_pane, conversationListFragment, TAG_CONVERSATION_LIST); fragmentTransaction.commitAllowingStateLoss(); + // Set default navigation here once the ConversationListFragment is created. + conversationListFragment.setNextFocusLeftId( + getClfNextFocusLeftId(getFolderListFragment().isMinimized())); } @Override @@ -147,7 +151,7 @@ public final class TwoPaneController extends AbstractActivityController implemen @Override public boolean onCreate(Bundle savedState) { mLayout = (TwoPaneLayout) mActivity.findViewById(R.id.two_pane_activity); - if (mLayout == null) { + if (mLayout == null) { // We need the layout for everything. Crash/Return early if it is null. LogUtils.wtf(LOG_TAG, "mLayout is null!"); return false; @@ -242,6 +246,11 @@ public final class TwoPaneController extends AbstractActivityController implemen flf.setMinimized(!flf.isMinimized()); mLayout.requestLayout(); resetActionBarIcon(); + + final ConversationListFragment clf = getConversationListFragment(); + if (clf != null) { + clf.setNextFocusLeftId(getClfNextFocusLeftId(flf.isMinimized())); + } } @Override @@ -273,6 +282,10 @@ public final class TwoPaneController extends AbstractActivityController implemen } } + private @IdRes int getClfNextFocusLeftId(boolean drawerMinimized) { + return (drawerMinimized) ? R.id.current_account_avatar : android.R.id.list; + } + @Override public void onConversationVisibilityChanged(boolean visible) { super.onConversationVisibilityChanged(visible); -- cgit v1.2.3