Merge "Support keyboard navigation for RTL" into ub-gmail-ur14-dev
diff --git a/res/layout/folder_list.xml b/res/layout/folder_list.xml
index 3632f9c..239dea7 100644
--- a/res/layout/folder_list.xml
+++ b/res/layout/folder_list.xml
@@ -24,8 +24,8 @@
         android:id="@android:id/list"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:nextFocusRight="@+id/conversation_list_view"
-        android:fadingEdge="none" />
+        android:fadingEdge="none"
+        style="@style/DrawerNavigationStyle" />
 
     <com.android.mail.ui.MiniDrawerView
         android:id="@+id/mini_drawer"
diff --git a/res/values-ldrtl/styles-ldrtl.xml b/res/values-ldrtl/styles-ldrtl.xml
index 54df227..99a1b53 100644
--- a/res/values-ldrtl/styles-ldrtl.xml
+++ b/res/values-ldrtl/styles-ldrtl.xml
@@ -63,6 +63,10 @@
         <item name="android:layout_marginEnd">@dimen/toast_bar_margin</item>
     </style>
 
+    <style name="DrawerNavigationStyle">
+        <item name="android:nextFocusLeft">@+id/conversation_list_view</item>
+    </style>
+
     <style name="FolderListItemStartStyle">
         <item name="android:layout_marginStart">@dimen/folder_list_item_text_start_margin</item>
     </style>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 0bc58bc..178b4b4 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -594,10 +594,13 @@
         <item name="android:layout_marginRight">@dimen/conversation_border_margin_side</item>
     </style>
 
-    <style name="MiniDrawerItemStyleBase">
+    <style name="DrawerNavigationStyle">
+        <item name="android:nextFocusRight">@+id/conversation_list_view</item>
+    </style>
+
+    <style name="MiniDrawerItemStyleBase" parent="@style/DrawerNavigationStyle">
         <item name="android:background">?android:attr/selectableItemBackground</item>
         <item name="android:focusable">true</item>
-        <item name="android:nextFocusRight">@+id/conversation_list_view</item>
         <item name="android:scaleType">fitCenter</item>
     </style>
 
diff --git a/src/com/android/mail/ui/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java
index dba18a8..57c947c 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -61,6 +61,7 @@
 import com.android.mail.ui.SwipeableListView.ListItemsRemovedListener;
 import com.android.mail.ui.SwipeableListView.SwipeListener;
 import com.android.mail.ui.ViewMode.ModeChangeListener;
+import com.android.mail.utils.KeyboardUtils;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
@@ -155,10 +156,11 @@
     // True if NO DATA has returned, false if we either partially or fully loaded the data
     private boolean mInitialCursorLoading;
 
-    private @IdRes int mNextFocusLeftId;
+    private @IdRes int mNextFocusStartId;
     // Tracks if a onKey event was initiated from the listview (received ACTION_DOWN before
     // ACTION_UP). If not, the listview only receives ACTION_UP.
     private boolean mKeyInitiatedFromList;
+    private boolean mIsRtl;
 
     /** Duration, in milliseconds, of the CAB mode (peek icon) animation. */
     private static long sSelectionModeAnimationDuration = -1;
@@ -467,13 +469,12 @@
         mListView.setOnKeyListener(this);
         mListView.setOnItemClickListener(this);
 
+        mIsRtl = Utils.isCurrentLocaleRtl();
         // For tablets, the default left focus is the mini-drawer
-        if (mTabletDevice) {
-            mNextFocusLeftId = R.id.current_account_avatar;
+        if (mTabletDevice && mNextFocusStartId == 0) {
+            mNextFocusStartId = R.id.current_account_avatar;
         }
-        if (mNextFocusLeftId != 0) {
-            mListView.setNextFocusLeftId(mNextFocusLeftId);
-        }
+        setNextFocusStartOnList();
 
         // enable animateOnLayout (equivalent of setLayoutTransition) only for >=JB (b/14302062)
         if (Utils.isRunningJellybeanOrLater()) {
@@ -639,7 +640,7 @@
         if (view instanceof  SwipeableListView) {
             SwipeableListView list = (SwipeableListView) view;
             // Don't need to handle ENTER because it's auto-handled as a "click".
-            if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+            if (KeyboardUtils.isKeycodeDirectionEnd(keyCode, mIsRtl)) {
                 if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
                     if (mKeyInitiatedFromList) {
                         onListItemSelected(list.getSelectedView(), list.getSelectedItemPosition());
@@ -649,14 +650,14 @@
                     mKeyInitiatedFromList = true;
                 }
                 return true;
-            } else if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
-                if (keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
-                    final int position = list.getSelectedItemPosition();
-                    final Object item = getAnimatedAdapter().getItem(position);
-                    if (item != null && item instanceof ConversationCursor) {
-                        final Conversation conv = ((ConversationCursor) item).getConversation();
-                        mCallbacks.onConversationFocused(conv);
-                    }
+            } else if ((keyCode == KeyEvent.KEYCODE_DPAD_UP ||
+                    keyCode == KeyEvent.KEYCODE_DPAD_DOWN) &&
+                    keyEvent.getAction() == KeyEvent.ACTION_UP) {
+                final int position = list.getSelectedItemPosition();
+                final Object item = getAnimatedAdapter().getItem(position);
+                if (item != null && item instanceof ConversationCursor) {
+                    final Conversation conv = ((ConversationCursor) item).getConversation();
+                    mCallbacks.onConversationFocused(conv);
                 }
             }
         }
@@ -1225,10 +1226,18 @@
         return mListView;
     }
 
-    public void setNextFocusLeftId(@IdRes int id) {
-        mNextFocusLeftId = id;
-        if (mListView != null) {
-            mListView.setNextFocusLeftId(mNextFocusLeftId);
+    public void setNextFocusStartId(@IdRes int id) {
+        mNextFocusStartId = id;
+        setNextFocusStartOnList();
+    }
+
+    private void setNextFocusStartOnList() {
+        if (mListView != null && mNextFocusStartId != 0) {
+            // Since we manually handle right navigation from the list, let's just always set both
+            // the default left and right navigation to the left id so that whenever the framework
+            // handles one of these directions, it will go to the left side regardless of RTL.
+            mListView.setNextFocusLeftId(mNextFocusStartId);
+            mListView.setNextFocusRightId(mNextFocusStartId);
         }
     }
 }
diff --git a/src/com/android/mail/ui/ConversationViewFragment.java b/src/com/android/mail/ui/ConversationViewFragment.java
index 6c23274..1f173f2 100644
--- a/src/com/android/mail/ui/ConversationViewFragment.java
+++ b/src/com/android/mail/ui/ConversationViewFragment.java
@@ -82,6 +82,7 @@
 import com.android.mail.providers.UIProvider;
 import com.android.mail.ui.ConversationViewState.ExpansionState;
 import com.android.mail.utils.ConversationViewUtils;
+import com.android.mail.utils.KeyboardUtils;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
@@ -141,6 +142,7 @@
     private View mOriginalKeyedView;
     private int mMaxScreenHeight;
     private int mTopOfVisibleScreen;
+    private boolean mIsRtl;
 
     protected ConversationContainer mConversationContainer;
 
@@ -440,6 +442,8 @@
         mViewsCreated = true;
         mWebViewLoadedData = false;
 
+        mIsRtl = Utils.isCurrentLocaleRtl();
+
         return rootView;
     }
 
@@ -1178,8 +1182,8 @@
         if (mOriginalKeyedView != null) {
             final int id = mOriginalKeyedView.getId();
             final boolean isActionUp = keyEvent.getAction() == KeyEvent.ACTION_UP;
-            final boolean isLeft = keyCode == KeyEvent.KEYCODE_DPAD_LEFT;
-            final boolean isRight = keyCode == KeyEvent.KEYCODE_DPAD_RIGHT;
+            final boolean isStart = KeyboardUtils.isKeycodeDirectionStart(keyCode, mIsRtl);
+            final boolean isEnd = KeyboardUtils.isKeycodeDirectionEnd(keyCode, mIsRtl);
             final boolean isUp = keyCode == KeyEvent.KEYCODE_DPAD_UP;
             final boolean isDown = keyCode == KeyEvent.KEYCODE_DPAD_DOWN;
 
@@ -1187,14 +1191,14 @@
             // We manually check if the view+direction combination should shift focus away from the
             // conversation view to the thread list in two-pane landscape mode.
             final boolean isTwoPaneLand = mNavigationController.isTwoPaneLandscape();
-            final boolean navigateAway = shouldNavigateAway(id, isLeft, isTwoPaneLand);
+            final boolean navigateAway = shouldNavigateAway(id, isStart, isTwoPaneLand);
             if (mNavigationController.onInterceptKeyFromCV(keyCode, keyEvent, navigateAway)) {
                 return true;
             }
 
             // If controller didn't handle the event, check directional interception.
-            if ((isLeft || isRight) && shouldInterceptLeftRightEvents(
-                    id, isLeft, isRight, isTwoPaneLand)) {
+            if ((isStart || isEnd) && shouldInterceptLeftRightEvents(
+                    id, isStart, isEnd, isTwoPaneLand)) {
                 return true;
             } else if (isUp || isDown) {
                 // We don't do anything on up/down for overlay
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 22cb630..9ba9270 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -119,7 +119,7 @@
                 TAG_CONVERSATION_LIST);
         fragmentTransaction.commitAllowingStateLoss();
         // Set default navigation here once the ConversationListFragment is created.
-        conversationListFragment.setNextFocusLeftId(
+        conversationListFragment.setNextFocusStartId(
                 getClfNextFocusLeftId(getFolderListFragment().isMinimized()));
     }
 
@@ -252,7 +252,7 @@
 
         final ConversationListFragment clf = getConversationListFragment();
         if (clf != null) {
-            clf.setNextFocusLeftId(getClfNextFocusLeftId(flf.isMinimized()));
+            clf.setNextFocusStartId(getClfNextFocusLeftId(flf.isMinimized()));
 
             final SwipeableListView list = clf.getListView();
             if (list != null) {
diff --git a/src/com/android/mail/utils/KeyboardUtils.java b/src/com/android/mail/utils/KeyboardUtils.java
new file mode 100644
index 0000000..7bfd61c
--- /dev/null
+++ b/src/com/android/mail/utils/KeyboardUtils.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2014, Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.utils;
+
+import android.view.KeyEvent;
+
+/**
+ * Utility class for keyboard navigation.
+ */
+public class KeyboardUtils {
+    /**
+     * Determine if the provided keycode is toward the start direction of the normal layout.
+     * This is used for keyboard navigation since the layouts are flipped for RTL.
+     */
+    public static boolean isKeycodeDirectionStart(int keyCode, boolean isRtl) {
+        return (!isRtl && keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ||
+                (isRtl && keyCode == KeyEvent.KEYCODE_DPAD_RIGHT);
+    }
+
+    /**
+     * Determine if the provided keycode is toward the end direction of the normal layout.
+     * This is used for keyboard navigation since the layouts are flipped for RTL.
+     */
+    public static boolean isKeycodeDirectionEnd(int keyCode, boolean isRtl) {
+        return (isRtl && keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ||
+                (!isRtl && keyCode == KeyEvent.KEYCODE_DPAD_RIGHT);
+    }
+}
diff --git a/src/com/android/mail/utils/Utils.java b/src/com/android/mail/utils/Utils.java
index 662a270..05f3665 100644
--- a/src/com/android/mail/utils/Utils.java
+++ b/src/com/android/mail/utils/Utils.java
@@ -35,6 +35,8 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.provider.Browser;
+import android.support.v4.text.TextUtilsCompat;
+import android.support.v4.view.ViewCompat;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.Spanned;
@@ -63,7 +65,6 @@
 import com.android.mail.providers.UIProvider;
 import com.android.mail.providers.UIProvider.EditSettingsExtras;
 import com.android.mail.ui.HelpActivity;
-import com.android.mail.ui.ViewMode;
 import com.google.android.mail.common.html.parser.HtmlDocument;
 import com.google.android.mail.common.html.parser.HtmlParser;
 import com.google.android.mail.common.html.parser.HtmlTree;
@@ -1157,4 +1158,9 @@
         final NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
         return (networkInfo != null) && networkInfo.isConnected();
     }
+
+    public static boolean isCurrentLocaleRtl() {
+        return TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) ==
+                ViewCompat.LAYOUT_DIRECTION_RTL;
+    }
 }