summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJin Cao <jinyan@google.com>2014-08-05 14:03:59 -0700
committerJin Cao <jinyan@google.com>2014-08-08 17:57:43 -0700
commita7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62 (patch)
tree0d8e9613760c7ffff1a6ca24b910671a231f38cb /src
parent094986e3c824d705909af10464954532c377adc3 (diff)
downloadandroid_packages_apps_UnifiedEmail-a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62.tar.gz
android_packages_apps_UnifiedEmail-a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62.tar.bz2
android_packages_apps_UnifiedEmail-a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62.zip
[KBNav CV] basic support for CV keyboard nav
Support basic navigation via keyboard in CV. b/16636060 Change-Id: I66dbcd8015d722244b57c4e24579d0d854d3ee74
Diffstat (limited to 'src')
-rw-r--r--src/com/android/mail/browse/ConversationContainer.java1
-rw-r--r--src/com/android/mail/browse/ConversationOverlayItem.java17
-rw-r--r--src/com/android/mail/browse/ConversationViewAdapter.java84
-rw-r--r--src/com/android/mail/ui/ConversationViewFragment.java32
-rw-r--r--src/com/android/mail/ui/TwoPaneController.java11
-rw-r--r--src/com/android/mail/ui/TwoPaneLayout.java13
6 files changed, 137 insertions, 21 deletions
diff --git a/src/com/android/mail/browse/ConversationContainer.java b/src/com/android/mail/browse/ConversationContainer.java
index a5e82b177..f99bd3731 100644
--- a/src/com/android/mail/browse/ConversationContainer.java
+++ b/src/com/android/mail/browse/ConversationContainer.java
@@ -29,7 +29,6 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.webkit.WebView;
-import android.widget.Adapter;
import android.widget.ListView;
import android.widget.ScrollView;
diff --git a/src/com/android/mail/browse/ConversationOverlayItem.java b/src/com/android/mail/browse/ConversationOverlayItem.java
index e52e9d662..08f2cdfba 100644
--- a/src/com/android/mail/browse/ConversationOverlayItem.java
+++ b/src/com/android/mail/browse/ConversationOverlayItem.java
@@ -42,6 +42,7 @@ public abstract class ConversationOverlayItem {
* @see Adapter#getItemViewType(int)
*/
public abstract @ConversationViewType int getType();
+
/**
* Inflate and perform one-time initialization on a view for later binding.
*/
@@ -55,6 +56,7 @@ public abstract class ConversationOverlayItem {
* know they can cut certain corners that do not affect a view's height)
*/
public abstract void bindView(View v, boolean measureOnly);
+
/**
* Returns true if this overlay view is meant to be positioned right on top of the overlay
* below. This special positioning allows {@link ConversationContainer} to stack overlays
@@ -63,6 +65,10 @@ public abstract class ConversationOverlayItem {
*/
public abstract boolean isContiguous();
+ public View.OnKeyListener getOnKeyListener() {
+ return null;
+ }
+
/**
* Returns true if this overlay view is in its expanded state.
*/
@@ -181,4 +187,15 @@ public abstract class ConversationOverlayItem {
public void rebindView(View view) {
// DO NOTHING
}
+
+ public void registerOnKeyListeners(View... views) {
+ final View.OnKeyListener listener = getOnKeyListener();
+ if (listener != null) {
+ for (View v : views) {
+ if (v != null) {
+ v.setOnKeyListener(listener);
+ }
+ }
+ }
+ }
}
diff --git a/src/com/android/mail/browse/ConversationViewAdapter.java b/src/com/android/mail/browse/ConversationViewAdapter.java
index 0ae489694..bda63c136 100644
--- a/src/com/android/mail/browse/ConversationViewAdapter.java
+++ b/src/com/android/mail/browse/ConversationViewAdapter.java
@@ -110,6 +110,8 @@ public class ConversationViewAdapter extends BaseAdapter {
private final BidiFormatter mBidiFormatter;
+ private final View.OnKeyListener mOnKeyListener;
+
public class ConversationHeaderItem extends ConversationOverlayItem {
public final Conversation mConversation;
@@ -124,19 +126,22 @@ public class ConversationViewAdapter extends BaseAdapter {
@Override
public View createView(Context context, LayoutInflater inflater, ViewGroup parent) {
- final ConversationViewHeader headerView = (ConversationViewHeader) inflater.inflate(
+ final ConversationViewHeader v = (ConversationViewHeader) inflater.inflate(
R.layout.conversation_view_header, parent, false);
- headerView.setCallbacks(
+ v.setCallbacks(
mConversationCallbacks, mAccountController, mConversationUpdater);
- headerView.bind(this);
- headerView.setSubject(mConversation.subject);
+ v.bind(this);
+ v.setSubject(mConversation.subject);
if (mAccountController.getAccount().supportsCapability(
UIProvider.AccountCapabilities.MULTIPLE_FOLDERS_PER_CONV)) {
- headerView.setFolders(mConversation);
+ v.setFolders(mConversation);
}
- headerView.setStarred(mConversation.starred);
+ v.setStarred(mConversation.starred);
+
+ // Register the onkey listener for all relevant views
+ registerOnKeyListeners(v, v.findViewById(R.id.subject_and_folder_view));
- return headerView;
+ return v;
}
@Override
@@ -150,6 +155,11 @@ public class ConversationViewAdapter extends BaseAdapter {
return true;
}
+ @Override
+ public View.OnKeyListener getOnKeyListener() {
+ return mOnKeyListener;
+ }
+
public ConversationViewAdapter getAdapter() {
return ConversationViewAdapter.this;
}
@@ -169,11 +179,16 @@ public class ConversationViewAdapter extends BaseAdapter {
@Override
public View createView(Context context, LayoutInflater inflater, ViewGroup parent) {
- final ConversationFooterView view = (ConversationFooterView)
+ final ConversationFooterView v = (ConversationFooterView)
inflater.inflate(R.layout.conversation_footer, parent, false);
- view.setAccountController(mAccountController);
- view.setConversationFooterCallbacks(mConversationFooterCallbacks);
- return view;
+ v.setAccountController(mAccountController);
+ v.setConversationFooterCallbacks(mConversationFooterCallbacks);
+
+ // Register the onkey listener for all relevant views
+ registerOnKeyListeners(v, v.findViewById(R.id.reply_button),
+ v.findViewById(R.id.reply_all_button), v.findViewById(R.id.forward_button));
+
+ return v;
}
@Override
@@ -191,6 +206,11 @@ public class ConversationViewAdapter extends BaseAdapter {
return true;
}
+ @Override
+ public View.OnKeyListener getOnKeyListener() {
+ return mOnKeyListener;
+ }
+
public MessageHeaderItem getLastMessageHeaderItem() {
return mLastMessageHeaderItem;
}
@@ -248,6 +268,12 @@ public class ConversationViewAdapter extends BaseAdapter {
v.setCallbacks(mAdapter.mMessageCallbacks);
v.setContactInfoSource(mAdapter.mContactInfoSource);
v.setVeiledMatcher(mAdapter.mMatcher);
+
+ // Register the onkey listener for all relevant views
+ registerOnKeyListeners(v, v.findViewById(R.id.upper_header),
+ v.findViewById(R.id.hide_details), v.findViewById(R.id.edit_draft),
+ v.findViewById(R.id.reply), v.findViewById(R.id.reply_all),
+ v.findViewById(R.id.overflow), v.findViewById(R.id.send_date));
return v;
}
@@ -269,6 +295,11 @@ public class ConversationViewAdapter extends BaseAdapter {
}
@Override
+ public View.OnKeyListener getOnKeyListener() {
+ return mAdapter.getOnKeyListener();
+ }
+
+ @Override
public boolean isExpanded() {
return mExpanded;
}
@@ -367,6 +398,9 @@ public class ConversationViewAdapter extends BaseAdapter {
R.layout.conversation_message_footer, parent, false);
v.initialize(mAdapter.mLoaderManager, mAdapter.mFragmentManager,
mAdapter.mAccountController, mAdapter.mFooterCallbacks);
+
+ // Register the onkey listener for all relevant views
+ registerOnKeyListeners(v, v.findViewById(R.id.view_entire_message_prompt));
return v;
}
@@ -382,6 +416,11 @@ public class ConversationViewAdapter extends BaseAdapter {
}
@Override
+ public View.OnKeyListener getOnKeyListener() {
+ return mAdapter.getOnKeyListener();
+ }
+
+ @Override
public boolean isExpanded() {
return mHeaderItem.isExpanded();
}
@@ -427,10 +466,14 @@ public class ConversationViewAdapter extends BaseAdapter {
@Override
public View createView(Context context, LayoutInflater inflater, ViewGroup parent) {
- final SuperCollapsedBlock scb = (SuperCollapsedBlock) inflater.inflate(
+ final SuperCollapsedBlock v = (SuperCollapsedBlock) inflater.inflate(
R.layout.super_collapsed_block, parent, false);
- scb.initialize(mSuperCollapsedListener);
- return scb;
+ v.initialize(mSuperCollapsedListener);
+ v.setOnKeyListener(mOnKeyListener);
+
+ // Register the onkey listener for all relevant views
+ registerOnKeyListeners(v);
+ return v;
}
@Override
@@ -445,6 +488,11 @@ public class ConversationViewAdapter extends BaseAdapter {
}
@Override
+ public View.OnKeyListener getOnKeyListener() {
+ return mOnKeyListener;
+ }
+
+ @Override
public boolean isExpanded() {
return false;
}
@@ -479,7 +527,8 @@ public class ConversationViewAdapter extends BaseAdapter {
OnClickListener scbListener,
Map<String, Address> addressCache,
FormattedDateBuilder dateBuilder,
- BidiFormatter bidiFormatter) {
+ BidiFormatter bidiFormatter,
+ View.OnKeyListener onKeyListener) {
mContext = controllableActivity.getActivityContext();
mDateBuilder = dateBuilder;
mAccountController = accountController;
@@ -499,6 +548,7 @@ public class ConversationViewAdapter extends BaseAdapter {
mMatcher = controllableActivity.getAccountController().getVeiledAddressMatcher();
mBidiFormatter = bidiFormatter;
+ mOnKeyListener = onKeyListener;
}
@Override
@@ -665,4 +715,8 @@ public class ConversationViewAdapter extends BaseAdapter {
public BidiFormatter getBidiFormatter() {
return mBidiFormatter;
}
+
+ public View.OnKeyListener getOnKeyListener() {
+ return mOnKeyListener;
+ }
}
diff --git a/src/com/android/mail/ui/ConversationViewFragment.java b/src/com/android/mail/ui/ConversationViewFragment.java
index f5a0cdad7..803574ffc 100644
--- a/src/com/android/mail/ui/ConversationViewFragment.java
+++ b/src/com/android/mail/ui/ConversationViewFragment.java
@@ -30,6 +30,7 @@ import android.os.SystemClock;
import android.support.v4.text.BidiFormatter;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
@@ -97,7 +98,7 @@ import java.util.Set;
public class ConversationViewFragment extends AbstractConversationViewFragment implements
SuperCollapsedBlock.OnClickListener, OnLayoutChangeListener,
MessageHeaderView.MessageHeaderViewCallbacks, MessageFooterView.MessageFooterCallbacks,
- WebViewContextMenu.Callbacks, ConversationFooterCallbacks {
+ WebViewContextMenu.Callbacks, ConversationFooterCallbacks, View.OnKeyListener {
private static final String LOG_TAG = LogTag.getLogTag();
public static final String LAYOUT_TAG = "ConvLayout";
@@ -130,6 +131,8 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
protected ConversationWebView mWebView;
+ private ViewGroup mTopmostOverlay;
+
private ConversationViewProgressController mProgressController;
private Button mNewMessageBar;
@@ -276,7 +279,7 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
mAdapter = new ConversationViewAdapter(mActivity, this,
getLoaderManager(), this, this, getContactInfoSource(), this, this,
- getListController(), this, mAddressCache, dateBuilder, mBidiFormatter);
+ getListController(), this, mAddressCache, dateBuilder, mBidiFormatter, this);
mConversationContainer.setOverlayAdapter(mAdapter);
// set up snap header (the adapter usually does this with the other ones)
@@ -354,9 +357,10 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
.findViewById(R.id.conversation_container);
mConversationContainer.setAccountController(this);
- final ViewGroup topmostOverlay =
+ mTopmostOverlay =
(ViewGroup) mConversationContainer.findViewById(R.id.conversation_topmost_overlay);
- inflateSnapHeader(topmostOverlay, inflater);
+ mTopmostOverlay.setOnKeyListener(this);
+ inflateSnapHeader(mTopmostOverlay, inflater);
mConversationContainer.setupSnapHeader();
setupNewMessageBar();
@@ -1115,6 +1119,26 @@ public class ConversationViewFragment extends AbstractConversationViewFragment i
return getMessageCursor().getMessageForId(Long.parseLong(messageId));
}
+ @Override
+ public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
+ // Only care about enter and esc
+ View currFocus = mActivity.getWindow().getCurrentFocus();
+ if (keyCode == KeyEvent.KEYCODE_BACK && currFocus != null &&
+ currFocus.getId() != R.id.conversation_topmost_overlay) {
+ if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
+ mTopmostOverlay.requestFocus();
+ }
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_ENTER && (currFocus == null ||
+ currFocus.getId() == R.id.conversation_topmost_overlay)) {
+ if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
+ mConversationContainer.findViewById(R.id.upper_header).requestFocus();
+ }
+ return true;
+ }
+ return false;
+ }
+
public class ConversationWebViewClient extends AbstractConversationWebViewClient {
public ConversationWebViewClient(Account account) {
super(account);
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 781efa3d4..c37137257 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -42,7 +42,7 @@ import com.android.mail.utils.Utils;
* abounds.
*/
public final class TwoPaneController extends AbstractActivityController implements
- ConversationViewFrame.DownEventListener {
+ ConversationViewFrame.DownEventListener, TwoPaneLayout.TwoPaneLayoutListener {
private static final String SAVED_MISCELLANEOUS_VIEW = "saved-miscellaneous-view";
private static final String SAVED_MISCELLANEOUS_VIEW_TRANSACTION_ID =
@@ -153,6 +153,7 @@ public final class TwoPaneController extends AbstractActivityController implemen
return false;
}
mLayout.setController(this, Intent.ACTION_SEARCH.equals(mActivity.getIntent().getAction()));
+ mLayout.setLayoutListener(this);
mActivity.getWindow().setBackgroundDrawable(null);
mIsTabletLandscape = !mActivity.getResources().getBoolean(R.bool.list_collapsible);
@@ -590,4 +591,12 @@ public final class TwoPaneController extends AbstractActivityController implemen
}
return false;
}
+
+ @Override
+ public void onListViewLayout(boolean isOnScreen) {
+ ConversationListFragment clf = getConversationListFragment();
+ if (clf != null && clf.getListView() != null) {
+ clf.getListView().setFocusable(isOnScreen);
+ }
+ }
}
diff --git a/src/com/android/mail/ui/TwoPaneLayout.java b/src/com/android/mail/ui/TwoPaneLayout.java
index 5af59ccff..5f29664a7 100644
--- a/src/com/android/mail/ui/TwoPaneLayout.java
+++ b/src/com/android/mail/ui/TwoPaneLayout.java
@@ -96,6 +96,8 @@ final class TwoPaneLayout extends FrameLayout implements ModeChangeListener {
private View mFoldersView;
private View mListView;
+ private TwoPaneLayoutListener mLayoutListener;
+
public static final int MISCELLANEOUS_VIEW_ID = R.id.miscellaneous_pane;
private final Runnable mTransitionCompleteRunnable = new Runnable() {
@@ -171,6 +173,10 @@ final class TwoPaneLayout extends FrameLayout implements ModeChangeListener {
super.onLayout(changed, l, t, r, b);
}
+ public void setLayoutListener(TwoPaneLayoutListener listener) {
+ mLayoutListener = listener;
+ }
+
/**
* Sizes up the three sliding panes. This method will ensure that the LayoutParams of the panes
* have the correct widths set for the current overall size and view mode.
@@ -238,6 +244,10 @@ final class TwoPaneLayout extends FrameLayout implements ModeChangeListener {
}
animatePanes(foldersX, listX, convX);
+ // For keyboard navigation, let's disable focus on the list if it's not visible.
+ if (mLayoutListener != null) {
+ mLayoutListener.onListViewLayout(listX >= 0);
+ }
mPositionedMode = mCurrentMode;
}
@@ -456,4 +466,7 @@ final class TwoPaneLayout extends FrameLayout implements ModeChangeListener {
return !mListCollapsible;
}
+ public interface TwoPaneLayoutListener {
+ public void onListViewLayout(boolean isOnScreen);
+ }
}