Add lightweight visual indication for numbers.

This change adds lightweight visual hints of alternate numeric characters on the top row - e.g. having a light gray '1' on the upper right corner of letter 'q'

Note that MDPI resources are tentative (the same as HDPI for now, until we get fixed MDPI visual assets).

bug: 3004632
Change-Id: I7a25cf90b702433a844c88f5c47bf914706af9bc
diff --git a/java/res/drawable-hdpi/keyboard_hint_0.9.png b/java/res/drawable-hdpi/keyboard_hint_0.9.png
new file mode 100644
index 0000000..271264e
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_hint_0.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_hint_1.9.png b/java/res/drawable-hdpi/keyboard_hint_1.9.png
new file mode 100644
index 0000000..eaf3742
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_hint_1.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_hint_2.9.png b/java/res/drawable-hdpi/keyboard_hint_2.9.png
new file mode 100644
index 0000000..8a16571
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_hint_2.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_hint_3.9.png b/java/res/drawable-hdpi/keyboard_hint_3.9.png
new file mode 100644
index 0000000..34b5011
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_hint_3.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_hint_4.9.png b/java/res/drawable-hdpi/keyboard_hint_4.9.png
new file mode 100644
index 0000000..d4cc250
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_hint_4.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_hint_5.9.png b/java/res/drawable-hdpi/keyboard_hint_5.9.png
new file mode 100644
index 0000000..6a054b4
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_hint_5.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_hint_6.9.png b/java/res/drawable-hdpi/keyboard_hint_6.9.png
new file mode 100644
index 0000000..66e9140
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_hint_6.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_hint_7.9.png b/java/res/drawable-hdpi/keyboard_hint_7.9.png
new file mode 100644
index 0000000..5eae24f
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_hint_7.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_hint_8.9.png b/java/res/drawable-hdpi/keyboard_hint_8.9.png
new file mode 100644
index 0000000..ea7f512
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_hint_8.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_hint_9.9.png b/java/res/drawable-hdpi/keyboard_hint_9.9.png
new file mode 100644
index 0000000..0bf85de
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_hint_9.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_0.9.png b/java/res/drawable-mdpi/keyboard_hint_0.9.png
new file mode 100644
index 0000000..271264e
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_0.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_1.9.png b/java/res/drawable-mdpi/keyboard_hint_1.9.png
new file mode 100644
index 0000000..eaf3742
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_1.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_2.9.png b/java/res/drawable-mdpi/keyboard_hint_2.9.png
new file mode 100644
index 0000000..8a16571
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_2.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_3.9.png b/java/res/drawable-mdpi/keyboard_hint_3.9.png
new file mode 100644
index 0000000..34b5011
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_3.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_4.9.png b/java/res/drawable-mdpi/keyboard_hint_4.9.png
new file mode 100644
index 0000000..d4cc250
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_4.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_5.9.png b/java/res/drawable-mdpi/keyboard_hint_5.9.png
new file mode 100644
index 0000000..6a054b4
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_5.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_6.9.png b/java/res/drawable-mdpi/keyboard_hint_6.9.png
new file mode 100644
index 0000000..66e9140
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_6.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_7.9.png b/java/res/drawable-mdpi/keyboard_hint_7.9.png
new file mode 100644
index 0000000..5eae24f
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_7.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_8.9.png b/java/res/drawable-mdpi/keyboard_hint_8.9.png
new file mode 100644
index 0000000..ea7f512
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_8.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_9.9.png b/java/res/drawable-mdpi/keyboard_hint_9.9.png
new file mode 100644
index 0000000..0bf85de
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_9.9.png
Binary files differ
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboard.java b/java/src/com/android/inputmethod/latin/LatinKeyboard.java
index 4e139e8..8b89f39 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboard.java
@@ -63,6 +63,9 @@
     private Key mF1Key;
     private Key mSpaceKey;
     private Key m123Key;
+    private final int NUMBER_HINT_COUNT = 10;
+    private Key[] mNumberHintKeys;
+    private Drawable[] mNumberHintIcons = new Drawable[NUMBER_HINT_COUNT];
     private int mSpaceKeyIndex = -1;
     private int mSpaceDragStartX;
     private int mSpaceDragLastDiff;
@@ -129,6 +132,21 @@
         mIsAlphaKeyboard = xmlLayoutResId == R.xml.kbd_qwerty
                 || xmlLayoutResId == R.xml.kbd_qwerty_black;
         mSpaceKeyIndex = indexOf(' ');
+        initializeNumberHintResources(context);
+    }
+
+    private void initializeNumberHintResources(Context context) {
+        final Resources res = context.getResources();
+        mNumberHintIcons[0] = res.getDrawable(R.drawable.keyboard_hint_0);
+        mNumberHintIcons[1] = res.getDrawable(R.drawable.keyboard_hint_1);
+        mNumberHintIcons[2] = res.getDrawable(R.drawable.keyboard_hint_2);
+        mNumberHintIcons[3] = res.getDrawable(R.drawable.keyboard_hint_3);
+        mNumberHintIcons[4] = res.getDrawable(R.drawable.keyboard_hint_4);
+        mNumberHintIcons[5] = res.getDrawable(R.drawable.keyboard_hint_5);
+        mNumberHintIcons[6] = res.getDrawable(R.drawable.keyboard_hint_6);
+        mNumberHintIcons[7] = res.getDrawable(R.drawable.keyboard_hint_7);
+        mNumberHintIcons[8] = res.getDrawable(R.drawable.keyboard_hint_8);
+        mNumberHintIcons[9] = res.getDrawable(R.drawable.keyboard_hint_9);
     }
 
     @Override
@@ -150,6 +168,23 @@
             m123Label = key.label;
             break;
         }
+
+        // For number hints on the upper-right corner of key
+        if (mNumberHintKeys == null) {
+            // NOTE: This protected method is being called from the base class constructor before
+            // mNumberHintKeys gets initialized.
+            mNumberHintKeys = new Key[NUMBER_HINT_COUNT];
+        }
+        int hintNumber = -1;
+        if (LatinKeyboardBaseView.isNumberAtLeftmostPopupChar(key)) {
+            hintNumber = key.popupCharacters.charAt(0) - '0';
+        } else if (LatinKeyboardBaseView.isNumberAtRightmostPopupChar(key)) {
+            hintNumber = key.popupCharacters.charAt(key.popupCharacters.length() - 1) - '0';
+        }
+        if (hintNumber >= 0 && hintNumber <= 9) {
+            mNumberHintKeys[hintNumber] = key;
+        }
+
         return key;
     }
 
@@ -293,6 +328,7 @@
         if (mSpaceKey != null) {
             updateSpaceBarForLocale(isAutoCompletion, isBlack);
         }
+        updateNumberHintKeys();
     }
 
     private void setDefaultBounds(Drawable drawable) {
@@ -340,6 +376,14 @@
         return mSpaceKey;
     }
 
+    private void updateNumberHintKeys() {
+        for (int i = 0; i < mNumberHintKeys.length; ++i) {
+            if (mNumberHintKeys[i] != null) {
+                mNumberHintKeys[i].icon = mNumberHintIcons[i];
+            }
+        }
+    }
+
     private void updateSpaceBarForLocale(boolean isAutoCompletion, boolean isBlack) {
         // If application locales are explicitly selected.
         if (mLocale != null) {
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
index a2db129..26b3c05 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
@@ -797,6 +797,7 @@
             canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop);
             keyBackground.draw(canvas);
 
+            boolean shouldDrawIcon = true;
             if (label != null) {
                 // For characters, use large font. For labels like "Done", use small font.
                 if (label.length() > 1 && key.codes.length < 2) {
@@ -817,14 +818,24 @@
                     paint);
                 // Turn off drop shadow
                 paint.setShadowLayer(0, 0, 0, 0);
-            } else if (key.icon != null) {
+
+                // Usually don't draw icon if label is not null, but we draw icon for the number
+                // hint.
+                shouldDrawIcon = isNumberAtEdgeOfPopupChars(key);
+            }
+            if (key.icon != null && shouldDrawIcon) {
+                // Special handing for the upper-right number hint icons
+                final int drawableWidth = isNumberAtEdgeOfPopupChars(key) ?
+                        key.width : key.icon.getIntrinsicWidth();
+                final int drawableHeight = isNumberAtEdgeOfPopupChars(key) ?
+                        key.height : key.icon.getIntrinsicHeight();
+
                 final int drawableX = (key.width - padding.left - padding.right
-                                - key.icon.getIntrinsicWidth()) / 2 + padding.left;
+                        - drawableWidth) / 2 + padding.left;
                 final int drawableY = (key.height - padding.top - padding.bottom
-                        - key.icon.getIntrinsicHeight()) / 2 + padding.top;
+                        - drawableHeight) / 2 + padding.top;
                 canvas.translate(drawableX, drawableY);
-                key.icon.setBounds(0, 0,
-                        key.icon.getIntrinsicWidth(), key.icon.getIntrinsicHeight());
+                key.icon.setBounds(0, 0, drawableWidth, drawableHeight);
                 key.icon.draw(canvas);
                 canvas.translate(-drawableX, -drawableY);
             }
@@ -885,7 +896,8 @@
         Key key = tracker.getKey(keyIndex);
         if (key == null)
             return;
-        if (key.icon != null) {
+        // Should not draw number hint icons
+        if (key.icon != null && !isNumberAtEdgeOfPopupChars(key)) {
             mPreviewText.setCompoundDrawables(null, null, null,
                     key.iconPreview != null ? key.iconPreview : key.icon);
             mPreviewText.setText(null);
@@ -1100,12 +1112,8 @@
         }
 
         // HACK: Have the leftmost number in the popup characters right above the key
-        boolean isNumberAtLeftmost = false;
-        if (popupKey.popupCharacters != null && popupKey.popupCharacters.length() > 1) {
-            char leftmostChar = popupKey.popupCharacters.charAt(0);
-            isNumberAtLeftmost = leftmostChar >= '0' && leftmostChar <= '9';
-        }
-
+        boolean isNumberAtLeftmost =
+                hasMultiplePopupChars(popupKey) && isNumberAtLeftmostPopupChar(popupKey);
         int popupX = popupKey.x + mWindowOffset[0];
         int popupY = popupKey.y + mWindowOffset[1];
         if (isNumberAtLeftmost) {
@@ -1151,6 +1159,37 @@
         return true;
     }
 
+    private static boolean hasMultiplePopupChars(Key key) {
+        if (key.popupCharacters != null && key.popupCharacters.length() > 1) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean isNumberAtEdgeOfPopupChars(Key key) {
+        return isNumberAtLeftmostPopupChar(key) || isNumberAtRightmostPopupChar(key);
+    }
+
+    /* package */ static boolean isNumberAtLeftmostPopupChar(Key key) {
+        if (key.popupCharacters != null && key.popupCharacters.length() > 0
+                && isAsciiDigit(key.popupCharacters.charAt(0))) {
+            return true;
+        }
+        return false;
+    }
+
+    /* package */ static boolean isNumberAtRightmostPopupChar(Key key) {
+        if (key.popupCharacters != null && key.popupCharacters.length() > 0
+                && isAsciiDigit(key.popupCharacters.charAt(key.popupCharacters.length() - 1))) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean isAsciiDigit(char c) {
+        return (c < 0x80) && Character.isDigit(c);
+    }
+
     private MotionEvent generateMiniKeyboardMotionEvent(int action, int x, int y, long eventTime) {
         return MotionEvent.obtain(mMiniKeyboardPopupTime, eventTime, action,
                     x - mMiniKeyboardOriginX, y - mMiniKeyboardOriginY, 0);
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardView.java
index c17d7c5..a45bb21 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboardView.java
@@ -24,6 +24,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 
@@ -101,7 +102,7 @@
         if (keyboard.isShifted()
                 && keyboard instanceof LatinKeyboard
                 && ((LatinKeyboard) keyboard).isAlphaKeyboard()
-                && label != null && label.length() < 3
+                && !TextUtils.isEmpty(label) && label.length() < 3
                 && Character.isLowerCase(label.charAt(0))) {
             label = label.toString().toUpperCase();
         }