Filter non-ascii popup charcters from password keyboard

Change-Id: I10885efd317770f892165b6bb059313abf241436
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 68868f1..5b34dd5 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -33,7 +33,6 @@
 import com.android.inputmethod.keyboard.internal.Row;
 import com.android.inputmethod.latin.R;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -292,13 +291,18 @@
             mY = y;
             mWidth = keyWidth - mGap;
 
-            final CharSequence[] popupCharacters = style.getTextArray(keyAttr,
-                    R.styleable.Keyboard_Key_popupCharacters);
+            CharSequence[] popupCharacters = style.getTextArray(
+                    keyAttr, R.styleable.Keyboard_Key_popupCharacters);
+            if (mKeyboard.mId.mPasswordInput) {
+                popupCharacters = PopupCharactersParser.filterOut(
+                        res, popupCharacters, PopupCharactersParser.NON_ASCII_FILTER);
+            }
             // In Arabic symbol layouts, we'd like to keep digits in popup characters regardless of
             // config_digit_popup_characters_enabled.
             if (mKeyboard.mId.isAlphabetKeyboard() && !res.getBoolean(
                     R.bool.config_digit_popup_characters_enabled)) {
-                mPopupCharacters = filterOutDigitPopupCharacters(popupCharacters);
+                mPopupCharacters = PopupCharactersParser.filterOut(
+                        res, popupCharacters, PopupCharactersParser.DIGIT_FILTER);
             } else {
                 mPopupCharacters = popupCharacters;
             }
@@ -402,36 +406,6 @@
         return (mLabelOption & LABEL_OPTION_HAS_HINT_LABEL) != 0;
     }
 
-    private static boolean isDigitPopupCharacter(CharSequence label) {
-        return label != null && label.length() == 1 && Character.isDigit(label.charAt(0));
-    }
-
-    private static CharSequence[] filterOutDigitPopupCharacters(CharSequence[] popupCharacters) {
-        if (popupCharacters == null || popupCharacters.length < 1)
-            return null;
-        if (popupCharacters.length == 1 && isDigitPopupCharacter(
-                PopupCharactersParser.getLabel(popupCharacters[0].toString())))
-            return null;
-        ArrayList<CharSequence> filtered = null;
-        for (int i = 0; i < popupCharacters.length; i++) {
-            final CharSequence popupSpec = popupCharacters[i];
-            if (isDigitPopupCharacter(PopupCharactersParser.getLabel(popupSpec.toString()))) {
-                if (filtered == null) {
-                    filtered = new ArrayList<CharSequence>();
-                    for (int j = 0; j < i; j++)
-                        filtered.add(popupCharacters[j]);
-                }
-            } else if (filtered != null) {
-                filtered.add(popupSpec);
-            }
-        }
-        if (filtered == null)
-            return popupCharacters;
-        if (filtered.size() == 0)
-            return null;
-        return filtered.toArray(new CharSequence[filtered.size()]);
-    }
-
     public Drawable getIcon() {
         return mIcon;
     }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PopupCharactersParser.java b/java/src/com/android/inputmethod/keyboard/internal/PopupCharactersParser.java
index 8276f5d..032489e 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PopupCharactersParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PopupCharactersParser.java
@@ -23,6 +23,8 @@
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.latin.R;
 
+import java.util.ArrayList;
+
 /**
  * String parser of popupCharacters attribute of Key.
  * The string is comma separated texts each of which represents one popup key.
@@ -182,4 +184,54 @@
             super(message);
         }
     }
+
+    public interface CodeFilter {
+        public boolean shouldFilterOut(int code);
+    }
+
+    public static final CodeFilter DIGIT_FILTER = new CodeFilter() {
+        @Override
+        public boolean shouldFilterOut(int code) {
+            return Character.isDigit(code);
+        }
+    };
+
+    public static final CodeFilter NON_ASCII_FILTER = new CodeFilter() {
+        @Override
+        public boolean shouldFilterOut(int code) {
+            return code < 0x20 || code > 0x7e;
+        }
+    };
+
+    public static CharSequence[] filterOut(Resources res, CharSequence[] popupCharacters,
+            CodeFilter filter) {
+        if (popupCharacters == null || popupCharacters.length < 1) {
+            return null;
+        }
+        if (popupCharacters.length == 1
+                && filter.shouldFilterOut(getCode(res, popupCharacters[0].toString()))) {
+            return null;
+        }
+        ArrayList<CharSequence> filtered = null;
+        for (int i = 0; i < popupCharacters.length; i++) {
+            final CharSequence popupSpec = popupCharacters[i];
+            if (filter.shouldFilterOut(getCode(res, popupSpec.toString()))) {
+                if (filtered == null) {
+                    filtered = new ArrayList<CharSequence>();
+                    for (int j = 0; j < i; j++) {
+                        filtered.add(popupCharacters[j]);
+                    }
+                }
+            } else if (filtered != null) {
+                filtered.add(popupSpec);
+            }
+        }
+        if (filtered == null) {
+            return popupCharacters;
+        }
+        if (filtered.size() == 0) {
+            return null;
+        }
+        return filtered.toArray(new CharSequence[filtered.size()]);
+    }
 }