Merge "Tune the threshold of fullscreen mode from 2.5in to 500dip"
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 04deb4e..50eca4b 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -70,7 +70,7 @@
     <dimen name="key_preview_offset">0.1in</dimen>
 
     <dimen name="key_label_horizontal_padding">4dip</dimen>
-    <dimen name="key_hint_letter_padding">2dp</dimen>
+    <dimen name="key_hint_letter_padding">1dp</dimen>
     <dimen name="key_uppercase_letter_padding">2dp</dimen>
 
     <dimen name="key_preview_height_ics">80sp</dimen>
diff --git a/java/res/xml/kbd_rows_arabic.xml b/java/res/xml/kbd_rows_arabic.xml
index 569ac7e..3051386 100644
--- a/java/res/xml/kbd_rows_arabic.xml
+++ b/java/res/xml/kbd_rows_arabic.xml
@@ -28,48 +28,48 @@
     >
         <Key
             latin:keyLabel="ض"
-            latin:keyHintLabel="1"
-            latin:moreKeys="1,١" />
+            latin:keyHintLabel="١"
+            latin:moreKeys="١,1" />
         <Key
             latin:keyLabel="ص"
-            latin:keyHintLabel="2"
-            latin:moreKeys="2,٢" />
+            latin:keyHintLabel="٢"
+            latin:moreKeys="٢,2" />
         <Key
             latin:keyLabel="ق"
-            latin:keyHintLabel="3"
-            latin:moreKeys="3,٣" />
+            latin:keyHintLabel="٣"
+            latin:moreKeys="٣,3" />
         <!-- \u06a4: ARABIC LETTER VEH -->
         <Key
             latin:keyLabel="ف"
-            latin:keyHintLabel="4"
-            latin:moreKeys="4,٤,\u06a4" />
+            latin:keyHintLabel="٤"
+            latin:moreKeys="٤,4,\u06a4" />
         <Key
             latin:keyLabel="غ"
-            latin:keyHintLabel="5"
-            latin:moreKeys="5,٥" />
+            latin:keyHintLabel="٥"
+            latin:moreKeys="٥,5" />
         <Key
             latin:keyLabel="ع"
-            latin:keyHintLabel="6"
-            latin:moreKeys="6,٦" />
+            latin:keyHintLabel="٦"
+            latin:moreKeys="٦,6" />
         <!-- \ufeeb: ARABIC LETTER HEH INITIAL FORM
              \u0647\u0640: ARABIC LETTER HEH + ARABIC TATWEEL -->
         <Key
             latin:keyLabel="ه"
-            latin:keyHintLabel="7"
-            latin:moreKeys="7,٧,\ufeeb|\u0647\u0640" />
+            latin:keyHintLabel="٧"
+            latin:moreKeys="٧,7,\ufeeb|\u0647\u0640" />
         <Key
             latin:keyLabel="خ"
-            latin:keyHintLabel="8"
-            latin:moreKeys="8,٨" />
+            latin:keyHintLabel="٨"
+            latin:moreKeys="٨,8" />
         <Key
             latin:keyLabel="ح"
-            latin:keyHintLabel="9"
-            latin:moreKeys="9,٩" />
+            latin:keyHintLabel="٩"
+            latin:moreKeys="٩,9" />
         <!-- \u0686: ARABIC LETTER TCHEH -->
         <Key
             latin:keyLabel="ج"
-            latin:keyHintLabel="0"
-            latin:moreKeys="0,٠,\u0686"
+            latin:keyHintLabel="٠"
+            latin:moreKeys="٠,0,\u0686"
             latin:keyWidth="fillRight" />
     </Row>
     <Row
diff --git a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
index 9397483..a4dfa10 100644
--- a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
+++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
@@ -717,8 +717,8 @@
         mHasUsedVoiceInputUnsupportedLocale =
                 sp.getBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, false);
 
-        mLocaleSupportedForVoiceInput = SubtypeSwitcher.getInstance().isVoiceSupported(
-                SubtypeSwitcher.getInstance().getInputLocaleStr());
+        mLocaleSupportedForVoiceInput = SubtypeSwitcher.isVoiceSupported(
+                mService, SubtypeSwitcher.getInstance().getInputLocaleStr());
 
         final String voiceMode = sp.getString(PREF_VOICE_MODE,
                 mService.getString(R.string.voice_mode_main));
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 96eb694..1e7c326 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -124,7 +124,8 @@
     // This map caches key label text width in pixel as value and key label text size as map key.
     private static final HashMap<Integer, Float> sTextWidthCache =
             new HashMap<Integer, Float>();
-    private static final String KEY_LABEL_REFERENCE_CHAR = "M";
+    private static final char[] KEY_LABEL_REFERENCE_CHAR = { 'M' };
+    private static final char[] KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR = { '8' };
 
     private final DrawingHandler mDrawingHandler = new DrawingHandler(this);
 
@@ -545,8 +546,8 @@
             final int labelSize = key.selectTextSize(params.mKeyLetterSize,
                     params.mKeyLargeLetterSize, params.mKeyLabelSize, params.mKeyHintLabelSize);
             paint.setTextSize(labelSize);
-            final float labelCharHeight = getCharHeight(paint);
-            final float labelCharWidth = getCharWidth(paint);
+            final float labelCharHeight = getCharHeight(KEY_LABEL_REFERENCE_CHAR, paint);
+            final float labelCharWidth = getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint);
 
             // Vertical label text alignment.
             final float baseline = centerY + labelCharHeight / 2;
@@ -634,20 +635,25 @@
             }
             paint.setColor(hintColor);
             paint.setTextSize(hintSize);
-            final float hintCharWidth = getCharWidth(paint);
             final float hintX, hintY;
             if (key.hasHintLabel()) {
+                // The hint label is placed just right of the key label. Used mainly on
+                // "phone number" layout.
                 // TODO: Generalize the following calculations.
-                hintX = positionX + hintCharWidth * 2;
-                hintY = centerY + getCharHeight(paint) / 2;
+                hintX = positionX + getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) * 2;
+                hintY = centerY + getCharHeight(KEY_LABEL_REFERENCE_CHAR, paint) / 2;
                 paint.setTextAlign(Align.LEFT);
             } else if (key.hasUppercaseLetter()) {
-                hintX = keyWidth - params.mKeyUppercaseLetterPadding - hintCharWidth / 2;
-                hintY = -paint.ascent() + params.mKeyUppercaseLetterPadding;
+                // The hint label is placed at top-right corner of the key. Used mainly on tablet.
+                hintX = keyWidth - params.mKeyUppercaseLetterPadding
+                        - getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2;
+                hintY = -paint.ascent();
                 paint.setTextAlign(Align.CENTER);
             } else { // key.hasHintLetter()
-                hintX = keyWidth - params.mKeyHintLetterPadding - hintCharWidth / 2;
-                hintY = -paint.ascent() + params.mKeyHintLetterPadding;
+                // The hint label is placed at top-right corner of the key. Used mainly on phone.
+                hintX = keyWidth - params.mKeyHintLetterPadding
+                        - getCharWidth(KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR, paint) / 2;
+                hintY = -paint.ascent();
                 paint.setTextAlign(Align.CENTER);
             }
             canvas.drawText(hint, 0, hint.length(), hintX, hintY, paint);
@@ -690,7 +696,8 @@
             paint.setTextSize(params.mKeyHintLetterSize);
             paint.setColor(params.mKeyHintLabelColor);
             paint.setTextAlign(Align.CENTER);
-            final float hintX = keyWidth - params.mKeyHintLetterPadding - getCharWidth(paint) / 2;
+            final float hintX = keyWidth - params.mKeyHintLetterPadding
+                    - getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2;
             final float hintY = keyHeight - params.mKeyHintLetterPadding;
             canvas.drawText(POPUP_HINT_CHAR, hintX, hintY, paint);
 
@@ -704,37 +711,40 @@
 
     private static final Rect sTextBounds = new Rect();
 
-    private static float getCharHeight(Paint paint) {
+    private static int getCharGeometryCacheKey(char reference, Paint paint) {
         final int labelSize = (int)paint.getTextSize();
-        final Float cachedValue = sTextHeightCache.get(labelSize);
+        final Typeface face = paint.getTypeface();
+        final int codePointOffset = reference << 15;
+        if (face == Typeface.DEFAULT) {
+            return codePointOffset + labelSize;
+        } else if (face == Typeface.DEFAULT_BOLD) {
+            return codePointOffset + labelSize + 0x1000;
+        } else if (face == Typeface.MONOSPACE) {
+            return codePointOffset + labelSize + 0x2000;
+        } else {
+            return codePointOffset + labelSize;
+        }
+    }
+
+    private static float getCharHeight(char[] character, Paint paint) {
+        final Integer key = getCharGeometryCacheKey(character[0], paint);
+        final Float cachedValue = sTextHeightCache.get(key);
         if (cachedValue != null)
             return cachedValue;
 
-        paint.getTextBounds(KEY_LABEL_REFERENCE_CHAR, 0, 1, sTextBounds);
+        paint.getTextBounds(character, 0, 1, sTextBounds);
         final float height = sTextBounds.height();
-        sTextHeightCache.put(labelSize, height);
+        sTextHeightCache.put(key, height);
         return height;
     }
 
-    private static float getCharWidth(Paint paint) {
-        final int labelSize = (int)paint.getTextSize();
-        final Typeface face = paint.getTypeface();
-        final Integer key;
-        if (face == Typeface.DEFAULT) {
-            key = labelSize;
-        } else if (face == Typeface.DEFAULT_BOLD) {
-            key = labelSize + 1000;
-        } else if (face == Typeface.MONOSPACE) {
-            key = labelSize + 2000;
-        } else {
-            key = labelSize;
-        }
+    private static float getCharWidth(char[] character, Paint paint) {
+        final Integer key = getCharGeometryCacheKey(character[0], paint);
+        final Float cachedValue = sTextWidthCache.get(key);
+        if (cachedValue != null)
+            return cachedValue;
 
-        final Float cached = sTextWidthCache.get(key);
-        if (cached != null)
-            return cached;
-
-        paint.getTextBounds(KEY_LABEL_REFERENCE_CHAR, 0, 1, sTextBounds);
+        paint.getTextBounds(character, 0, 1, sTextBounds);
         final float width = sTextBounds.width();
         sTextWidthCache.put(key, width);
         return width;
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index e99bb70..e0eae18 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -580,8 +580,8 @@
                 // Get the current list of supported locales and check the current locale against
                 // that list, to decide whether to put a warning that voice input will not work in
                 // the current language as part of the pop-up confirmation dialog.
-                boolean localeSupported = SubtypeSwitcher.getInstance().isVoiceSupported(
-                        Locale.getDefault().toString());
+                boolean localeSupported = SubtypeSwitcher.isVoiceSupported(
+                        this, Locale.getDefault().toString());
 
                 final CharSequence message;
                 if (localeSupported) {
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index 56f14de..f9dda6a 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -539,14 +539,14 @@
     }
 
 
-    public boolean isVoiceSupported(String locale) {
+    public static boolean isVoiceSupported(Context context, String locale) {
         // Get the current list of supported locales and check the current locale against that
         // list. We cache this value so as not to check it every time the user starts a voice
         // input. Because this method is called by onStartInputView, this should mean that as
         // long as the locale doesn't change while the user is keeping the IME open, the
         // value should never be stale.
         String supportedLocalesString = VoiceProxy.getSupportedLocalesString(
-                mService.getContentResolver());
+                context.getContentResolver());
         List<String> voiceInputSupportedLocales = Arrays.asList(
                 supportedLocalesString.split("\\s+"));
         return voiceInputSupportedLocales.contains(locale);