Merge "Fix testCharacterTableIsPresent to use BinaryDictUtils.getDictFile"
diff --git a/java/res/xml-sw600dp/rows_nepali_romanized.xml b/java/res/xml-sw600dp/rows_nepali_romanized.xml
index fe73fbd..41cd2f9 100644
--- a/java/res/xml-sw600dp/rows_nepali_romanized.xml
+++ b/java/res/xml-sw600dp/rows_nepali_romanized.xml
@@ -39,7 +39,7 @@
             latin:keyWidth="fillRight" />
     </Row>
     <Row
-        latin:keyWidth="8.182%p"
+        latin:keyWidth="8.0%p"
         latin:keyLabelFlags="fontNormal"
     >
         <Key
@@ -47,6 +47,9 @@
             latin:keyWidth="10.0%p" />
         <include latin:keyboardLayout="@xml/rowkeys_nepali_romanized3" />
         <include latin:keyboardLayout="@xml/keys_exclamation_question" />
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="fillRight" />
     </Row>
     <include latin:keyboardLayout="@xml/row_qwerty4" />
 </merge>
diff --git a/java/res/xml-sw600dp/rows_nepali_traditional.xml b/java/res/xml-sw600dp/rows_nepali_traditional.xml
index e56271f..d23ca24 100644
--- a/java/res/xml-sw600dp/rows_nepali_traditional.xml
+++ b/java/res/xml-sw600dp/rows_nepali_traditional.xml
@@ -45,8 +45,8 @@
         <Key
             latin:keyStyle="shiftKeyStyle"
             latin:keyWidth="10.0%p" />
-        <include latin:keyboardLayout="@xml/rowkeys_nepali_traditional3_left6" />
-        <include latin:keyboardLayout="@xml/rowkeys_nepali_traditional3_right5" />
-    </Row>
+        <include latin:keyboardLayout="@xml/rowkeys_nepali_traditional3" />
+        <include latin:keyboardLayout="@xml/keys_exclamation_question" />
+        </Row>
     <include latin:keyboardLayout="@xml/row_qwerty4" />
 </merge>
diff --git a/java/res/xml/key_period.xml b/java/res/xml/key_period.xml
index 10325ef..5b59cff 100644
--- a/java/res/xml/key_period.xml
+++ b/java/res/xml/key_period.xml
@@ -23,21 +23,6 @@
 >
     <switch>
         <case
-            latin:languageCode="ne"
-            latin:keyboardLayoutSet="nepali_traditional"
-        >
-            <!-- Because the font rendering system prior to API version 16 can't automatically
-                 render dotted circle for incomplete combining letter of some scripts, different
-                 set of Key definitions are needed based on the API version. -->
-            <include
-                latin:keyboardLayout="@xml/keystyle_devanagari_sign_virama" />
-            <Key
-                latin:keyStyle="baseKeyDevanagariSignVirama"
-                latin:keyLabelFlags="hasPopupHint"
-                latin:moreKeys="!text/morekeys_punctuation"
-                latin:backgroundType="functional" />
-        </case>
-        <case
             latin:keyboardLayoutSet="dvorak"
         >
             <Key
diff --git a/java/res/xml/rowkeys_nepali_romanized3.xml b/java/res/xml/rowkeys_nepali_romanized3.xml
index 24f5908..c6a1e28 100644
--- a/java/res/xml/rowkeys_nepali_romanized3.xml
+++ b/java/res/xml/rowkeys_nepali_romanized3.xml
@@ -43,11 +43,6 @@
             <Key latin:keyStyle="baseKeyDevanagariSignAnusvara" />
             <!-- U+0919: "ङ" DEVANAGARI LETTER NGA -->
             <Key latin:keySpec="&#x0919;" />
-            <!-- Because the font rendering system prior to API version 16 can't automatically
-                 render dotted circle for incomplete combining letter of some scripts, different
-                 set of Key definitions are needed based on the API version. -->
-            <include latin:keyboardLayout="@xml/keystyle_devanagari_sign_virama" />
-            <Key latin:keyStyle="baseKeyDevanagariSignVirama" />
         </case>
         <default>
             <!-- U+0937: "ष" DEVANAGARI LETTER SSA -->
@@ -64,16 +59,14 @@
             <Key latin:keySpec="&#x0928;" />
             <!-- U+092E: "म" DEVANAGARI LETTER MA -->
             <Key latin:keySpec="&#x092E;" />
-            <!-- U+0964: "।" DEVANAGARI DANDA
-                 U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
-            <Key
-                latin:keySpec="&#x0964;"
-                latin:moreKeys="&#x093D;" />
             <!-- Because the font rendering system prior to API version 16 can't automatically
                  render dotted circle for incomplete combining letter of some scripts, different
                  set of Key definitions are needed based on the API version. -->
             <include latin:keyboardLayout="@xml/keystyle_devanagari_sign_virama" />
-            <Key latin:keyStyle="baseKeyDevanagariSignVirama" />
+            <!-- U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+            <Key
+                latin:keyStyle="baseKeyDevanagariSignVirama"
+                latin:moreKeys="&#x093D;" />
         </default>
     </switch>
 </merge>
diff --git a/java/res/xml/rowkeys_nepali_traditional3_right5.xml b/java/res/xml/rowkeys_nepali_traditional3.xml
similarity index 62%
rename from java/res/xml/rowkeys_nepali_traditional3_right5.xml
rename to java/res/xml/rowkeys_nepali_traditional3.xml
index c7c73a4..c43c593 100644
--- a/java/res/xml/rowkeys_nepali_traditional3_right5.xml
+++ b/java/res/xml/rowkeys_nepali_traditional3.xml
@@ -21,6 +21,27 @@
 <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
     <switch>
         <case latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted">
+            <!-- U+0915/U+094D: "क्" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA -->
+            <Key
+                latin:keySpec="&#x0915;&#x094D;"
+                latin:keyLabelFlags="followKeyLetterRatio" />
+            <!-- U+0939/U+094D/U+092E: "ह्म" DEVANAGARI LETTER HA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER MA -->
+            <Key
+                latin:keySpec="&#x0939;&#x094D;&#x092E;"
+                latin:keyLabelFlags="followKeyLetterRatio" />
+            <!-- U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R -->
+            <Key latin:keySpec="&#x090B;" />
+            <!-- U+0950: "ॐ" DEVANAGARI OM -->
+            <Key latin:keySpec="&#x0950;" />
+            <!-- Because the font rendering system prior to API version 16 can't automatically
+                 render dotted circle for incomplete combining letter of some scripts, different
+                 set of Key definitions are needed based on the API version. -->
+            <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_au" />
+            <Key latin:keyStyle="baseKeyDevanagariVowelSignAu" />
+            <!-- U+0926/U+094D/U+092F: "द्य" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER YA -->
+            <Key
+                latin:keySpec="&#x0926;&#x094D;&#x092F;"
+                latin:keyLabelFlags="followKeyLetterRatio" />
             <!-- Because the font rendering system prior to API version 16 can't automatically
                  render dotted circle for incomplete combining letter of some scripts, different
                  set of Key definitions are needed based on the API version. -->
@@ -33,44 +54,36 @@
                  set of Key definitions are needed based on the API version. -->
             <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ai" />
             <Key latin:keyStyle="baseKeyDevanagariVowelSignAi" />
-            <!-- U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U -->
-            <Key
-                latin:keySpec="&#x0930;&#x0941;"
-                latin:moreKeys="!"
-                latin:keyLabelFlags="followKeyLetterRatio" />
-            <Key
-                latin:keySpec="\?"
-                latin:keyLabelFlags="fontDefault" />
         </case>
         <default>
-            <!-- Because the font rendering system prior to API version 16 can't automatically
-                 render dotted circle for incomplete combining letter of some scripts, different
-                 set of Key definitions are needed based on the API version. -->
-            <include latin:keyboardLayout="@xml/keystyle_devanagari_sign_visarga" />
-            <!-- U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
-            <Key
-                latin:keyStyle="baseKeyDevanagariSignVisarga"
-                latin:moreKeys="&#x093D;" />
+            <!-- U+0936: "श" DEVANAGARI LETTER SHA -->
+            <Key latin:keySpec="&#x0936;" />
+            <!-- U+0939: "ह" DEVANAGARI LETTER HA -->
+            <Key latin:keySpec="&#x0939;" />
+            <!-- U+0905: "अ" DEVANAGARI LETTER A -->
+            <Key latin:keySpec="&#x0905;" />
+            <!-- U+0916: "ख" DEVANAGARI LETTER KHA -->
+            <Key latin:keySpec="&#x0916;" />
+            <!-- U+0926: "द" DEVANAGARI LETTER DA -->
+            <Key latin:keySpec="&#x0926;" />
+            <!-- U+0932: "ल" DEVANAGARI LETTER LA -->
+            <Key latin:keySpec="&#x0932;" />
             <!-- Because the font rendering system prior to API version 16 can't automatically
                  render dotted circle for incomplete combining letter of some scripts, different
                  set of Key definitions are needed based on the API version. -->
             <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_e" />
-            <!-- Override more keys with empty definition -->
-            <key-style latin:styleName="moreKeysDevanagariVowelSignE" />
             <Key latin:keyStyle="baseKeyDevanagariVowelSignE" />
-            <!-- U+0964: "।" DEVANAGARI DANDA -->
-            <Key latin:keySpec="&#x0964;" />
-            <!-- U+0930: "र" DEVANAGARI LETTER RA -->
-            <Key
-                latin:keySpec="&#x0930;"
-                latin:moreKeys="!" />
             <!-- Because the font rendering system prior to API version 16 can't automatically
                  render dotted circle for incomplete combining letter of some scripts, different
                  set of Key definitions are needed based on the API version. -->
-            <include latin:keyboardLayout="@xml/keystyle_devanagari_sign_virama" />
+            <include
+                latin:keyboardLayout="@xml/keystyle_devanagari_sign_virama" />
+            <Key latin:keyStyle="baseKeyDevanagariSignVirama" />
+            <!-- U+0930: "र" DEVANAGARI LETTER RA
+                 U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U -->
             <Key
-                latin:keyStyle="baseKeyDevanagariSignVirama"
-                latin:moreKeys="\?" />
+                latin:keySpec="&#x0930;"
+                latin:moreKeys="&#x0930;&#x0941;" />
         </default>
     </switch>
 </merge>
diff --git a/java/res/xml/rowkeys_nepali_traditional3_left6.xml b/java/res/xml/rowkeys_nepali_traditional3_left6.xml
deleted file mode 100644
index ade2787..0000000
--- a/java/res/xml/rowkeys_nepali_traditional3_left6.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2013, The Android Open Source Project
-**
-** 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.
-*/
--->
-
-<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
-    <switch>
-        <case latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted">
-            <!-- U+0915/U+094D: "क्" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA -->
-            <Key
-                latin:keySpec="&#x0915;&#x094D;"
-                latin:keyLabelFlags="followKeyLetterRatio" />
-            <!-- U+0939/U+094D/U+092E: "ह्म" DEVANAGARI LETTER HA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER MA -->
-            <Key
-                latin:keySpec="&#x0939;&#x094D;&#x092E;"
-                latin:keyLabelFlags="followKeyLetterRatio" />
-            <!-- U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R -->
-            <Key latin:keySpec="&#x090B;" />
-            <!-- U+0950: "ॐ" DEVANAGARI OM -->
-            <Key latin:keySpec="&#x0950;" />
-            <!-- Because the font rendering system prior to API version 16 can't automatically
-                 render dotted circle for incomplete combining letter of some scripts, different
-                 set of Key definitions are needed based on the API version. -->
-            <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_au" />
-            <Key latin:keyStyle="baseKeyDevanagariVowelSignAu" />
-            <!-- U+0926/U+094D/U+092F: "द्य" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER YA -->
-            <Key
-                latin:keySpec="&#x0926;&#x094D;&#x092F;"
-                latin:keyLabelFlags="followKeyLetterRatio" />
-        </case>
-        <default>
-            <!-- U+0936: "श" DEVANAGARI LETTER SHA -->
-            <Key latin:keySpec="&#x0936;" />
-            <!-- U+0939: "ह" DEVANAGARI LETTER HA -->
-            <Key latin:keySpec="&#x0939;" />
-            <!-- U+0905: "अ" DEVANAGARI LETTER A -->
-            <Key latin:keySpec="&#x0905;" />
-            <!-- U+0916: "ख" DEVANAGARI LETTER KHA -->
-            <Key latin:keySpec="&#x0916;" />
-            <!-- U+0926: "द" DEVANAGARI LETTER DA -->
-            <Key latin:keySpec="&#x0926;" />
-            <!-- U+0932: "ल" DEVANAGARI LETTER LA -->
-            <Key latin:keySpec="&#x0932;" />
-        </default>
-    </switch>
-</merge>
diff --git a/java/res/xml/rowkeys_nepali_traditional3_right3.xml b/java/res/xml/rowkeys_nepali_traditional3_right3.xml
deleted file mode 100644
index 4db438d..0000000
--- a/java/res/xml/rowkeys_nepali_traditional3_right3.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2013, The Android Open Source Project
-**
-** 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.
-*/
--->
-
-<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
-    <switch>
-        <case latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted">
-            <!-- Because the font rendering system prior to API version 16 can't automatically
-                 render dotted circle for incomplete combining letter of some scripts, different
-                 set of Key definitions are needed based on the API version. -->
-            <include latin:keyboardLayout="@xml/keystyle_devanagari_sign_anusvara" />
-            <Key latin:keyStyle="baseKeyDevanagariSignAnusvara" />
-            <!-- U+0919: "ङ" DEVANAGARI LETTER NGA -->
-            <Key latin:keySpec="&#x0919;" />
-            <!-- Because the font rendering system prior to API version 16 can't automatically
-                 render dotted circle for incomplete combining letter of some scripts, different
-                 set of Key definitions are needed based on the API version. -->
-            <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ai" />
-            <Key latin:keyStyle="baseKeyDevanagariVowelSignAi" />
-        </case>
-        <default>
-            <!-- Because the font rendering system prior to API version 16 can't automatically
-                 render dotted circle for incomplete combining letter of some scripts, different
-                 set of Key definitions are needed based on the API version. -->
-            <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_e" />
-            <Key latin:keyStyle="baseKeyDevanagariVowelSignE" />
-            <!-- U+0964: "।" DEVANAGARI DANDA -->
-            <Key latin:keySpec="&#x0964;" />
-            <!-- U+0930: "र" DEVANAGARI LETTER RA
-                 U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U -->
-            <Key
-                latin:keySpec="&#x0930;"
-                latin:moreKeys="&#x0930;&#x0941;" />
-        </default>
-    </switch>
-</merge>
diff --git a/java/res/xml/rows_nepali_romanized.xml b/java/res/xml/rows_nepali_romanized.xml
index daca3ee..26737ec 100644
--- a/java/res/xml/rows_nepali_romanized.xml
+++ b/java/res/xml/rows_nepali_romanized.xml
@@ -33,16 +33,18 @@
         <include latin:keyboardLayout="@xml/rowkeys_nepali_romanized2" />
     </Row>
     <Row
-        latin:keyWidth="8.711%p"
+        latin:keyWidth="8.75%p"
         latin:keyLabelFlags="fontNormal"
     >
         <Key
             latin:keyStyle="shiftKeyStyle"
-            latin:keyWidth="10.8%p" />
+            latin:keyWidth="15%p"
+            latin:visualInsetsRight="1%p" />
         <include latin:keyboardLayout="@xml/rowkeys_nepali_romanized3" />
         <Key
             latin:keyStyle="deleteKeyStyle"
-            latin:keyWidth="fillRight" />
+            latin:keyWidth="fillRight"
+            latin:visualInsetsLeft="1%p" />
     </Row>
     <include latin:keyboardLayout="@xml/row_qwerty4" />
 </merge>
diff --git a/java/res/xml/rows_nepali_traditional.xml b/java/res/xml/rows_nepali_traditional.xml
index edcc73a..e2e710c 100644
--- a/java/res/xml/rows_nepali_traditional.xml
+++ b/java/res/xml/rows_nepali_traditional.xml
@@ -40,8 +40,7 @@
         <Key
             latin:keyStyle="shiftKeyStyle"
             latin:keyWidth="10.8%p" />
-        <include latin:keyboardLayout="@xml/rowkeys_nepali_traditional3_left6" />
-        <include latin:keyboardLayout="@xml/rowkeys_nepali_traditional3_right3" />
+        <include latin:keyboardLayout="@xml/rowkeys_nepali_traditional3" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 85dfea4..d35c8fa 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -108,10 +108,9 @@
         mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping);
         mIconsSet = params.mIconsSet;
 
-        mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(),
-                params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
-                mMostCommonKeyWidth, mMostCommonKeyHeight, mSortedKeys,
-                params.mTouchPositionCorrection);
+        mProximityInfo = new ProximityInfo(params.GRID_WIDTH, params.GRID_HEIGHT,
+                mOccupiedWidth, mOccupiedHeight, mMostCommonKeyWidth, mMostCommonKeyHeight,
+                mSortedKeys, params.mTouchPositionCorrection);
         mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 246d11b..7f2957f 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -254,8 +254,9 @@
     }
 
     public void onToggleEmojiKeyboard() {
-        if (mKeyboardLayoutSet == null || !isShowingEmojiPalettes()) {
-            mLatinIME.startShowingInputView();
+        final boolean needsToLoadKeyboard = (mKeyboardLayoutSet == null);
+        if (needsToLoadKeyboard || !isShowingEmojiPalettes()) {
+            mLatinIME.startShowingInputView(needsToLoadKeyboard);
             setEmojiKeyboard();
         } else {
             mLatinIME.stopShowingInputView();
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index c19cd67..9c5abcd 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -52,18 +52,11 @@
     private final int mMostCommonKeyHeight;
     private final List<Key> mSortedKeys;
     private final List<Key>[] mGridNeighbors;
-    private final String mLocaleStr;
 
     @SuppressWarnings("unchecked")
-    ProximityInfo(final String localeStr, final int gridWidth, final int gridHeight,
-            final int minWidth, final int height, final int mostCommonKeyWidth,
-            final int mostCommonKeyHeight, final List<Key> sortedKeys,
+    ProximityInfo(final int gridWidth, final int gridHeight, final int minWidth, final int height,
+            final int mostCommonKeyWidth, final int mostCommonKeyHeight, final List<Key> sortedKeys,
             final TouchPositionCorrection touchPositionCorrection) {
-        if (TextUtils.isEmpty(localeStr)) {
-            mLocaleStr = "";
-        } else {
-            mLocaleStr = localeStr;
-        }
         mGridWidth = gridWidth;
         mGridHeight = gridHeight;
         mGridSize = mGridWidth * mGridHeight;
@@ -89,11 +82,10 @@
     }
 
     // TODO: Stop passing proximityCharsArray
-    private static native long setProximityInfoNative(String locale,
-            int displayWidth, int displayHeight, int gridWidth, int gridHeight,
-            int mostCommonKeyWidth, int mostCommonKeyHeight, int[] proximityCharsArray,
-            int keyCount, int[] keyXCoordinates, int[] keyYCoordinates, int[] keyWidths,
-            int[] keyHeights, int[] keyCharCodes, float[] sweetSpotCenterXs,
+    private static native long setProximityInfoNative(int displayWidth, int displayHeight,
+            int gridWidth, int gridHeight, int mostCommonKeyWidth, int mostCommonKeyHeight,
+            int[] proximityCharsArray, int keyCount, int[] keyXCoordinates, int[] keyYCoordinates,
+            int[] keyWidths, int[] keyHeights, int[] keyCharCodes, float[] sweetSpotCenterXs,
             float[] sweetSpotCenterYs, float[] sweetSpotRadii);
 
     private static native void releaseProximityInfoNative(long nativeProximityInfo);
@@ -221,10 +213,10 @@
         }
 
         // TODO: Stop passing proximityCharsArray
-        return setProximityInfoNative(mLocaleStr, mKeyboardMinWidth, mKeyboardHeight,
-                mGridWidth, mGridHeight, mMostCommonKeyWidth, mMostCommonKeyHeight,
-                proximityCharsArray, keyCount, keyXCoordinates, keyYCoordinates, keyWidths,
-                keyHeights, keyCharCodes, sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
+        return setProximityInfoNative(mKeyboardMinWidth, mKeyboardHeight, mGridWidth, mGridHeight,
+                mMostCommonKeyWidth, mMostCommonKeyHeight, proximityCharsArray, keyCount,
+                keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes,
+                sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
     }
 
     public long getNativeProximityInfo() {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
index 978194a..a81d7ea 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
@@ -136,37 +136,37 @@
         /*  50: 5 */ "additional_morekeys_symbols_8",
         /*  51: 5 */ "additional_morekeys_symbols_9",
         /*  52: 5 */ "additional_morekeys_symbols_0",
-        /*  53: 4 */ "morekeys_nordic_row2_11",
-        /*  54: 4 */ "morekeys_punctuation",
-        /*  55: 4 */ "keyspec_tablet_comma",
-        /*  56: 4 */ "morekeys_tablet_period",
-        /*  57: 3 */ "keyspec_swiss_row1_11",
-        /*  58: 3 */ "keyspec_swiss_row2_10",
-        /*  59: 3 */ "keyspec_swiss_row2_11",
-        /*  60: 3 */ "morekeys_swiss_row1_11",
-        /*  61: 3 */ "morekeys_swiss_row2_10",
-        /*  62: 3 */ "morekeys_swiss_row2_11",
-        /*  63: 3 */ "morekeys_star",
-        /*  64: 3 */ "keyspec_left_parenthesis",
-        /*  65: 3 */ "keyspec_right_parenthesis",
-        /*  66: 3 */ "keyspec_left_square_bracket",
-        /*  67: 3 */ "keyspec_right_square_bracket",
-        /*  68: 3 */ "keyspec_left_curly_bracket",
-        /*  69: 3 */ "keyspec_right_curly_bracket",
-        /*  70: 3 */ "keyspec_less_than",
-        /*  71: 3 */ "keyspec_greater_than",
-        /*  72: 3 */ "keyspec_less_than_equal",
-        /*  73: 3 */ "keyspec_greater_than_equal",
-        /*  74: 3 */ "keyspec_left_double_angle_quote",
-        /*  75: 3 */ "keyspec_right_double_angle_quote",
-        /*  76: 3 */ "keyspec_left_single_angle_quote",
-        /*  77: 3 */ "keyspec_right_single_angle_quote",
-        /*  78: 3 */ "keyspec_comma",
-        /*  79: 3 */ "morekeys_tablet_comma",
-        /*  80: 3 */ "keyspec_period",
-        /*  81: 3 */ "keyhintlabel_period",
-        /*  82: 3 */ "morekeys_period",
-        /*  83: 3 */ "keyspec_tablet_period",
+        /*  53: 5 */ "morekeys_tablet_period",
+        /*  54: 4 */ "morekeys_nordic_row2_11",
+        /*  55: 4 */ "morekeys_punctuation",
+        /*  56: 4 */ "keyspec_tablet_comma",
+        /*  57: 4 */ "keyspec_period",
+        /*  58: 4 */ "morekeys_period",
+        /*  59: 4 */ "keyspec_tablet_period",
+        /*  60: 3 */ "keyspec_swiss_row1_11",
+        /*  61: 3 */ "keyspec_swiss_row2_10",
+        /*  62: 3 */ "keyspec_swiss_row2_11",
+        /*  63: 3 */ "morekeys_swiss_row1_11",
+        /*  64: 3 */ "morekeys_swiss_row2_10",
+        /*  65: 3 */ "morekeys_swiss_row2_11",
+        /*  66: 3 */ "morekeys_star",
+        /*  67: 3 */ "keyspec_left_parenthesis",
+        /*  68: 3 */ "keyspec_right_parenthesis",
+        /*  69: 3 */ "keyspec_left_square_bracket",
+        /*  70: 3 */ "keyspec_right_square_bracket",
+        /*  71: 3 */ "keyspec_left_curly_bracket",
+        /*  72: 3 */ "keyspec_right_curly_bracket",
+        /*  73: 3 */ "keyspec_less_than",
+        /*  74: 3 */ "keyspec_greater_than",
+        /*  75: 3 */ "keyspec_less_than_equal",
+        /*  76: 3 */ "keyspec_greater_than_equal",
+        /*  77: 3 */ "keyspec_left_double_angle_quote",
+        /*  78: 3 */ "keyspec_right_double_angle_quote",
+        /*  79: 3 */ "keyspec_left_single_angle_quote",
+        /*  80: 3 */ "keyspec_right_single_angle_quote",
+        /*  81: 3 */ "keyspec_comma",
+        /*  82: 3 */ "morekeys_tablet_comma",
+        /*  83: 3 */ "keyhintlabel_period",
         /*  84: 3 */ "morekeys_question",
         /*  85: 2 */ "morekeys_h",
         /*  86: 2 */ "morekeys_w",
@@ -298,11 +298,16 @@
         // Label for "switch to symbols" key.
         /* keylabel_to_symbol */ "?123",
         /* additional_morekeys_symbols_1 ~ */
-        EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-        /* ~ morekeys_nordic_row2_11 */
+        EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+        /* ~ additional_morekeys_symbols_0 */
+        /* morekeys_tablet_period */ "!text/morekeys_tablet_punctuation",
+        /* morekeys_nordic_row2_11 */ EMPTY,
         /* morekeys_punctuation */ "!autoColumnOrder!8,\\,,?,!,#,!text/keyspec_right_parenthesis,!text/keyspec_left_parenthesis,/,;,',@,:,-,\",+,\\%,&",
         /* keyspec_tablet_comma */ ",",
-        /* morekeys_tablet_period */ "!text/morekeys_tablet_punctuation",
+        // Period key
+        /* keyspec_period */ ".",
+        /* morekeys_period */ "!text/morekeys_punctuation",
+        /* keyspec_tablet_period */ ".",
         /* keyspec_swiss_row1_11 ~ */
         EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
         /* ~ morekeys_swiss_row2_11 */
@@ -335,11 +340,7 @@
         // Comma key
         /* keyspec_comma */ ",",
         /* morekeys_tablet_comma */ EMPTY,
-        // Period key
-        /* keyspec_period */ ".",
         /* keyhintlabel_period */ EMPTY,
-        /* morekeys_period */ "!text/morekeys_punctuation",
-        /* keyspec_tablet_period */ ".",
         // U+00BF: "¿" INVERTED QUESTION MARK
         /* morekeys_question */ "\u00BF",
         /* morekeys_h ~ */
@@ -587,15 +588,17 @@
         // U+066B: "٫" ARABIC DECIMAL SEPARATOR
         // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
         /* additional_morekeys_symbols_0 */ "0,\u066B,\u066C",
+        /* morekeys_tablet_period */ "!text/morekeys_arabic_diacritics",
         /* morekeys_nordic_row2_11 */ null,
         /* morekeys_punctuation */ null,
         // U+061F: "؟" ARABIC QUESTION MARK
         // U+060C: "،" ARABIC COMMA
         // U+061B: "؛" ARABIC SEMICOLON
         /* keyspec_tablet_comma */ "\u060C",
-        /* morekeys_tablet_period */ "!text/morekeys_arabic_diacritics",
-        /* keyspec_swiss_row1_11 ~ */
-        null, null, null, null, null, null,
+        /* keyspec_period */ null,
+        /* morekeys_period */ "!text/morekeys_arabic_diacritics",
+        /* keyspec_tablet_period ~ */
+        null, null, null, null, null, null, null,
         /* ~ morekeys_swiss_row2_11 */
         // U+2605: "★" BLACK STAR
         // U+066D: "٭" ARABIC FIVE POINTED STAR
@@ -623,11 +626,8 @@
         // U+060C: "،" ARABIC COMMA
         /* keyspec_comma */ "\u060C",
         /* morekeys_tablet_comma */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,\",\'",
-        /* keyspec_period */ null,
         // U+0651: "ّ" ARABIC SHADDA
         /* keyhintlabel_period */ "\u0651",
-        /* morekeys_period */ "!text/morekeys_arabic_diacritics",
-        /* keyspec_tablet_period */ null,
         // U+00BF: "¿" INVERTED QUESTION MARK
         /* morekeys_question */ "?,\u00BF",
         /* morekeys_h ~ */
@@ -877,14 +877,14 @@
         /* morekeys_g ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null,
+        null, null, null, null, null, null, null, null,
         /* ~ morekeys_nordic_row2_11 */
         // U+00B7: "·" MIDDLE DOT
         /* morekeys_punctuation */ "!autoColumnOrder!9,\\,,?,!,\u00B7,#,),(,/,;,',@,:,-,\",+,\\%,&",
         /* keyspec_tablet_comma ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null, null, null, null,
+        null, null, null, null, null, null, null, null, null, null, null,
         /* ~ keyspec_south_slavic_row3_8 */
         /* morekeys_tablet_punctuation */ "!autoColumnOrder!8,\\,,',\u00B7,#,),(,/,;,@,:,-,\",+,\\%,&",
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
@@ -1038,8 +1038,8 @@
         /* morekeys_nordic_row2_10 */ "\u00E4",
         /* keyspec_east_slavic_row1_9 ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null, null, null,
-        /* ~ additional_morekeys_symbols_0 */
+        null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~ morekeys_tablet_period */
         // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
         /* morekeys_nordic_row2_11 */ "\u00F6",
     };
@@ -1096,8 +1096,8 @@
         /* morekeys_r ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null,
-        /* ~ morekeys_tablet_period */
+        null, null, null, null, null, null, null, null, null, null,
+        /* ~ keyspec_tablet_period */
         // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
         /* keyspec_swiss_row1_11 */ "\u00FC",
         // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
@@ -1378,7 +1378,7 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null,
+        null, null,
         /* ~ morekeys_nordic_row2_11 */
         // U+00A1: "¡" INVERTED EXCLAMATION MARK
         // U+00BF: "¿" INVERTED QUESTION MARK
@@ -1597,6 +1597,7 @@
         // U+066B: "٫" ARABIC DECIMAL SEPARATOR
         // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
         /* additional_morekeys_symbols_0 */ "0,\u066B,\u066C",
+        /* morekeys_tablet_period */ "!text/morekeys_arabic_diacritics",
         /* morekeys_nordic_row2_11 */ null,
         /* morekeys_punctuation */ null,
         // U+060C: "،" ARABIC COMMA
@@ -1605,9 +1606,10 @@
         // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
         // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
         /* keyspec_tablet_comma */ "\u060C",
-        /* morekeys_tablet_period */ "!text/morekeys_arabic_diacritics",
-        /* keyspec_swiss_row1_11 ~ */
-        null, null, null, null, null, null,
+        /* keyspec_period */ null,
+        /* morekeys_period */ "!text/morekeys_arabic_diacritics",
+        /* keyspec_tablet_period ~ */
+        null, null, null, null, null, null, null,
         /* ~ morekeys_swiss_row2_11 */
         // U+2605: "★" BLACK STAR
         // U+066D: "٭" ARABIC FIVE POINTED STAR
@@ -1629,11 +1631,8 @@
         // U+060C: "،" ARABIC COMMA
         /* keyspec_comma */ "\u060C",
         /* morekeys_tablet_comma */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,!text/keyspec_left_double_angle_quote,!text/keyspec_right_double_angle_quote",
-        /* keyspec_period */ null,
         // U+064B: "ً" ARABIC FATHATAN
         /* keyhintlabel_period */ "\u064B",
-        /* morekeys_period */ "!text/morekeys_arabic_diacritics",
-        /* keyspec_tablet_period */ null,
         // U+00BF: "¿" INVERTED QUESTION MARK
         /* morekeys_question */ "?,\u00BF",
         /* morekeys_h ~ */
@@ -1737,8 +1736,8 @@
         /* morekeys_nordic_row2_10 */ "\u00F8",
         /* keyspec_east_slavic_row1_9 ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null, null, null,
-        /* ~ additional_morekeys_symbols_0 */
+        null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~ morekeys_tablet_period */
         // U+00E6: "æ" LATIN SMALL LETTER AE
         /* morekeys_nordic_row2_11 */ "\u00E6",
     };
@@ -1800,8 +1799,9 @@
         /* morekeys_z ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~ morekeys_tablet_period */
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        null, null,
+        /* ~ keyspec_tablet_period */
         // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
         /* keyspec_swiss_row1_11 */ "\u00E8",
         // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
@@ -1921,17 +1921,12 @@
         /* additional_morekeys_symbols_8 */ "8",
         /* additional_morekeys_symbols_9 */ "9",
         /* additional_morekeys_symbols_0 */ "0",
+        /* morekeys_tablet_period */ "!autoColumnOrder!8,\\,,.,',#,),(,/,;,@,:,-,\",+,\\%,&",
         /* morekeys_nordic_row2_11 ~ */
         null, null, null,
         /* ~ keyspec_tablet_comma */
-        /* morekeys_tablet_period */ "!autoColumnOrder!8,\\,,.,',#,),(,/,;,@,:,-,\",+,\\%,&",
-        /* keyspec_swiss_row1_11 ~ */
-        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_tablet_comma */
         // U+0964: "।" DEVANAGARI DANDA
         /* keyspec_period */ "\u0964",
-        /* keyhintlabel_period */ null,
         /* morekeys_period */ "!autoColumnOrder!9,\\,,.,?,!,#,),(,/,;,',@,:,-,\",+,\\%,&",
         /* keyspec_tablet_period */ "\u0964",
     };
@@ -2065,8 +2060,10 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null,
-        /* ~ morekeys_nordic_row2_11 */
+        null, null, null,
+        /* ~ additional_morekeys_symbols_0 */
+        /* morekeys_tablet_period */ "!text/morekeys_punctuation",
+        /* morekeys_nordic_row2_11 */ null,
         // U+055E: "՞" ARMENIAN QUESTION MARK
         // U+055C: "՜" ARMENIAN EXCLAMATION MARK
         // U+055A: "՚" ARMENIAN APOSTROPHE
@@ -2079,7 +2076,10 @@
         // U+055F: "՟" ARMENIAN ABBREVIATION MARK
         /* morekeys_punctuation */ "!autoColumnOrder!8,\\,,\u055E,\u055C,.,\u055A,\u0559,?,!,\u055D,\u055B,\u058A,\u00BB,\u00AB,\u055F,;,:",
         /* keyspec_tablet_comma */ "\u055D",
-        /* morekeys_tablet_period */ "!text/morekeys_punctuation",
+        // U+0589: "։" ARMENIAN FULL STOP
+        /* keyspec_period */ "\u0589",
+        /* morekeys_period */ null,
+        /* keyspec_tablet_period */ "\u0589",
         /* keyspec_swiss_row1_11 ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null,
@@ -2091,11 +2091,7 @@
         // U+055D: "՝" ARMENIAN COMMA
         /* keyspec_comma */ "\u055D",
         /* morekeys_tablet_comma */ null,
-        // U+0589: "։" ARMENIAN FULL STOP
-        /* keyspec_period */ "\u0589",
         /* keyhintlabel_period */ null,
-        /* morekeys_period */ null,
-        /* keyspec_tablet_period */ "\u0589",
         // U+055E: "՞" ARMENIAN QUESTION MARK
         // U+00BF: "¿" INVERTED QUESTION MARK
         /* morekeys_question */ "\u055E,\u00BF",
@@ -2216,8 +2212,8 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null,
-        /* ~ morekeys_tablet_period */
+        null, null, null, null, null, null, null, null, null,
+        /* ~ keyspec_tablet_period */
         // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
         /* keyspec_swiss_row1_11 */ "\u00FC",
         // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
@@ -2254,7 +2250,7 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null,
+        null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_swiss_row2_11 */
         // U+2605: "★" BLACK STAR
         /* morekeys_star */ "\u2605",
@@ -2284,7 +2280,7 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null,
+        null, null, null, null,
         /* ~ morekeys_currency_dollar */
         // U+00B1: "±" PLUS-MINUS SIGN
         // U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN
@@ -2799,21 +2795,21 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null,
+        null, null, null, null, null,
         /* ~ morekeys_nordic_row2_11 */
         /* morekeys_punctuation */ "!autoColumnOrder!9,\u104A,.,?,!,#,),(,/,;,...,',@,:,-,\",+,\\%,&",
         // U+104A: "၊" MYANMAR SIGN LITTLE SECTION
         // U+104B: "။" MYANMAR SIGN SECTION
         /* keyspec_tablet_comma */ "\u104A",
-        /* morekeys_tablet_period ~ */
-        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null,
-        /* ~ keyspec_comma */
-        /* morekeys_tablet_comma */ "\\,",
         /* keyspec_period */ "\u104B",
-        /* keyhintlabel_period */ "\u104A",
         /* morekeys_period */ null,
         /* keyspec_tablet_period */ "\u104B",
+        /* keyspec_swiss_row1_11 ~ */
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        null, null, null, null, null, null, null,
+        /* ~ keyspec_comma */
+        /* morekeys_tablet_comma */ "\\,",
+        /* keyhintlabel_period */ "\u104A",
         /* morekeys_question ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null,
         /* ~ keyspec_south_slavic_row3_8 */
@@ -2873,8 +2869,8 @@
         /* morekeys_nordic_row2_10 */ "\u00F6",
         /* keyspec_east_slavic_row1_9 ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null, null, null,
-        /* ~ additional_morekeys_symbols_0 */
+        null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~ morekeys_tablet_period */
         // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
         /* morekeys_nordic_row2_11 */ "\u00E4",
     };
@@ -2930,6 +2926,14 @@
         /* additional_morekeys_symbols_8 */ "8",
         /* additional_morekeys_symbols_9 */ "9",
         /* additional_morekeys_symbols_0 */ "0",
+        /* morekeys_tablet_period */ "!autoColumnOrder!8,.,\\,,',#,),(,/,;,@,:,-,\",+,\\%,&",
+        /* morekeys_nordic_row2_11 ~ */
+        null, null, null,
+        /* ~ keyspec_tablet_comma */
+        // U+0964: "।" DEVANAGARI DANDA
+        /* keyspec_period */ "\u0964",
+        /* morekeys_period */ "!autoColumnOrder!9,.,\\,,?,!,#,),(,/,;,',@,:,-,\",+,\\%,&",
+        /* keyspec_tablet_period */ "\u0964",
     };
 
     /* Locale nl: Dutch */
@@ -3510,8 +3514,8 @@
         /* morekeys_nordic_row2_10 */ "\u00F8,\u0153",
         /* keyspec_east_slavic_row1_9 ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null, null, null,
-        /* ~ additional_morekeys_symbols_0 */
+        null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~ morekeys_tablet_period */
         // U+00E6: "æ" LATIN SMALL LETTER AE
         /* morekeys_nordic_row2_11 */ "\u00E6",
     };
@@ -4153,25 +4157,25 @@
         "bn_IN"  , TEXTS_bn_IN, /*   2/ 12 Bengali (India) */
         "ca"     , TEXTS_ca,    /*  11/ 99 Catalan */
         "cs"     , TEXTS_cs,    /*  17/ 21 Czech */
-        "da"     , TEXTS_da,    /*  19/ 54 Danish */
-        "de"     , TEXTS_de,    /*  16/ 63 German */
+        "da"     , TEXTS_da,    /*  19/ 55 Danish */
+        "de"     , TEXTS_de,    /*  16/ 66 German */
         "el"     , TEXTS_el,    /*   1/  5 Greek */
         "en"     , TEXTS_en,    /*   8/ 10 English */
         "eo"     , TEXTS_eo,    /*  26/126 Esperanto */
-        "es"     , TEXTS_es,    /*   8/ 55 Spanish */
+        "es"     , TEXTS_es,    /*   8/ 56 Spanish */
         "et_EE"  , TEXTS_et_EE, /*  22/ 27 Estonian (Estonia) */
         "eu_ES"  , TEXTS_eu_ES, /*   7/  8 Basque (Spain) */
         "fa"     , TEXTS_fa,    /*  58/133 Persian */
-        "fi"     , TEXTS_fi,    /*  10/ 54 Finnish */
-        "fr"     , TEXTS_fr,    /*  13/ 63 French */
+        "fi"     , TEXTS_fi,    /*  10/ 55 Finnish */
+        "fr"     , TEXTS_fr,    /*  13/ 66 French */
         "gl_ES"  , TEXTS_gl_ES, /*   7/  8 Gallegan (Spain) */
-        "hi"     , TEXTS_hi,    /*  27/ 84 Hindi */
+        "hi"     , TEXTS_hi,    /*  27/ 60 Hindi */
         "hi_ZZ"  , TEXTS_hi_ZZ, /*   9/118 Hindi (ZZ) */
         "hr"     , TEXTS_hr,    /*   9/ 20 Croatian */
         "hu"     , TEXTS_hu,    /*   9/ 20 Hungarian */
         "hy_AM"  , TEXTS_hy_AM, /*   9/134 Armenian (Armenia) */
         "is"     , TEXTS_is,    /*  10/ 16 Icelandic */
-        "it"     , TEXTS_it,    /*  11/ 63 Italian */
+        "it"     , TEXTS_it,    /*  11/ 66 Italian */
         "iw"     , TEXTS_iw,    /*  20/131 Hebrew */
         "ka_GE"  , TEXTS_ka_GE, /*   3/ 11 Georgian (Georgia) */
         "kk"     , TEXTS_kk,    /*  15/129 Kazakh */
@@ -4186,8 +4190,8 @@
         "mn_MN"  , TEXTS_mn_MN, /*   2/ 12 Mongolian (Mongolia) */
         "mr_IN"  , TEXTS_mr_IN, /*  23/ 53 Marathi (India) */
         "my_MM"  , TEXTS_my_MM, /*   8/ 98 Burmese (Myanmar) */
-        "nb"     , TEXTS_nb,    /*  11/ 54 Norwegian Bokmål */
-        "ne_NP"  , TEXTS_ne_NP, /*  23/ 53 Nepali (Nepal) */
+        "nb"     , TEXTS_nb,    /*  11/ 55 Norwegian Bokmål */
+        "ne_NP"  , TEXTS_ne_NP, /*  27/ 60 Nepali (Nepal) */
         "nl"     , TEXTS_nl,    /*   9/ 13 Dutch */
         "pl"     , TEXTS_pl,    /*  10/ 17 Polish */
         "pt"     , TEXTS_pt,    /*   6/  8 Portuguese */
@@ -4199,7 +4203,7 @@
         "sl"     , TEXTS_sl,    /*   8/ 20 Slovenian */
         "sr"     , TEXTS_sr,    /*  11/ 97 Serbian */
         "sr_ZZ"  , TEXTS_sr_ZZ, /*  14/118 Serbian (ZZ) */
-        "sv"     , TEXTS_sv,    /*  21/ 54 Swedish */
+        "sv"     , TEXTS_sv,    /*  21/ 55 Swedish */
         "sw"     , TEXTS_sw,    /*   9/ 18 Swahili */
         "ta_IN"  , TEXTS_ta_IN, /*   2/ 12 Tamil (India) */
         "ta_LK"  , TEXTS_ta_LK, /*   2/ 12 Tamil (Sri Lanka) */
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 861a890..be2efb2 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -733,6 +733,7 @@
     public void setInputView(final View view) {
         super.setInputView(view);
         mInputView = view;
+        updateSoftInputWindowLayoutParameters();
         mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view);
         if (hasSuggestionStripView()) {
             mSuggestionStripView.setListener(this, view);
@@ -1147,6 +1148,10 @@
     @Override
     public void onComputeInsets(final InputMethodService.Insets outInsets) {
         super.onComputeInsets(outInsets);
+        // This method may be called before {@link #setInputView(View)}.
+        if (mInputView == null) {
+            return;
+        }
         final SettingsValues settingsValues = mSettings.getCurrent();
         final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView();
         if (visibleKeyboardView == null || !hasSuggestionStripView()) {
@@ -1181,12 +1186,15 @@
         outInsets.visibleTopInsets = visibleTopY;
     }
 
-    public void startShowingInputView() {
+    public void startShowingInputView(final boolean needsToLoadKeyboard) {
         mIsExecutingStartShowingInputView = true;
         // This {@link #showWindow(boolean)} will eventually call back
         // {@link #onEvaluateInputViewShown()}.
         showWindow(true /* showInput */);
         mIsExecutingStartShowingInputView = false;
+        if (needsToLoadKeyboard) {
+            loadKeyboard();
+        }
     }
 
     public void stopShowingInputView() {
@@ -1194,6 +1202,14 @@
     }
 
     @Override
+    public boolean onShowInputRequested(final int flags, final boolean configChange) {
+        if (Settings.getInstance().getCurrent().mHasHardwareKeyboard) {
+            return true;
+        }
+        return super.onShowInputRequested(flags, configChange);
+    }
+
+    @Override
     public boolean onEvaluateInputViewShown() {
         if (mIsExecutingStartShowingInputView) {
             return true;
@@ -1223,8 +1239,14 @@
 
     @Override
     public void updateFullscreenMode() {
+        super.updateFullscreenMode();
+        mInputLogic.onUpdateFullscreenMode(isFullscreenMode());
+        updateSoftInputWindowLayoutParameters();
+    }
+
+    private void updateSoftInputWindowLayoutParameters() {
         // Override layout parameters to expand {@link SoftInputWindow} to the entire screen.
-        // See {@link InputMethodService#setinputView(View) and
+        // See {@link InputMethodService#setinputView(View)} and
         // {@link SoftInputWindow#updateWidthHeight(WindowManager.LayoutParams)}.
         final Window window = getWindow().getWindow();
         ViewLayoutUtils.updateLayoutHeightOf(window, LayoutParams.MATCH_PARENT);
@@ -1243,8 +1265,6 @@
             ViewLayoutUtils.updateLayoutGravityOf(inputArea, Gravity.BOTTOM);
             ViewLayoutUtils.updateLayoutHeightOf(mInputView, layoutHeight);
         }
-        super.updateFullscreenMode();
-        mInputLogic.onUpdateFullscreenMode(isFullscreenMode());
     }
 
     private int getCurrentAutoCapsState() {
diff --git a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java
index 46705f9..a180d06 100644
--- a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java
+++ b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java
@@ -54,11 +54,15 @@
         mWord = word;
         mProbabilityInfo = probabilityInfo;
         mShortcutTargets = shortcutTargets;
-        mNgrams = new ArrayList<>();
-        final NgramContext ngramContext = new NgramContext(new WordInfo(mWord));
-        if (bigrams != null) {
-            for (final WeightedString bigramTarget : bigrams) {
-                mNgrams.add(new NgramProperty(bigramTarget, ngramContext));
+        if (null == bigrams) {
+            mNgrams = null;
+        } else {
+            mNgrams = new ArrayList<>();
+            final NgramContext ngramContext = new NgramContext(new WordInfo(mWord));
+            if (bigrams != null) {
+                for (final WeightedString bigramTarget : bigrams) {
+                    mNgrams.add(new NgramProperty(bigramTarget, ngramContext));
+                }
             }
         }
         mIsBeginningOfSentence = false;
@@ -87,7 +91,7 @@
         mWord = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints);
         mProbabilityInfo = createProbabilityInfoFromArray(probabilityInfo);
         mShortcutTargets = new ArrayList<>();
-        mNgrams = new ArrayList<>();
+        final ArrayList<NgramProperty> ngrams = new ArrayList<>();
         mIsBeginningOfSentence = isBeginningOfSentence;
         mIsNotAWord = isNotAWord;
         mIsBlacklistEntry = isBlacklisted;
@@ -104,8 +108,9 @@
             final WeightedString ngramTarget = new WeightedString(ngramTargetString,
                     createProbabilityInfoFromArray(bigramProbabilityInfo.get(i)));
             // TODO: Support n-gram.
-            mNgrams.add(new NgramProperty(ngramTarget, ngramContext));
+            ngrams.add(new NgramProperty(ngramTarget, ngramContext));
         }
+        mNgrams = ngrams.isEmpty() ? null : ngrams;
 
         final int shortcutTargetCount = shortcutTargets.size();
         for (int i = 0; i < shortcutTargetCount; i++) {
@@ -118,6 +123,9 @@
 
     // TODO: Remove
     public ArrayList<WeightedString> getBigrams() {
+        if (null == mNgrams) {
+            return null;
+        }
         final ArrayList<WeightedString> bigrams = new ArrayList<>();
         for (final NgramProperty ngram : mNgrams) {
             if (ngram.mNgramContext.getPrevWordCount() == 1) {
@@ -167,11 +175,18 @@
         if (!(o instanceof WordProperty)) return false;
         WordProperty w = (WordProperty)o;
         return mProbabilityInfo.equals(w.mProbabilityInfo) && mWord.equals(w.mWord)
-                && mShortcutTargets.equals(w.mShortcutTargets) && mNgrams.equals(w.mNgrams)
+                && mShortcutTargets.equals(w.mShortcutTargets) && equals(mNgrams, w.mNgrams)
                 && mIsNotAWord == w.mIsNotAWord && mIsBlacklistEntry == w.mIsBlacklistEntry
                 && mHasNgrams == w.mHasNgrams && mHasShortcuts && w.mHasNgrams;
     }
 
+    private <T> boolean equals(final ArrayList<T> a, final ArrayList<T> b) {
+        if (null == a) {
+            return null == b;
+        }
+        return a.equals(b);
+    }
+
     @Override
     public int hashCode() {
         if (mHashCode == 0) {
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index 3a2073f..6003a6f 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -48,7 +48,7 @@
 
 ifeq ($(FLAG_DO_PROFILE), true)
     $(warning Making profiling version of native library)
-    LOCAL_CFLAGS += -DFLAG_DO_PROFILE -funwind-tables -fno-inline
+    LOCAL_CFLAGS += -DFLAG_DO_PROFILE -funwind-tables
 else # FLAG_DO_PROFILE
 ifeq ($(FLAG_DBG), true)
     $(warning Making debug version of native library)
diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
index f88d37e..80419b3 100644
--- a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
+++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
@@ -25,13 +25,13 @@
 
 namespace latinime {
 
-static jlong latinime_Keyboard_setProximityInfo(JNIEnv *env, jclass clazz, jstring localeJStr,
+static jlong latinime_Keyboard_setProximityInfo(JNIEnv *env, jclass clazz,
         jint displayWidth, jint displayHeight, jint gridWidth, jint gridHeight,
         jint mostCommonkeyWidth, jint mostCommonkeyHeight, jintArray proximityChars, jint keyCount,
         jintArray keyXCoordinates, jintArray keyYCoordinates, jintArray keyWidths,
         jintArray keyHeights, jintArray keyCharCodes, jfloatArray sweetSpotCenterXs,
         jfloatArray sweetSpotCenterYs, jfloatArray sweetSpotRadii) {
-    ProximityInfo *proximityInfo = new ProximityInfo(env, localeJStr, displayWidth, displayHeight,
+    ProximityInfo *proximityInfo = new ProximityInfo(env, displayWidth, displayHeight,
             gridWidth, gridHeight, mostCommonkeyWidth, mostCommonkeyHeight, proximityChars,
             keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes,
             sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
@@ -46,7 +46,7 @@
 static const JNINativeMethod sMethods[] = {
     {
         const_cast<char *>("setProximityInfoNative"),
-        const_cast<char *>("(Ljava/lang/String;IIIIII[II[I[I[I[I[I[F[F[F)J"),
+        const_cast<char *>("(IIIIII[II[I[I[I[I[I[F[F[F)J"),
         reinterpret_cast<void *>(latinime_Keyboard_setProximityInfo)
     },
     {
diff --git a/native/jni/src/suggest/core/layout/additional_proximity_chars.cpp b/native/jni/src/suggest/core/layout/additional_proximity_chars.cpp
index 34b8b37..8b39f7d 100644
--- a/native/jni/src/suggest/core/layout/additional_proximity_chars.cpp
+++ b/native/jni/src/suggest/core/layout/additional_proximity_chars.cpp
@@ -19,7 +19,7 @@
 namespace latinime {
 // TODO: Stop using hardcoded additional proximity characters.
 // TODO: Have proximity character informations in each language's binary dictionary.
-const char *AdditionalProximityChars::LOCALE_EN_US = "en";
+const int AdditionalProximityChars::LOCALE_EN_US[LOCALE_EN_US_SIZE] = { 'e', 'n' };
 
 const int AdditionalProximityChars::EN_US_ADDITIONAL_A[EN_US_ADDITIONAL_A_SIZE] = {
     'e', 'i', 'o', 'u'
diff --git a/native/jni/src/suggest/core/layout/additional_proximity_chars.h b/native/jni/src/suggest/core/layout/additional_proximity_chars.h
index a88fd6c..2260be9 100644
--- a/native/jni/src/suggest/core/layout/additional_proximity_chars.h
+++ b/native/jni/src/suggest/core/layout/additional_proximity_chars.h
@@ -18,6 +18,7 @@
 #define LATINIME_ADDITIONAL_PROXIMITY_CHARS_H
 
 #include <cstring>
+#include <vector>
 
 #include "defines.h"
 
@@ -26,7 +27,8 @@
 class AdditionalProximityChars {
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(AdditionalProximityChars);
-    static const char *LOCALE_EN_US;
+    static const int LOCALE_EN_US_SIZE = 2;
+    static const int LOCALE_EN_US[LOCALE_EN_US_SIZE];
     static const int EN_US_ADDITIONAL_A_SIZE = 4;
     static const int EN_US_ADDITIONAL_A[];
     static const int EN_US_ADDITIONAL_E_SIZE = 4;
@@ -38,15 +40,22 @@
     static const int EN_US_ADDITIONAL_U_SIZE = 4;
     static const int EN_US_ADDITIONAL_U[];
 
-    AK_FORCE_INLINE static bool isEnLocale(const char *localeStr) {
-        const size_t LOCALE_EN_US_SIZE = strlen(LOCALE_EN_US);
-        return localeStr && strlen(localeStr) >= LOCALE_EN_US_SIZE
-                && strncmp(localeStr, LOCALE_EN_US, LOCALE_EN_US_SIZE) == 0;
+    AK_FORCE_INLINE static bool isEnLocale(const std::vector<int> *locale) {
+        const int NCHARS = NELEMS(LOCALE_EN_US);
+        if (locale->size() < NCHARS) {
+            return false;
+        }
+        for (int i = 0; i < NCHARS; ++i) {
+            if ((*locale)[i] != LOCALE_EN_US[i]) {
+                return false;
+            }
+        }
+        return true;
     }
 
  public:
-    static int getAdditionalCharsSize(const char *const localeStr, const int c) {
-        if (!isEnLocale(localeStr)) {
+    static int getAdditionalCharsSize(const std::vector<int> *locale, const int c) {
+        if (!isEnLocale(locale)) {
             return 0;
         }
         switch (c) {
@@ -65,8 +74,8 @@
         }
     }
 
-    static const int *getAdditionalChars(const char *const localeStr, const int c) {
-        if (!isEnLocale(localeStr)) {
+    static const int *getAdditionalChars(const std::vector<int> *locale, const int c) {
+        if (!isEnLocale(locale)) {
             return 0;
         }
         switch (c) {
diff --git a/native/jni/src/suggest/core/layout/proximity_info.cpp b/native/jni/src/suggest/core/layout/proximity_info.cpp
index 4c75a18..933a5e1 100644
--- a/native/jni/src/suggest/core/layout/proximity_info.cpp
+++ b/native/jni/src/suggest/core/layout/proximity_info.cpp
@@ -49,13 +49,13 @@
     }
 }
 
-ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr,
-        const int keyboardWidth, const int keyboardHeight, const int gridWidth,
-        const int gridHeight, const int mostCommonKeyWidth, const int mostCommonKeyHeight,
-        const jintArray proximityChars, const int keyCount, const jintArray keyXCoordinates,
-        const jintArray keyYCoordinates, const jintArray keyWidths, const jintArray keyHeights,
-        const jintArray keyCharCodes, const jfloatArray sweetSpotCenterXs,
-        const jfloatArray sweetSpotCenterYs, const jfloatArray sweetSpotRadii)
+ProximityInfo::ProximityInfo(JNIEnv *env, const int keyboardWidth, const int keyboardHeight,
+        const int gridWidth, const int gridHeight, const int mostCommonKeyWidth,
+        const int mostCommonKeyHeight, const jintArray proximityChars, const int keyCount,
+        const jintArray keyXCoordinates, const jintArray keyYCoordinates,
+        const jintArray keyWidths, const jintArray keyHeights, const jintArray keyCharCodes,
+        const jfloatArray sweetSpotCenterXs, const jfloatArray sweetSpotCenterYs,
+        const jfloatArray sweetSpotRadii)
         : GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight), MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth),
           MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth),
           NORMALIZED_SQUARED_MOST_COMMON_KEY_HYPOTENUSE(1.0f +
@@ -82,13 +82,6 @@
     if (DEBUG_PROXIMITY_INFO) {
         AKLOGI("Create proximity info array %d", proximityCharsLength);
     }
-    const jsize localeCStrUtf8Length = env->GetStringUTFLength(localeJStr);
-    if (localeCStrUtf8Length >= MAX_LOCALE_STRING_LENGTH) {
-        AKLOGI("Locale string length too long: length=%d", localeCStrUtf8Length);
-        ASSERT(false);
-    }
-    memset(mLocaleStr, 0, sizeof(mLocaleStr));
-    env->GetStringUTFRegion(localeJStr, 0, env->GetStringLength(localeJStr), mLocaleStr);
     safeGetOrFillZeroIntArrayRegion(env, proximityChars, proximityCharsLength,
             mProximityCharsArray);
     safeGetOrFillZeroIntArrayRegion(env, keyXCoordinates, KEY_COUNT, mKeyXCoordinates);
diff --git a/native/jni/src/suggest/core/layout/proximity_info.h b/native/jni/src/suggest/core/layout/proximity_info.h
index d4e4537..f7c9076 100644
--- a/native/jni/src/suggest/core/layout/proximity_info.h
+++ b/native/jni/src/suggest/core/layout/proximity_info.h
@@ -18,6 +18,7 @@
 #define LATINIME_PROXIMITY_INFO_H
 
 #include <unordered_map>
+#include <vector>
 
 #include "defines.h"
 #include "jni.h"
@@ -27,9 +28,9 @@
 
 class ProximityInfo {
  public:
-    ProximityInfo(JNIEnv *env, const jstring localeJStr,
-            const int keyboardWidth, const int keyboardHeight, const int gridWidth,
-            const int gridHeight, const int mostCommonKeyWidth, const int mostCommonKeyHeight,
+    ProximityInfo(JNIEnv *env, const int keyboardWidth, const int keyboardHeight,
+            const int gridWidth, const int gridHeight,
+            const int mostCommonKeyWidth, const int mostCommonKeyHeight,
             const jintArray proximityChars, const int keyCount, const jintArray keyXCoordinates,
             const jintArray keyYCoordinates, const jintArray keyWidths, const jintArray keyHeights,
             const jintArray keyCharCodes, const jfloatArray sweetSpotCenterXs,
@@ -71,11 +72,11 @@
 
     AK_FORCE_INLINE void initializeProximities(const int *const inputCodes,
             const int *const inputXCoordinates, const int *const inputYCoordinates,
-            const int inputSize, int *allInputCodes) const {
+            const int inputSize, int *allInputCodes, const std::vector<int> *locale) const {
         ProximityInfoUtils::initializeProximities(inputCodes, inputXCoordinates, inputYCoordinates,
                 inputSize, mKeyXCoordinates, mKeyYCoordinates, mKeyWidths, mKeyHeights,
                 mProximityCharsArray, CELL_HEIGHT, CELL_WIDTH, GRID_WIDTH, MOST_COMMON_KEY_WIDTH,
-                KEY_COUNT, mLocaleStr, &mLowerCodePointToKeyMap, allInputCodes);
+                KEY_COUNT, locale, &mLowerCodePointToKeyMap, allInputCodes);
     }
 
     AK_FORCE_INLINE int getKeyIndexOf(const int c) const {
@@ -103,9 +104,6 @@
     const int KEYBOARD_HEIGHT;
     const float KEYBOARD_HYPOTENUSE;
     const bool HAS_TOUCH_POSITION_CORRECTION_DATA;
-    // Assuming locale strings such as en_US, sr-Latn etc.
-    static const int MAX_LOCALE_STRING_LENGTH = 10;
-    char mLocaleStr[MAX_LOCALE_STRING_LENGTH];
     int *mProximityCharsArray;
     int mKeyXCoordinates[MAX_KEY_COUNT_IN_A_KEYBOARD];
     int mKeyYCoordinates[MAX_KEY_COUNT_IN_A_KEYBOARD];
diff --git a/native/jni/src/suggest/core/layout/proximity_info_state.cpp b/native/jni/src/suggest/core/layout/proximity_info_state.cpp
index 91469e2..d43a002 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_state.cpp
+++ b/native/jni/src/suggest/core/layout/proximity_info_state.cpp
@@ -42,7 +42,7 @@
 void ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength,
         const ProximityInfo *proximityInfo, const int *const inputCodes, const int inputSize,
         const int *const xCoordinates, const int *const yCoordinates, const int *const times,
-        const int *const pointerIds, const bool isGeometric) {
+        const int *const pointerIds, const bool isGeometric, const std::vector<int> *locale) {
     ASSERT(isGeometric || (inputSize < MAX_WORD_LENGTH));
     mIsContinuousSuggestionPossible = (mHasBeenUpdatedByGeometricInput != isGeometric) ?
             false : ProximityInfoStateUtils::checkAndReturnIsContinuousSuggestionPossible(
@@ -66,7 +66,7 @@
 
     if (!isGeometric && pointerId == 0) {
         mProximityInfo->initializeProximities(inputCodes, xCoordinates, yCoordinates,
-                inputSize, mInputProximities);
+                inputSize, mInputProximities, locale);
     }
 
     ///////////////////////
diff --git a/native/jni/src/suggest/core/layout/proximity_info_state.h b/native/jni/src/suggest/core/layout/proximity_info_state.h
index e6180fe..a2d6635 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_state.h
+++ b/native/jni/src/suggest/core/layout/proximity_info_state.h
@@ -37,7 +37,8 @@
     void initInputParams(const int pointerId, const float maxPointToKeyLength,
             const ProximityInfo *proximityInfo, const int *const inputCodes,
             const int inputSize, const int *xCoordinates, const int *yCoordinates,
-            const int *const times, const int *const pointerIds, const bool isGeometric);
+            const int *const times, const int *const pointerIds, const bool isGeometric,
+            const std::vector<int> *locale);
 
     /////////////////////////////////////////
     // Defined here                        //
diff --git a/native/jni/src/suggest/core/layout/proximity_info_utils.h b/native/jni/src/suggest/core/layout/proximity_info_utils.h
index 178aada..79d0615 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_utils.h
+++ b/native/jni/src/suggest/core/layout/proximity_info_utils.h
@@ -19,6 +19,7 @@
 
 #include <cmath>
 #include <unordered_map>
+#include <vector>
 
 #include "defines.h"
 #include "suggest/core/layout/additional_proximity_chars.h"
@@ -51,7 +52,7 @@
             const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
             const int *const proximityCharsArray, const int cellHeight, const int cellWidth,
             const int gridWidth, const int mostCommonKeyWidth, const int keyCount,
-            const char *const localeStr,
+            const std::vector<int> *locale,
             const std::unordered_map<int, int> *const codeToKeyMap, int *inputProximities) {
         // Initialize
         // - mInputCodes
@@ -64,7 +65,7 @@
             int *proximities = &inputProximities[i * MAX_PROXIMITY_CHARS_SIZE];
             calculateProximities(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights,
                     proximityCharsArray, cellHeight, cellWidth, gridWidth, mostCommonKeyWidth,
-                    keyCount, x, y, primaryKey, localeStr, codeToKeyMap, proximities);
+                    keyCount, x, y, primaryKey, locale, codeToKeyMap, proximities);
         }
 
         if (DEBUG_PROXIMITY_CHARS) {
@@ -143,7 +144,7 @@
             const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
             const int *const proximityCharsArray, const int cellHeight, const int cellWidth,
             const int gridWidth, const int mostCommonKeyWidth, const int keyCount,
-            const int x, const int y, const int primaryKey, const char *const localeStr,
+            const int x, const int y, const int primaryKey, const std::vector<int> *locale,
             const std::unordered_map<int, int> *const codeToKeyMap, int *proximities) {
         const int mostCommonKeyWidthSquare = mostCommonKeyWidth * mostCommonKeyWidth;
         int insertPos = 0;
@@ -177,7 +178,7 @@
                 }
             }
             const int additionalProximitySize =
-                    AdditionalProximityChars::getAdditionalCharsSize(localeStr, primaryKey);
+                    AdditionalProximityChars::getAdditionalCharsSize(locale, primaryKey);
             if (additionalProximitySize > 0) {
                 proximities[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE;
                 if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
@@ -188,7 +189,7 @@
                 }
 
                 const int *additionalProximityChars =
-                        AdditionalProximityChars::getAdditionalChars(localeStr, primaryKey);
+                        AdditionalProximityChars::getAdditionalChars(locale, primaryKey);
                 for (int j = 0; j < additionalProximitySize; ++j) {
                     const int ac = additionalProximityChars[j];
                     int k = 0;
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.cpp b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
index 4d7505a..b4d01d0 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
@@ -69,8 +69,12 @@
     for (int i = 0; i < maxPointerCount; ++i) {
         mProximityInfoStates[i].initInputParams(i, maxSpatialDistance, getProximityInfo(),
                 inputCodePoints, inputSize, inputXs, inputYs, times, pointerIds,
-                maxPointerCount == MAX_POINTER_COUNT_G
-                /* TODO: this is a hack. fix proximity info state */);
+                // Right now the line below is trying to figure out whether this is a gesture by
+                // looking at the pointer count and assuming whatever is above the cutoff is
+                // a gesture and whatever is below is type. This is hacky and incorrect, we
+                // should pass the correct information instead.
+                maxPointerCount == MAX_POINTER_COUNT_G,
+                getDictionaryStructurePolicy()->getHeaderStructurePolicy()->getLocale());
         mInputSize += mProximityInfoStates[i].size();
     }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java b/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java
index 640b63d..299cb61 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java
@@ -33,26 +33,17 @@
     private static final String LAYOUT_NAME = "nepali_romanized";
 
     public NepaliRomanized(final Locale locale) {
-        super(new NepaliRomanizedCustomizer(locale), HindiSymbols.class, SymbolsShifted.class);
+        super(new NepaliCustomizer(locale), HindiSymbols.class, SymbolsShifted.class);
     }
 
     @Override
     public String getName() { return LAYOUT_NAME; }
 
-    private static class NepaliRomanizedCustomizer extends NepaliCustomizer {
-        NepaliRomanizedCustomizer(final Locale locale) { super(locale); }
-
-        @Override
-        public ExpectedKey[] getRightShiftKeys(final boolean isPhone) {
-            return isPhone ? EMPTY_KEYS : EXCLAMATION_AND_QUESTION_MARKS;
-        }
-    }
+    @Override
+    ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; }
 
     @Override
-    ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone) { return ALPHABET_COMMON; }
-
-    @Override
-    ExpectedKey[][] getCommonAlphabetShiftLayout(boolean isPhone, final int elementId) {
+    ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) {
         if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
             return getCommonAlphabetLayout(isPhone);
         }
@@ -118,11 +109,9 @@
                     // U+0928: "न" DEVANAGARI LETTER NA
                     // U+092E: "म" DEVANAGARI LETTER MA
                     "\u0937", "\u0921", "\u091A", "\u0935", "\u092C", "\u0928", "\u092E",
-                    // U+0964: "।" DEVANAGARI DANDA
-                    // U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA
-                    key("\u0964", moreKey("\u093D")),
                     // U+094D: "्" DEVANAGARI SIGN VIRAMA
-                    key(SIGN_VIRAMA, "\u094D"))
+                    // U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA
+                    key(SIGN_VIRAMA, "\u094D", moreKey("\u093D")))
             .build();
 
     private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder()
@@ -172,8 +161,6 @@
                     // U+0902: "ं" DEVANAGARI SIGN ANUSVARA
                     key(SIGN_ANUSVARA, "\u0902"),
                     // U+0919: "ङ" DEVANAGARI LETTER NGA
-                    "\u0919",
-                    // U+094D: "्" DEVANAGARI SIGN VIRAMA
-                    key(SIGN_VIRAMA, "\u094D"))
+                    "\u0919")
             .build();
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/NepaliTraditional.java b/tests/src/com/android/inputmethod/keyboard/layout/NepaliTraditional.java
index 17e226f..0a2bea3 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/NepaliTraditional.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/NepaliTraditional.java
@@ -43,82 +43,20 @@
         NepaliTraditionalCustomizer(final Locale locale) { super(locale); }
 
         @Override
-        public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { return EMPTY_KEYS; }
-
-        @Override
-        public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
-            if (isPhone) {
-                // U+094D: "्" DEVANAGARI SIGN VIRAMA
-                return joinKeys(key(SIGN_VIRAMA, "\u094D", PHONE_PUNCTUATION_MORE_KEYS));
-            }
-            return super.getKeysRightToSpacebar(isPhone);
+        public ExpectedKey[] getRightShiftKeys(final boolean isPhone) {
+            return isPhone ? EMPTY_KEYS : EXCLAMATION_AND_QUESTION_MARKS;
         }
     }
 
     @Override
-    ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone) {
-        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON);
-        if (isPhone) {
-            builder.addKeysOnTheRightOfRow(3,
-                    // U+0947: "े" DEVANAGARI VOWEL SIGN E
-                    // U+0903: "ः‍" DEVANAGARI SIGN VISARGA
-                    // U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA
-                    key(VOWEL_SIGN_E, "\u0947", joinMoreKeys(
-                            moreKey(SIGN_VISARGA, "\u0903"), "\u093D")),
-                    // U+0964: "।" DEVANAGARI DANDA
-                    "\u0964",
-                    // U+0930: "र" DEVANAGARI LETTER RA
-                    // U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U
-                    key("\u0930", moreKey("\u0930\u0941")));
-        } else {
-            builder.addKeysOnTheRightOfRow(3,
-                    // U+0903: "ः" DEVANAGARI SIGN VISARGA
-                    // U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA
-                    key(SIGN_VISARGA, "\u0903", moreKey("\u093D")),
-                    // U+0947: "े" DEVANAGARI VOWEL SIGN E
-                    key(VOWEL_SIGN_E, "\u0947"),
-                    // U+0964: "।" DEVANAGARI DANDA
-                    "\u0964",
-                    // U+0930: "र" DEVANAGARI LETTER RA
-                    key("\u0930", moreKey("!")),
-                    // U+094D: "्" DEVANAGARI SIGN VIRAMA
-                    key(SIGN_VIRAMA, "\u094D", moreKey("?")));
-        }
-        return builder.build();
-    }
+    ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; }
 
     @Override
-    ExpectedKey[][] getCommonAlphabetShiftLayout(boolean isPhone, final int elementId) {
+    ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) {
         if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
             return getCommonAlphabetLayout(isPhone);
         }
-        final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(
-                ALPHABET_SHIFTED_COMMON);
-        if (isPhone) {
-            builder.addKeysOnTheRightOfRow(3,
-                    // U+0902: "ं" DEVANAGARI SIGN ANUSVARA
-                    key(SIGN_ANUSVARA, "\u0902"),
-                    // U+0919: "ङ" DEVANAGARI LETTER NGA
-                    "\u0919",
-                    // U+0948: "ै" DEVANAGARI VOWEL SIGN AI
-                    // U+0936/U+094D/U+0930:
-                    //     "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA
-                    key(VOWEL_SIGN_AI, "\u0948", moreKey("\u0936\u094D\u0930")));
-        } else {
-            builder.addKeysOnTheRightOfRow(3,
-                    // U+0902: "ं" DEVANAGARI SIGN ANUSVARA
-                    key(SIGN_ANUSVARA, "\u0902"),
-                    // U+0919: "ङ" DEVANAGARI LETTER NGA
-                    "\u0919",
-                    // U+0948: "ै" DEVANAGARI VOWEL SIGN AI
-                    // U+0936/U+094D/U+0930:
-                    //     "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA
-                    key(VOWEL_SIGN_AI, "\u0948", moreKey("\u0936\u094D\u0930")),
-                    // U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U
-                    key("\u0930\u0941", moreKey("!")),
-                    "?");
-        }
-        return builder.build();
+        return ALPHABET_SHIFTED_COMMON;
     }
 
     private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
@@ -181,7 +119,17 @@
                     // U+0916: "ख" DEVANAGARI LETTER KHA
                     // U+0926: "द" DEVANAGARI LETTER DA
                     // U+0932: "ल" DEVANAGARI LETTER LA
-                    "\u0936", "\u0939", "\u0905", "\u0916", "\u0926", "\u0932")
+                    "\u0936", "\u0939", "\u0905", "\u0916", "\u0926", "\u0932",
+                    // U+0947: "े" DEVANAGARI VOWEL SIGN E
+                    // U+0903: "ः‍" DEVANAGARI SIGN VISARGA
+                    // U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA
+                    key(VOWEL_SIGN_E, "\u0947", joinMoreKeys(
+                            moreKey(SIGN_VISARGA, "\u0903"), "\u093D")),
+                    // U+094D: "्" DEVANAGARI SIGN VIRAMA
+                    key(SIGN_VIRAMA, "\u094D"),
+                    // U+0930: "र" DEVANAGARI LETTER RA
+                    // U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U
+                    key("\u0930", moreKey("\u0930\u0941")))
             .build();
 
     private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder()
@@ -264,6 +212,14 @@
                     key(VOWEL_SIGN_AU, "\u094C"),
                     // U+0926/U+094D/U+092F:
                     //     "द्य" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER YA
-                    "\u0926\u094D\u092F")
+                    "\u0926\u094D\u092F",
+                    // U+0902: "ं" DEVANAGARI SIGN ANUSVARA
+                    key(SIGN_ANUSVARA, "\u0902"),
+                    // U+0919: "ङ" DEVANAGARI LETTER NGA
+                    "\u0919",
+                    // U+0948: "ै" DEVANAGARI VOWEL SIGN AI
+                    // U+0936/U+094D/U+0930:
+                    //     "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA
+                    key(VOWEL_SIGN_AI, "\u0948", moreKey("\u0936\u094D\u0930")))
             .build();
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/customizer/NepaliCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/customizer/NepaliCustomizer.java
index 7a00d80..264322f 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/customizer/NepaliCustomizer.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/customizer/NepaliCustomizer.java
@@ -38,8 +38,30 @@
         return joinKeys(LANGUAGE_SWITCH_KEY, SPACE_KEY, key(ZWNJ_KEY, ZWJ_KEY));
     }
 
+    @Override
+    public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
+        // U+0964: "।" DEVANAGARI DANDA
+        final ExpectedKey periodKey = key("\u0964", getPunctuationMoreKeys(isPhone));
+        return joinKeys(periodKey);
+    }
+
+    @Override
+    public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) {
+        return isPhone ? NEPALI_PHONE_PUNCTUATION_MORE_KEYS
+                : NEPALI_TABLET_PUNCTUATION_MORE_KEYS;
+    }
+
     // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN
     private static final ExpectedKey CURRENCY_NEPALI = key("\u0930\u0941\u002E",
             Symbols.DOLLAR_SIGN, Symbols.CENT_SIGN, Symbols.EURO_SIGN, Symbols.POUND_SIGN,
             Symbols.YEN_SIGN, Symbols.PESO_SIGN);
+
+    // Punctuation more keys for phone form factor.
+    private static final ExpectedKey[] NEPALI_PHONE_PUNCTUATION_MORE_KEYS = joinKeys(
+            ".", ",", "?", "!", "#", ")", "(", "/", ";",
+            "'", "@", ":", "-", "\"", "+", "%", "&");
+    // Punctuation more keys for tablet form factor.
+    private static final ExpectedKey[] NEPALI_TABLET_PUNCTUATION_MORE_KEYS = joinKeys(
+            ".", ",", "'", "#", ")", "(", "/", ";",
+            "@", ":", "-", "\"", "+", "%", "&");
 }
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
index 8d5d6cc..6b6ad21 100644
--- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
@@ -37,6 +37,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Random;
@@ -49,6 +50,7 @@
     private static final int DUMMY_PROBABILITY = 0;
     private static final int[] DICT_FORMAT_VERSIONS =
             new int[] { FormatSpec.VERSION4, FormatSpec.VERSION4_DEV };
+    private static final String DICTIONARY_ID = "TestDecayingBinaryDictionary";
 
     private int mCurrentTime = 0;
 
@@ -56,10 +58,15 @@
     protected void setUp() throws Exception {
         super.setUp();
         mCurrentTime = 0;
+        mDictFilesToBeDeleted.clear();
     }
 
     @Override
     protected void tearDown() throws Exception {
+        for (final File dictFile : mDictFilesToBeDeleted) {
+            dictFile.delete();
+        }
+        mDictFilesToBeDeleted.clear();
         stopTestModeInNativeCode();
         super.tearDown();
     }
@@ -103,25 +110,32 @@
         binaryDictionary.flushWithGC();
     }
 
-    private File createEmptyDictionaryAndGetFile(final String dictId,
-            final int formatVersion) throws IOException {
+    private HashSet<File> mDictFilesToBeDeleted = new HashSet<>();
+
+    private File createEmptyDictionaryAndGetFile(final int formatVersion) {
         if (formatVersion == FormatSpec.VERSION4
                 || formatVersion == FormatSpec.VERSION4_ONLY_FOR_TESTING
                 || formatVersion == FormatSpec.VERSION4_DEV) {
-            return createEmptyVer4DictionaryAndGetFile(dictId, formatVersion);
+            try {
+                final File dictFile = createEmptyVer4DictionaryAndGetFile(formatVersion);
+                mDictFilesToBeDeleted.add(dictFile);
+                return dictFile;
+            } catch (final IOException e) {
+                fail(e.toString());
+            }
         } else {
-            throw new IOException("Dictionary format version " + formatVersion
-                    + " is not supported.");
+            fail("Dictionary format version " + formatVersion + " is not supported.");
         }
+        return null;
     }
 
-    private File createEmptyVer4DictionaryAndGetFile(final String dictId, final int formatVersion)
+    private File createEmptyVer4DictionaryAndGetFile(final int formatVersion)
             throws IOException {
-        final File file = File.createTempFile(dictId, TEST_DICT_FILE_EXTENSION,
+        final File file = File.createTempFile(DICTIONARY_ID, TEST_DICT_FILE_EXTENSION,
                 getContext().getCacheDir());
         FileUtils.deleteRecursively(file);
         Map<String, String> attributeMap = new HashMap<>();
-        attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, dictId);
+        attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, DICTIONARY_ID);
         attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY,
                 String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())));
         attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY,
@@ -137,6 +151,12 @@
         }
     }
 
+    private BinaryDictionary getBinaryDictionary(final File dictFile) {
+        return new BinaryDictionary(dictFile.getAbsolutePath(),
+                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+    }
+
     private static int setCurrentTimeForTestMode(final int currentTime) {
         return BinaryDictionaryUtils.setCurrentTimeForTest(currentTime);
     }
@@ -153,15 +173,8 @@
 
     private void testReadDictInJavaSide(final int formatVersion) {
         setCurrentTimeForTestMode(mCurrentTime);
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
         addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY);
         addUnigramWord(binaryDictionary, "ab", DUMMY_PROBABILITY);
         addUnigramWord(binaryDictionary, "aaa", DUMMY_PROBABILITY);
@@ -189,7 +202,6 @@
         } catch (UnsupportedFormatException e) {
             fail("Unsupported format: " + e);
         }
-        dictFile.delete();
     }
 
     public void testControlCurrentTime() {
@@ -214,15 +226,8 @@
     }
 
     private void testAddValidAndInvalidWords(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
 
         addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY);
         assertFalse(binaryDictionary.isValidWord("a"));
@@ -249,7 +254,6 @@
         assertFalse(isValidBigram(binaryDictionary, "x", "y"));
 
         binaryDictionary.close();
-        dictFile.delete();
     }
 
     public void testDecayingProbability() {
@@ -259,15 +263,8 @@
     }
 
     private void testDecayingProbability(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
 
         addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY);
         assertTrue(binaryDictionary.isValidWord("a"));
@@ -306,7 +303,6 @@
         assertFalse(isValidBigram(binaryDictionary, "a", "b"));
 
         binaryDictionary.close();
-        dictFile.delete();
     }
 
     public void testAddManyUnigramsToDecayingDict() {
@@ -321,16 +317,8 @@
         final int codePointSetSize = 50;
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
         setCurrentTimeForTestMode(mCurrentTime);
 
         final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
@@ -384,16 +372,8 @@
         final int codePointSetSize = 50;
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
         setCurrentTimeForTestMode(mCurrentTime);
         final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
 
@@ -445,16 +425,9 @@
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
 
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
         setCurrentTimeForTestMode(mCurrentTime);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
 
         final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
         final ArrayList<String> words = new ArrayList<>();
@@ -523,17 +496,9 @@
         final int codePointSetSize = 50;
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
         setCurrentTimeForTestMode(mCurrentTime);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
         final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
 
         final ArrayList<String> words = new ArrayList<>();
@@ -596,15 +561,8 @@
 
     private void testDictMigration(final int fromFormatVersion, final int toFormatVersion) {
         setCurrentTimeForTestMode(mCurrentTime);
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", fromFormatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(fromFormatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
         addUnigramWord(binaryDictionary, "aaa", DUMMY_PROBABILITY);
         assertTrue(binaryDictionary.isValidWord("aaa"));
         addUnigramWord(binaryDictionary, "bbb", Dictionary.NOT_A_PROBABILITY);
@@ -634,7 +592,6 @@
         addBigramWords(binaryDictionary, "aaa", "bbb", Dictionary.NOT_A_PROBABILITY);
         assertTrue(isValidBigram(binaryDictionary, "aaa", "bbb"));
         binaryDictionary.close();
-        dictFile.delete();
     }
 
     public void testBeginningOfSentence() {
@@ -647,15 +604,8 @@
 
     private void testBeginningOfSentence(final int formatVersion) {
         setCurrentTimeForTestMode(mCurrentTime);
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
 
         binaryDictionary.addUnigramEntry("", DUMMY_PROBABILITY, "" /* shortcutTarget */,
                 BinaryDictionary.NOT_A_PROBABILITY /* shortcutProbability */,
@@ -687,7 +637,6 @@
         assertTrue(binaryDictionary.isValidNgram(beginningOfSentenceContext, "aaa"));
         assertTrue(binaryDictionary.isValidNgram(beginningOfSentenceContext, "bbb"));
         binaryDictionary.close();
-        dictFile.delete();
     }
 
     public void testRemoveUnigrams() {
@@ -699,15 +648,8 @@
     private void testRemoveUnigrams(final int formatVersion) {
         final int unigramInputCount = 20;
         setCurrentTimeForTestMode(mCurrentTime);
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
 
         addUnigramWord(binaryDictionary, "aaa", Dictionary.NOT_A_PROBABILITY);
         assertFalse(binaryDictionary.isValidWord("aaa"));
@@ -719,6 +661,5 @@
         assertFalse(binaryDictionary.isValidWord("aaa"));
 
         binaryDictionary.close();
-        dictFile.delete();
     }
 }
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
index 9c7792c..90dd436 100644
--- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
@@ -46,6 +46,7 @@
     private static final String TEST_LOCALE = "test";
     private static final int[] DICT_FORMAT_VERSIONS =
             new int[] { FormatSpec.VERSION4, FormatSpec.VERSION4_DEV };
+    private static final String DICTIONARY_ID = "TestBinaryDictionary";
 
     private static boolean canCheckBigramProbability(final int formatVersion) {
         return formatVersion > FormatSpec.VERSION401;
@@ -59,21 +60,42 @@
         return formatVersion >= FormatSpec.VERSION4_DEV;
     }
 
-    private File createEmptyDictionaryAndGetFile(final String dictId,
-            final int formatVersion) throws IOException {
+    private HashSet<File> mDictFilesToBeDeleted = new HashSet<>();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDictFilesToBeDeleted.clear();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        for (final File dictFile : mDictFilesToBeDeleted) {
+            dictFile.delete();
+        }
+        mDictFilesToBeDeleted.clear();
+        super.tearDown();
+    }
+
+    private File createEmptyDictionaryAndGetFile(final int formatVersion) {
         if (formatVersion == FormatSpec.VERSION4
                 || formatVersion == FormatSpec.VERSION4_ONLY_FOR_TESTING
                 || formatVersion == FormatSpec.VERSION4_DEV) {
-            return createEmptyVer4DictionaryAndGetFile(dictId, formatVersion);
+            try {
+                final File dictFile = createEmptyVer4DictionaryAndGetFile(formatVersion);
+                mDictFilesToBeDeleted.add(dictFile);
+                return dictFile;
+            } catch (final IOException e) {
+                fail(e.toString());
+            }
         } else {
-            throw new IOException("Dictionary format version " + formatVersion
-                    + " is not supported.");
+            fail("Dictionary format version " + formatVersion + " is not supported.");
         }
+        return null;
     }
 
-    private File createEmptyVer4DictionaryAndGetFile(final String dictId,
-            final int formatVersion) throws IOException {
-        final File file = File.createTempFile(dictId, TEST_DICT_FILE_EXTENSION,
+    private File createEmptyVer4DictionaryAndGetFile(final int formatVersion) throws IOException {
+        final File file = File.createTempFile(DICTIONARY_ID, TEST_DICT_FILE_EXTENSION,
                 getContext().getCacheDir());
         file.delete();
         file.mkdir();
@@ -87,6 +109,19 @@
         }
     }
 
+    private BinaryDictionary getBinaryDictionary(final File dictFile) {
+        return new BinaryDictionary(dictFile.getAbsolutePath(),
+                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+    }
+
+    private BinaryDictionary getEmptyBinaryDictionary(final int formatVersion) {
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        return new BinaryDictionary(dictFile.getAbsolutePath(),
+                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+    }
+
     public void testIsValidDictionary() {
         for (final int formatVersion : DICT_FORMAT_VERSIONS) {
             testIsValidDictionary(formatVersion);
@@ -94,24 +129,15 @@
     }
 
     private void testIsValidDictionary(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
         assertTrue("binaryDictionary must be valid for existing valid dictionary file.",
                 binaryDictionary.isValidDictionary());
         binaryDictionary.close();
         assertFalse("binaryDictionary must be invalid after closing.",
                 binaryDictionary.isValidDictionary());
         FileUtils.deleteRecursively(dictFile);
-        binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), 0 /* offset */,
-                dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(),
-                TEST_LOCALE, true /* isUpdatable */);
+        binaryDictionary = getBinaryDictionary(dictFile);
         assertFalse("binaryDictionary must be invalid for not existing dictionary file.",
                 binaryDictionary.isValidDictionary());
         binaryDictionary.close();
@@ -124,15 +150,10 @@
     }
 
     private void testConstructingDictionaryOnMemory(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
         FileUtils.deleteRecursively(dictFile);
         assertFalse(dictFile.exists());
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
                 true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, formatVersion,
                 new HashMap<String, String>());
         assertTrue(binaryDictionary.isValidDictionary());
@@ -147,7 +168,6 @@
         assertEquals(formatVersion, binaryDictionary.getFormatVersion());
         assertEquals(probability, binaryDictionary.getFrequency("word"));
         binaryDictionary.close();
-        dictFile.delete();
     }
 
     public void testAddTooLongWord() {
@@ -157,16 +177,7 @@
     }
 
     private void testAddTooLongWord(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
-
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
         final StringBuffer stringBuilder = new StringBuffer();
         for (int i = 0; i < Constants.DICTIONARY_MAX_WORD_LENGTH; i++) {
             stringBuilder.append('a');
@@ -195,7 +206,6 @@
         assertEquals(BinaryDictionary.NOT_A_PROBABILITY,
                 binaryDictionary.getFrequency(invalidLongWord));
         assertEquals(updatedProbability, binaryDictionary.getFrequency("abc"));
-        dictFile.delete();
     }
 
     private static void addUnigramWord(final BinaryDictionary binaryDictionary, final String word,
@@ -256,16 +266,7 @@
     }
 
     private void testAddUnigramWord(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
-
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
         final int probability = 100;
         addUnigramWord(binaryDictionary, "aaa", probability);
         // Reallocate and create.
@@ -289,8 +290,6 @@
         assertEquals(probability, binaryDictionary.getFrequency("aaaa"));
         assertEquals(probability, binaryDictionary.getFrequency("a"));
         assertEquals(updatedProbability, binaryDictionary.getFrequency("aaa"));
-
-        dictFile.delete();
     }
 
     public void testRandomlyAddUnigramWord() {
@@ -303,16 +302,7 @@
         final int wordCount = 1000;
         final int codePointSetSize = 50;
         final long seed = System.currentTimeMillis();
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
 
         final HashMap<String, Integer> probabilityMap = new HashMap<>();
         // Test a word that isn't contained within the dictionary.
@@ -328,7 +318,6 @@
         for (String word : probabilityMap.keySet()) {
             assertEquals(word, (int)probabilityMap.get(word), binaryDictionary.getFrequency(word));
         }
-        dictFile.delete();
     }
 
     public void testAddBigramWords() {
@@ -338,15 +327,7 @@
     }
 
     private void testAddBigramWords(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
 
         final int unigramProbability = 100;
         final int bigramProbability = 150;
@@ -405,8 +386,6 @@
             assertEquals(updatedBigramProbability,
                     getBigramProbability(binaryDictionary, "abcde", "fghij"));
         }
-
-        dictFile.delete();
     }
 
     public void testRandomlyAddBigramWords() {
@@ -421,16 +400,7 @@
         final int codePointSetSize = 50;
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
 
         final ArrayList<String> words = new ArrayList<>();
         final ArrayList<Pair<String, String>> bigramWords = new ArrayList<>();
@@ -470,8 +440,6 @@
                         getBigramProbability(binaryDictionary, bigram.first, bigram.second));
             }
         }
-
-        dictFile.delete();
     }
 
     public void testRemoveBigramWords() {
@@ -481,15 +449,7 @@
     }
 
     private void testRemoveBigramWords(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
         final int unigramProbability = 100;
         final int bigramProbability = 150;
         addUnigramWord(binaryDictionary, "aaa", unigramProbability);
@@ -522,8 +482,6 @@
         // Test remove non-existing bigram operation.
         removeBigramEntry(binaryDictionary, "aaa", "abb");
         removeBigramEntry(binaryDictionary, "bcc", "aaa");
-
-        dictFile.delete();
     }
 
     public void testAddTrigramWords() {
@@ -535,16 +493,7 @@
     }
 
     private void testAddTrigramWords(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
-
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
         final int unigramProbability = 100;
         final int trigramProbability = 150;
         final int updatedTrigramProbability = 200;
@@ -572,8 +521,6 @@
         assertEquals(Dictionary.NOT_A_PROBABILITY,
                 getTrigramProbability(binaryDictionary, "aaa", "abb", "bcc"));
         assertTrue(isValidBigram(binaryDictionary, "abb", "bcc"));
-
-        dictFile.delete();
     }
 
     public void testFlushDictionary() {
@@ -583,15 +530,8 @@
     }
 
     private void testFlushDictionary(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
 
         final int probability = 100;
         addUnigramWord(binaryDictionary, "aaa", probability);
@@ -611,23 +551,16 @@
         binaryDictionary.flush();
         binaryDictionary.close();
 
-        binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
-
+        binaryDictionary = getBinaryDictionary(dictFile);
         assertEquals(probability, binaryDictionary.getFrequency("aaa"));
         assertEquals(probability, binaryDictionary.getFrequency("abcd"));
         addUnigramWord(binaryDictionary, "bcde", probability);
         binaryDictionary.flush();
         binaryDictionary.close();
 
-        binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        binaryDictionary = getBinaryDictionary(dictFile);
         assertEquals(probability, binaryDictionary.getFrequency("bcde"));
         binaryDictionary.close();
-
-        dictFile.delete();
     }
 
     public void testFlushWithGCDictionary() {
@@ -637,16 +570,8 @@
     }
 
     private void testFlushWithGCDictionary(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
-
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
         final int unigramProbability = 100;
         final int bigramProbability = 150;
         addUnigramWord(binaryDictionary, "aaa", unigramProbability);
@@ -659,9 +584,7 @@
         binaryDictionary.flushWithGC();
         binaryDictionary.close();
 
-        binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        binaryDictionary = getBinaryDictionary(dictFile);
         assertEquals(unigramProbability, binaryDictionary.getFrequency("aaa"));
         assertEquals(unigramProbability, binaryDictionary.getFrequency("abb"));
         assertEquals(unigramProbability, binaryDictionary.getFrequency("bcc"));
@@ -676,8 +599,6 @@
         assertFalse(isValidBigram(binaryDictionary, "aaa", "aaa"));
         binaryDictionary.flushWithGC();
         binaryDictionary.close();
-
-        dictFile.delete();
     }
 
     public void testAddBigramWordsAndFlashWithGC() {
@@ -694,16 +615,8 @@
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
 
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
 
         final ArrayList<String> words = new ArrayList<>();
         final ArrayList<Pair<String, String>> bigramWords = new ArrayList<>();
@@ -736,10 +649,7 @@
 
         binaryDictionary.flushWithGC();
         binaryDictionary.close();
-        binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
-
+        binaryDictionary = getBinaryDictionary(dictFile);
 
         for (final Pair<String, String> bigram : bigramWords) {
             final int bigramProbability = bigramProbabilities.get(bigram);
@@ -750,8 +660,6 @@
                         getBigramProbability(binaryDictionary, bigram.first, bigram.second));
             }
         }
-
-        dictFile.delete();
     }
 
     public void testRandomOperationsAndFlashWithGC() {
@@ -771,17 +679,9 @@
 
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
 
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-
-        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
         final ArrayList<String> words = new ArrayList<>();
         final ArrayList<Pair<String, String>> bigramWords = new ArrayList<>();
         final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
@@ -798,9 +698,7 @@
         binaryDictionary.close();
 
         for (int gcCount = 0; gcCount < flashWithGCIterationCount; gcCount++) {
-            binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                    0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                    Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+            binaryDictionary = getBinaryDictionary(dictFile);
             for (int opCount = 0; opCount < operationCountInEachIteration; opCount++) {
                 // Add unigram.
                 if (random.nextFloat() < addUnigramProb) {
@@ -867,8 +765,6 @@
             binaryDictionary.flushWithGC();
             binaryDictionary.close();
         }
-
-        dictFile.delete();
     }
 
     public void testAddManyUnigramsAndFlushWithGC() {
@@ -884,12 +780,7 @@
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
 
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
 
         final ArrayList<String> words = new ArrayList<>();
         final HashMap<String, Integer> unigramProbabilities = new HashMap<>();
@@ -897,9 +788,7 @@
 
         BinaryDictionary binaryDictionary;
         for (int i = 0; i < flashWithGCIterationCount; i++) {
-            binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                    0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                    Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+            binaryDictionary = getBinaryDictionary(dictFile);
             while(!binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) {
                 final String word = CodePointUtils.generateWord(random, codePointSet);
                 words.add(word);
@@ -917,8 +806,6 @@
             binaryDictionary.flushWithGC();
             binaryDictionary.close();
         }
-
-        dictFile.delete();
     }
 
     public void testUnigramAndBigramCount() {
@@ -934,13 +821,7 @@
         final int bigramCountPerIteration = 2000;
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
 
         final ArrayList<String> words = new ArrayList<>();
         final HashSet<Pair<String, String>> bigrams = new HashSet<>();
@@ -948,9 +829,7 @@
 
         BinaryDictionary binaryDictionary;
         for (int i = 0; i < flashWithGCIterationCount; i++) {
-            binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                    0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                    Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+            binaryDictionary = getBinaryDictionary(dictFile);
             for (int j = 0; j < unigramCountPerIteration; j++) {
                 final String word = CodePointUtils.generateWord(random, codePointSet);
                 words.add(word);
@@ -982,8 +861,6 @@
                             BinaryDictionary.BIGRAM_COUNT_QUERY)));
             binaryDictionary.close();
         }
-
-        dictFile.delete();
     }
 
     public void testAddMultipleDictionaryEntries() {
@@ -998,13 +875,7 @@
         final double bigramContinueRate = 0.9;
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
 
         final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
         final HashMap<String, Integer> unigramProbabilities = new HashMap<>();
@@ -1029,9 +900,7 @@
             prevWord = (random.nextDouble() < bigramContinueRate) ? word : null;
         }
 
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
         binaryDictionary.addMultipleDictionaryEntries(languageModelParams);
 
         for (Map.Entry<String, Integer> entry : unigramProbabilities.entrySet()) {
@@ -1064,16 +933,8 @@
         final int BIGRAM_COUNT = 1000;
         final int codePointSetSize = 20;
         final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+        final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
 
         final WordProperty invalidWordProperty = binaryDictionary.getWordProperty("dummyWord",
                 false /* isBeginningOfSentence */);
@@ -1168,16 +1029,7 @@
         final int BIGRAM_COUNT = 1000;
         final int codePointSetSize = 20;
         final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
 
         final WordProperty invalidWordProperty = binaryDictionary.getWordProperty("dummyWord",
                 false /* isBeginningOfSentence */);
@@ -1237,15 +1089,17 @@
             wordSet.remove(word0);
             final HashSet<String> bigramWord1s = bigrams.get(word0);
             // TODO: Support ngram.
-            for (final WeightedString bigramTarget : wordProperty.getBigrams()) {
-                final String word1 = bigramTarget.mWord;
-                assertTrue(bigramWord1s.contains(word1));
-                final Pair<String, String> bigram = new Pair<>(word0, word1);
-                if (canCheckBigramProbability(formatVersion)) {
-                    final int bigramProbability = bigramProbabilitiesToCheckLater.get(bigram);
-                    assertEquals(bigramProbability, bigramTarget.getProbability());
+            if (wordProperty.mHasNgrams) {
+                for (final WeightedString bigramTarget : wordProperty.getBigrams()) {
+                    final String word1 = bigramTarget.mWord;
+                    assertTrue(bigramWord1s.contains(word1));
+                    final Pair<String, String> bigram = new Pair<>(word0, word1);
+                    if (canCheckBigramProbability(formatVersion)) {
+                        final int bigramProbability = bigramProbabilitiesToCheckLater.get(bigram);
+                        assertEquals(bigramProbability, bigramTarget.getProbability());
+                    }
+                    bigramSet.remove(bigram);
                 }
-                bigramSet.remove(bigram);
             }
             token = result.mNextToken;
         } while (token != 0);
@@ -1260,15 +1114,7 @@
     }
 
     private void testAddShortcuts(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
 
         final int unigramProbability = 100;
         final int shortcutProbability = 10;
@@ -1336,16 +1182,7 @@
         final ArrayList<String> words = new ArrayList<>();
         final HashMap<String, Integer> unigramProbabilities = new HashMap<>();
         final HashMap<String, HashMap<String, Integer>> shortcutTargets = new HashMap<>();
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
 
         for (int i = 0; i < UNIGRAM_COUNT; i++) {
             final String word = CodePointUtils.generateWord(random, codePointSet);
@@ -1403,15 +1240,7 @@
     }
 
     private void testDictMigration(final int fromFormatVersion, final int toFormatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", fromFormatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(fromFormatVersion);
         final int unigramProbability = 100;
         addUnigramWord(binaryDictionary, "aaa", unigramProbability);
         addUnigramWord(binaryDictionary, "bbb", unigramProbability);
@@ -1463,16 +1292,7 @@
         final int codePointSetSize = 50;
         final long seed = System.currentTimeMillis();
         final Random random = new Random(seed);
-
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", fromFormatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(fromFormatVersion);
 
         final ArrayList<String> words = new ArrayList<>();
         final ArrayList<Pair<String, String>> bigrams = new ArrayList<>();
@@ -1538,15 +1358,7 @@
     }
 
     private void testBeginningOfSentence(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
         final int dummyProbability = 0;
         final NgramContext beginningOfSentenceContext = NgramContext.BEGINNING_OF_SENTENCE;
         final int bigramProbability = 200;
@@ -1574,15 +1386,7 @@
     }
 
     private void testGetMaxFrequencyOfExactMatches(final int formatVersion) {
-        File dictFile = null;
-        try {
-            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
-        } catch (IOException e) {
-            fail("IOException while writing an initial dictionary : " + e);
-        }
-        final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
-                0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
-                Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+        final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
         addUnigramWord(binaryDictionary, "abc", 10);
         addUnigramWord(binaryDictionary, "aBc", 15);
         assertEquals(15, binaryDictionary.getMaxFrequencyOfExactMatches("abc"));
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
index 3f324c4..637ea4e 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
@@ -716,11 +716,13 @@
                 }
                 assertTrue(shortcutList.isEmpty());
             }
-            for (final WeightedString bigramTarget : wordProperty.getBigrams()) {
-                final String word1 = bigramTarget.mWord;
-                final Pair<String, String> bigram = new Pair<>(word0, word1);
-                assertTrue(bigramSet.contains(bigram));
-                bigramSet.remove(bigram);
+            if (wordProperty.mHasNgrams) {
+                for (final WeightedString bigramTarget : wordProperty.getBigrams()) {
+                    final String word1 = bigramTarget.mWord;
+                    final Pair<String, String> bigram = new Pair<>(word0, word1);
+                    assertTrue(bigramSet.contains(bigram));
+                    bigramSet.remove(bigram);
+                }
             }
             token = result.mNextToken;
         } while (token != 0);
diff --git a/tools/dicttool/compat/com/android/inputmethod/keyboard/ProximityInfo.java b/tools/dicttool/compat/com/android/inputmethod/keyboard/ProximityInfo.java
index 561b663..3a068bd 100644
--- a/tools/dicttool/compat/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/tools/dicttool/compat/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -18,11 +18,10 @@
 
 public class ProximityInfo {
     public long getNativeProximityInfo() { return 0l; }
-    private static native long setProximityInfoNative(String locale,
-            int displayWidth, int displayHeight, int gridWidth, int gridHeight,
-            int mostCommonKeyWidth, int mostCommonKeyHeight, int[] proximityCharsArray,
-            int keyCount, int[] keyXCoordinates, int[] keyYCoordinates, int[] keyWidths,
-            int[] keyHeights, int[] keyCharCodes, float[] sweetSpotCenterXs,
+    private static native long setProximityInfoNative(int displayWidth, int displayHeight,
+            int gridWidth, int gridHeight, int mostCommonKeyWidth, int mostCommonKeyHeight,
+            int[] proximityCharsArray, int keyCount, int[] keyXCoordinates, int[] keyYCoordinates,
+            int[] keyWidths, int[] keyHeights, int[] keyCharCodes, float[] sweetSpotCenterXs,
             float[] sweetSpotCenterYs, float[] sweetSpotRadii);
     private static native void releaseProximityInfoNative(long nativeProximityInfo);
 }
diff --git a/tools/make-keyboard-text/res/values-ne-rNP/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ne-rNP/donottranslate-more-keys.xml
index 97c50d1..56b594f 100644
--- a/tools/make-keyboard-text/res/values-ne-rNP/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-ne-rNP/donottranslate-more-keys.xml
@@ -57,4 +57,9 @@
     <string name="additional_morekeys_symbols_0">0</string>
     <!-- U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN -->
     <string name="keyspec_currency">&#x0930;&#x0941;&#x002E;</string>
+    <!-- U+0964: "।" DEVANAGARI DANDA -->
+    <string name="keyspec_period">&#x0964;</string>
+    <string name="keyspec_tablet_period">&#x0964;</string>
+    <string name="morekeys_period">"!autoColumnOrder!9,.,\\,,?,!,#,),(,/,;,',@,:,-,\",+,\\%,&amp;"</string>
+    <string name="morekeys_tablet_period">"!autoColumnOrder!8,.,\\,,',#,),(,/,;,@,:,-,\",+,\\%,&amp;"</string>
 </resources>