Merge "Move gesture preview trail parameters to resource"
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index bc9e8cd..1fe23a3 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -29,17 +29,18 @@
 import android.content.res.XmlResourceParser;
 import android.text.InputType;
 import android.text.TextUtils;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.Xml;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
-import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.compat.EditorInfoCompatUtils;
 import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
 import com.android.inputmethod.keyboard.internal.KeyboardParams;
 import com.android.inputmethod.keyboard.internal.KeysCache;
+import com.android.inputmethod.latin.AdditionalSubtype;
 import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.InputAttributes;
 import com.android.inputmethod.latin.InputTypeUtils;
@@ -72,6 +73,8 @@
     private static final String TAG_ELEMENT = "Element";
 
     private static final String KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX = "keyboard_layout_set_";
+    private static final int SPELLCHECKER_DUMMY_KEYBOARD_WIDTH = 480;
+    private static final int SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT = 800;
 
     private final Context mContext;
     private final Params mParams;
@@ -282,8 +285,7 @@
             return this;
         }
 
-        @UsedForTesting
-        public void disableTouchPositionCorrectionDataForTest() {
+        public void disableTouchPositionCorrectionData() {
             mParams.mDisableTouchPositionCorrectionDataForTest = true;
         }
 
@@ -413,4 +415,47 @@
             }
         }
     }
+
+    public static KeyboardLayoutSet createKeyboardSetForSpellChecker(final Context context,
+            final String locale, final String layout) {
+        final InputMethodSubtype subtype =
+                AdditionalSubtype.createAdditionalSubtype(locale, layout, null);
+        return createKeyboardSet(context, subtype, SPELLCHECKER_DUMMY_KEYBOARD_WIDTH,
+                SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT, false);
+    }
+
+    public static KeyboardLayoutSet createKeyboardSetForTest(final Context context,
+            final InputMethodSubtype subtype, final int orientation,
+            final boolean testCasesHaveTouchCoordinates) {
+        final DisplayMetrics dm = context.getResources().getDisplayMetrics();
+        final int width;
+        final int height;
+        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            width = Math.max(dm.widthPixels, dm.heightPixels);
+            height = Math.min(dm.widthPixels, dm.heightPixels);
+        } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+            width = Math.min(dm.widthPixels, dm.heightPixels);
+            height = Math.max(dm.widthPixels, dm.heightPixels);
+        } else {
+            throw new RuntimeException("Orientation should be ORIENTATION_LANDSCAPE or "
+                    + "ORIENTATION_PORTRAIT: orientation=" + orientation);
+        }
+        return createKeyboardSet(context, subtype, width, height, testCasesHaveTouchCoordinates);
+    }
+
+    private static KeyboardLayoutSet createKeyboardSet(final Context context,
+            final InputMethodSubtype subtype, final int width, final int height,
+            final boolean testCasesHaveTouchCoordinates) {
+        final EditorInfo editorInfo = new EditorInfo();
+        editorInfo.inputType = InputType.TYPE_CLASS_TEXT;
+        final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
+                context, editorInfo);
+        builder.setScreenGeometry(width, height);
+        builder.setSubtype(subtype);
+        if (!testCasesHaveTouchCoordinates) {
+            // For spell checker and tests
+            builder.disableTouchPositionCorrectionData();
+        }
+        return builder.build();
+    }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index b77e378..57d3fed 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -79,23 +79,6 @@
         mNativeProximityInfo = createNativeProximityInfo(touchPositionCorrection);
     }
 
-    /**
-     * Constructor for subclasses such as
-     * {@link com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo}.
-     */
-    protected ProximityInfo(final int[] proximityCharsArray, final int gridWidth,
-            final int gridHeight) {
-        this("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null);
-        mNativeProximityInfo = setProximityInfoNative("" /* locale */,
-                gridWidth /* displayWidth */, gridHeight /* displayHeight */,
-                gridWidth, gridHeight, 1 /* mostCommonKeyWidth */,
-                1 /* mostCommonKeyHeight */, proximityCharsArray, 0 /* keyCount */,
-                null /*keyXCoordinates */, null /* keyYCoordinates */,
-                null /* keyWidths */, null /* keyHeights */, null /* keyCharCodes */,
-                null /* sweetSpotCenterXs */, null /* sweetSpotCenterYs */,
-                null /* sweetSpotRadii */);
-    }
-
     private long mNativeProximityInfo;
     static {
         JniUtils.loadNativeLibrary();
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 75c2cf2..d660f70 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -20,8 +20,10 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.database.Cursor;
+import android.net.Uri;
 import android.os.SystemClock;
 import android.provider.BaseColumns;
+import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
 import android.text.TextUtils;
 import android.util.Log;
@@ -30,7 +32,7 @@
 
 public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
 
-    private static final String[] PROJECTION = {BaseColumns._ID, Contacts.DISPLAY_NAME,};
+    private static final String[] PROJECTION = {BaseColumns._ID, Contacts.DISPLAY_NAME};
     private static final String[] PROJECTION_ID_ONLY = {BaseColumns._ID};
 
     private static final String TAG = ContactsBinaryDictionary.class.getSimpleName();
@@ -102,9 +104,16 @@
 
     @Override
     public void loadDictionaryAsync() {
+        clearFusionDictionary();
+        loadDictionaryAsyncForUri(ContactsContract.Profile.CONTENT_URI);
+        // TODO: Switch this URL to the newer ContactsContract too
+        loadDictionaryAsyncForUri(Contacts.CONTENT_URI);
+    }
+
+    private void loadDictionaryAsyncForUri(final Uri uri) {
         try {
             Cursor cursor = mContext.getContentResolver()
-                    .query(Contacts.CONTENT_URI, PROJECTION, null, null, null);
+                    .query(uri, PROJECTION, null, null, null);
             if (cursor != null) {
                 try {
                     if (cursor.moveToFirst()) {
@@ -129,7 +138,6 @@
     }
 
     private void addWords(final Cursor cursor) {
-        clearFusionDictionary();
         int count = 0;
         while (!cursor.isAfterLast() && count < MAX_CONTACT_COUNT) {
             String name = cursor.getString(INDEX_NAME);
@@ -173,6 +181,9 @@
                 // capitalization of i.
                 final int wordLen = StringUtils.codePointCount(word);
                 if (wordLen < MAX_WORD_LENGTH && wordLen > 1) {
+                    if (DEBUG) {
+                        Log.d(TAG, "addName " + name + ", " + word + ", " + prevWord);
+                    }
                     super.addWord(word, null /* shortcut */, FREQUENCY_FOR_CONTACTS,
                             false /* isNotAWord */);
                     if (!TextUtils.isEmpty(prevWord)) {
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 51bd901..e078f03 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,7 +16,6 @@
 
 package com.android.inputmethod.latin;
 
-import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 
@@ -211,9 +210,8 @@
     }
 
     /**
-     * Internal method to retrieve reasonable proximity info for a character.
+     * Add a dummy key by retrieving reasonable coordinates
      */
-    @UsedForTesting
     public void addKeyInfo(final int codePoint, final Keyboard keyboard) {
         final int x, y;
         final Key key;
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
index affe3a3..acb0766 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
@@ -190,18 +190,13 @@
                 .path(Integer.toString(R.raw.setup_welcome_video))
                 .build();
         mWelcomeVideoView = (VideoView)findViewById(R.id.setup_welcome_video);
-        mWelcomeVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
-            @Override
-            public void onCompletion(final MediaPlayer mp) {
-                mp.start();
-            }
-        });
         mWelcomeVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
             @Override
             public void onPrepared(final MediaPlayer mp) {
                 // Now VideoView has been laid-out and ready to play, remove background of it to
                 // reveal the video.
                 mWelcomeVideoView.setBackgroundResource(0);
+                mp.setLooping(true);
             }
         });
         final ImageView welcomeImageView = (ImageView)findViewById(R.id.setup_welcome_image);
@@ -365,9 +360,14 @@
         super.onBackPressed();
     }
 
+    private static void hideAndStopVideo(final VideoView videoView) {
+        videoView.stopPlayback();
+        videoView.setVisibility(View.INVISIBLE);
+    }
+
     @Override
     protected void onPause() {
-        mWelcomeVideoView.stopPlayback();
+        hideAndStopVideo(mWelcomeVideoView);
         super.onPause();
     }
 
@@ -385,11 +385,12 @@
         mWelcomeScreen.setVisibility(welcomeScreen ? View.VISIBLE : View.GONE);
         mSetupScreen.setVisibility(welcomeScreen ? View.GONE: View.VISIBLE);
         if (welcomeScreen) {
+            mWelcomeVideoView.setVisibility(View.VISIBLE);
             mWelcomeVideoView.setVideoURI(mWelcomeVideoUri);
             mWelcomeVideoView.start();
             return;
         }
-        mWelcomeVideoView.stopPlayback();
+        hideAndStopVideo(mWelcomeVideoView);
         final boolean isStepActionAlreadyDone = mStepNumber < determineSetupStepNumber();
         mSetupStepGroup.enableStep(mStepNumber, isStepActionAlreadyDone);
         mActionNext.setVisibility(isStepActionAlreadyDone ? View.VISIBLE : View.GONE);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index aa60496..13fcaf4 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -23,7 +23,7 @@
 import android.util.Log;
 import android.view.textservice.SuggestionsInfo;
 
-import com.android.inputmethod.keyboard.ProximityInfo;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
 import com.android.inputmethod.latin.BinaryDictionary;
 import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.ContactsBinaryDictionary;
@@ -126,6 +126,19 @@
         return script;
     }
 
+    private static String getKeyboardLayoutNameForScript(final int script) {
+        switch (script) {
+        case AndroidSpellCheckerService.SCRIPT_LATIN:
+            return "qwerty";
+        case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
+            return "east_slavic";
+        case AndroidSpellCheckerService.SCRIPT_GREEK:
+            return "greek";
+        default:
+            throw new RuntimeException("Wrong script supplied: " + script);
+        }
+    }
+
     @Override
     public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
         if (!PREF_USE_CONTACTS_KEY.equals(key)) return;
@@ -385,9 +398,13 @@
         return pool;
     }
 
-    public DictAndProximity createDictAndProximity(final Locale locale) {
+    public DictAndKeyboard createDictAndKeyboard(final Locale locale) {
         final int script = getScriptFromLocale(locale);
-        final ProximityInfo proximityInfo = new SpellCheckerProximityInfo(script);
+        final String keyboardLayoutName = getKeyboardLayoutNameForScript(script);
+        final KeyboardLayoutSet keyboardLayoutSet =
+                KeyboardLayoutSet.createKeyboardSetForSpellChecker(this, locale.toString(),
+                        keyboardLayoutName);
+
         final DictionaryCollection dictionaryCollection =
                 DictionaryFactory.createMainDictionaryFromManager(this, locale,
                         true /* useFullEditDistance */);
@@ -412,6 +429,6 @@
             mDictionaryCollectionsList.add(
                     new WeakReference<DictionaryCollection>(dictionaryCollection));
         }
-        return new DictAndProximity(dictionaryCollection, proximityInfo);
+        return new DictAndKeyboard(dictionaryCollection, keyboardLayoutSet);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 61850e4..16e9fb7 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -257,7 +257,7 @@
             }
 
             if (shouldFilterOut(inText, mScript)) {
-                DictAndProximity dictInfo = null;
+                DictAndKeyboard dictInfo = null;
                 try {
                     dictInfo = mDictionaryPool.pollWithDefaultTimeout();
                     if (!DictionaryPool.isAValidDictionary(dictInfo)) {
@@ -286,7 +286,7 @@
 
             final int capitalizeType = StringUtils.getCapitalizationType(text);
             boolean isInDict = true;
-            DictAndProximity dictInfo = null;
+            DictAndKeyboard dictInfo = null;
             try {
                 dictInfo = mDictionaryPool.pollWithDefaultTimeout();
                 if (!DictionaryPool.isAValidDictionary(dictInfo)) {
@@ -296,20 +296,13 @@
                 final int length = text.length();
                 for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) {
                     final int codePoint = text.codePointAt(i);
-                    // The getXYForCodePointAndScript method returns (Y << 16) + X
-                    final int xy = SpellCheckerProximityInfo.getXYForCodePointAndScript(
-                            codePoint, mScript);
-                    if (SpellCheckerProximityInfo.NOT_A_COORDINATE_PAIR == xy) {
-                        composer.add(codePoint,
-                                Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
-                    } else {
-                        composer.add(codePoint, xy & 0xFFFF, xy >> 16);
-                    }
+                    composer.addKeyInfo(codePoint, dictInfo.getKeyboard(codePoint));
                 }
                 // TODO: make a spell checker option to block offensive words or not
                 final ArrayList<SuggestedWordInfo> suggestions =
                         dictInfo.mDictionary.getSuggestions(composer, prevWord,
-                                dictInfo.mProximityInfo, true /* blockOffensiveWords */);
+                                dictInfo.getProximityInfo(),
+                                true /* blockOffensiveWords */);
                 for (final SuggestedWordInfo suggestion : suggestions) {
                     final String suggestionStr = suggestion.mWord;
                     suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0,
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java b/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java
new file mode 100644
index 0000000..b77f3e2
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.inputmethod.latin.spellcheck;
+
+import com.android.inputmethod.latin.Dictionary;
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.ProximityInfo;
+
+/**
+ * A container for a Dictionary and a Keyboard.
+ */
+public final class DictAndKeyboard {
+    public final Dictionary mDictionary;
+    private final Keyboard mKeyboard;
+    private final Keyboard mManualShiftedKeyboard;
+
+    public DictAndKeyboard(
+            final Dictionary dictionary, final KeyboardLayoutSet keyboardLayoutSet) {
+        mDictionary = dictionary;
+        if (keyboardLayoutSet == null) {
+            mKeyboard = null;
+            mManualShiftedKeyboard = null;
+            return;
+        }
+        mKeyboard = keyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
+        mManualShiftedKeyboard =
+                keyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED);
+    }
+
+    public Keyboard getKeyboard(final int codePoint) {
+        if (mKeyboard == null) {
+            return null;
+        }
+        return mKeyboard.getKey(codePoint) != null ? mKeyboard : mManualShiftedKeyboard;
+    }
+
+    public ProximityInfo getProximityInfo() {
+        return mKeyboard == null ? null : mKeyboard.getProximityInfo();
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java b/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java
deleted file mode 100644
index 017a4f5..0000000
--- a/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-package com.android.inputmethod.latin.spellcheck;
-
-import com.android.inputmethod.latin.Dictionary;
-import com.android.inputmethod.keyboard.ProximityInfo;
-
-/**
- * A simple container for both a Dictionary and a ProximityInfo.
- */
-public final class DictAndProximity {
-    public final Dictionary mDictionary;
-    public final ProximityInfo mProximityInfo;
-    public DictAndProximity(final Dictionary dictionary, final ProximityInfo proximityInfo) {
-        mDictionary = dictionary;
-        mProximityInfo = proximityInfo;
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
index 27964b3..a20e09e 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
@@ -36,7 +36,7 @@
  * the client code, but may help with sloppy clients.
  */
 @SuppressWarnings("serial")
-public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> {
+public final class DictionaryPool extends LinkedBlockingQueue<DictAndKeyboard> {
     private final static String TAG = DictionaryPool.class.getSimpleName();
     // How many seconds we wait for a dictionary to become available. Past this delay, we give up in
     // fear some bug caused a deadlock, and reset the whole pool.
@@ -47,7 +47,7 @@
     private int mSize;
     private volatile boolean mClosed;
     final static ArrayList<SuggestedWordInfo> noSuggestions = CollectionUtils.newArrayList();
-    private final static DictAndProximity dummyDict = new DictAndProximity(
+    private final static DictAndKeyboard dummyDict = new DictAndKeyboard(
             new Dictionary(Dictionary.TYPE_MAIN) {
                 @Override
                 public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
@@ -64,7 +64,7 @@
                 }
             }, null);
 
-    static public boolean isAValidDictionary(final DictAndProximity dictInfo) {
+    static public boolean isAValidDictionary(final DictAndKeyboard dictInfo) {
         return null != dictInfo && dummyDict != dictInfo;
     }
 
@@ -79,32 +79,32 @@
     }
 
     @Override
-    public DictAndProximity poll(final long timeout, final TimeUnit unit)
+    public DictAndKeyboard poll(final long timeout, final TimeUnit unit)
             throws InterruptedException {
-        final DictAndProximity dict = poll();
+        final DictAndKeyboard dict = poll();
         if (null != dict) return dict;
         synchronized(this) {
             if (mSize >= mMaxSize) {
                 // Our pool is already full. Wait until some dictionary is ready, or TIMEOUT
                 // expires to avoid a deadlock.
-                final DictAndProximity result = super.poll(timeout, unit);
+                final DictAndKeyboard result = super.poll(timeout, unit);
                 if (null == result) {
                     Log.e(TAG, "Deadlock detected ! Resetting dictionary pool");
                     clear();
                     mSize = 1;
-                    return mService.createDictAndProximity(mLocale);
+                    return mService.createDictAndKeyboard(mLocale);
                 } else {
                     return result;
                 }
             } else {
                 ++mSize;
-                return mService.createDictAndProximity(mLocale);
+                return mService.createDictAndKeyboard(mLocale);
             }
         }
     }
 
     // Convenience method
-    public DictAndProximity pollWithDefaultTimeout() {
+    public DictAndKeyboard pollWithDefaultTimeout() {
         try {
             return poll(TIMEOUT, TimeUnit.SECONDS);
         } catch (InterruptedException e) {
@@ -115,7 +115,7 @@
     public void close() {
         synchronized(this) {
             mClosed = true;
-            for (DictAndProximity dict : this) {
+            for (DictAndKeyboard dict : this) {
                 dict.mDictionary.close();
             }
             clear();
@@ -123,7 +123,7 @@
     }
 
     @Override
-    public boolean offer(final DictAndProximity dict) {
+    public boolean offer(final DictAndKeyboard dict) {
         if (mClosed) {
             dict.mDictionary.close();
             return super.offer(dummyDict);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
deleted file mode 100644
index 0c480ea..0000000
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-package com.android.inputmethod.latin.spellcheck;
-
-import android.util.SparseIntArray;
-
-import com.android.inputmethod.keyboard.ProximityInfo;
-import com.android.inputmethod.latin.Constants;
-
-public final class SpellCheckerProximityInfo extends ProximityInfo {
-    public SpellCheckerProximityInfo(final int script) {
-        super(getProximityForScript(script), PROXIMITY_GRID_WIDTH, PROXIMITY_GRID_HEIGHT);
-    }
-
-    private static final int NUL = Constants.NOT_A_CODE;
-
-    // This must be the same as MAX_PROXIMITY_CHARS_SIZE else it will not work inside
-    // native code - this value is passed at creation of the binary object and reused
-    // as the size of the passed array afterwards so they can't be different.
-    private static final int ROW_SIZE = ProximityInfo.MAX_PROXIMITY_CHARS_SIZE;
-
-    // The number of keys in a row of the grid used by the spell checker.
-    private static final int PROXIMITY_GRID_WIDTH = 11;
-    // The number of rows in the grid used by the spell checker.
-    private static final int PROXIMITY_GRID_HEIGHT = 3;
-
-    private static final int NOT_AN_INDEX = -1;
-    public static final int NOT_A_COORDINATE_PAIR = -1;
-
-    // Helper methods
-    static void buildProximityIndices(final int[] proximity, final int rowSize,
-            final SparseIntArray indices) {
-        for (int i = 0; i < proximity.length; i += rowSize) {
-            if (NUL != proximity[i]) indices.put(proximity[i], i / rowSize);
-        }
-    }
-
-    private static final class Latin {
-        // The proximity here is the union of
-        // - the proximity for a QWERTY keyboard.
-        // - the proximity for an AZERTY keyboard.
-        // - the proximity for a QWERTZ keyboard.
-        // ...plus, add all characters in the ('a', 'e', 'i', 'o', 'u') set to each other.
-        //
-        // The reasoning behind this construction is, almost any alphabetic text we may want
-        // to spell check has been entered with one of the keyboards above. Also, specifically
-        // to English, many spelling errors consist of the last vowel of the word being wrong
-        // because in English vowels tend to merge with each other in pronunciation.
-        /*
-        The Qwerty layout this represents looks like the following:
-            q w e r t y u i o p
-             a s d f g h j k l
-               z x c v b n m
-        */
-        static final int[] PROXIMITY = {
-            // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
-            // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
-            // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
-            'q', 'w', 's', 'a', 'z', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'w', 'q', 'a', 's', 'd', 'e', 'x', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'e', 'w', 's', 'd', 'f', 'r', 'a', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL,
-            'r', 'e', 'd', 'f', 'g', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            't', 'r', 'f', 'g', 'h', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'y', 't', 'g', 'h', 'j', 'u', 'a', 's', 'd', 'x', NUL, NUL, NUL, NUL, NUL, NUL,
-            'u', 'y', 'h', 'j', 'k', 'i', 'a', 'e', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'i', 'u', 'j', 'k', 'l', 'o', 'a', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'o', 'i', 'k', 'l', 'p', 'a', 'e', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'p', 'o', 'l', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-            // Proximity for row 2. See comment above about size.
-            'a', 'z', 'x', 's', 'w', 'q', 'e', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL,
-            's', 'q', 'a', 'z', 'x', 'c', 'd', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'd', 'w', 's', 'x', 'c', 'v', 'f', 'r', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'f', 'e', 'd', 'c', 'v', 'b', 'g', 't', 'r', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'g', 'r', 'f', 'v', 'b', 'n', 'h', 'y', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'h', 't', 'g', 'b', 'n', 'm', 'j', 'u', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'j', 'y', 'h', 'n', 'm', 'k', 'i', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'k', 'u', 'j', 'm', 'l', 'o', 'i', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'l', 'i', 'k', 'p', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-            // Proximity for row 3. See comment above about size.
-            'z', 'a', 's', 'd', 'x', 't', 'g', 'h', 'j', 'u', 'q', 'e', NUL, NUL, NUL, NUL,
-            'x', 'z', 'a', 's', 'd', 'c', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'c', 'x', 's', 'd', 'f', 'v', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'v', 'c', 'd', 'f', 'g', 'b', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'b', 'v', 'f', 'g', 'h', 'n', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'n', 'b', 'g', 'h', 'j', 'm', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'm', 'n', 'h', 'j', 'k', 'l', 'o', 'p', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-        };
-
-        // This is a mapping array from the code point to the index in the PROXIMITY array.
-        // When we check the spelling of a word, we need to pass (x,y) coordinates to the native
-        // code for each letter of the word. These are most easily computed from the index in the
-        // PROXIMITY array. Since we'll need to do that very often, the index lookup from the code
-        // point needs to be as fast as possible, and a map is probably the best way to do this.
-        // To avoid unnecessary boxing conversion to Integer, here we use SparseIntArray.
-        static final SparseIntArray INDICES = new SparseIntArray(PROXIMITY.length / ROW_SIZE);
-
-        static {
-            buildProximityIndices(PROXIMITY, ROW_SIZE, INDICES);
-        }
-    }
-
-    private static final class Cyrillic {
-        // TODO: The following table is solely based on the keyboard layout. Consult with Russian
-        // speakers on commonly misspelled words/letters.
-        /*
-        The Russian layout this represents looks like the following:
-            й ц у к е н г ш щ з х
-            ф ы в а п р о л д ж э
-              я ч с м и т ь б ю
-
-        This gives us the following table:
-            'й', 'ц', 'ф', 'ы', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ц', 'й', 'ф', 'ы', 'в', 'у', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'у', 'ц', 'ы', 'в', 'а', 'к', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'к', 'у', 'в', 'а', 'п', 'е', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'е', 'к', 'а', 'п', 'р', 'н', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'н', 'е', 'п', 'р', 'о', 'г', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'г', 'н', 'р', 'о', 'л', 'ш', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ш', 'г', 'о', 'л', 'д', 'щ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'щ', 'ш', 'л', 'д', 'ж', 'з', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'з', 'щ', 'д', 'ж', 'э', 'х', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'х', 'з', 'ж', 'э', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-            'ф', 'й', 'ц', 'ы', 'я', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ы', 'й', 'ц', 'у', 'ф', 'в', 'я', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'в', 'ц', 'у', 'к', 'ы', 'а', 'я', 'ч', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'а', 'у', 'к', 'е', 'в', 'п', 'ч', 'с', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'п', 'к', 'е', 'н', 'а', 'р', 'с', 'м', 'и', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'р', 'е', 'н', 'г', 'п', 'о', 'м', 'и', 'т', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'о', 'н', 'г', 'ш', 'р', 'л', 'и', 'т', 'ь', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'л', 'г', 'ш', 'щ', 'о', 'д', 'т', 'ь', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'д', 'ш', 'щ', 'з', 'л', 'ж', 'ь', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ж', 'щ', 'з', 'х', 'д', 'э', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'э', 'з', 'х', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-            'я', 'ф', 'ы', 'в', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ч', 'ы', 'в', 'а', 'я', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'с', 'в', 'а', 'п', 'ч', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'м', 'а', 'п', 'р', 'с', 'и', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'и', 'п', 'р', 'о', 'м', 'т', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'т', 'р', 'о', 'л', 'и', 'ь', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ь', 'о', 'л', 'д', 'т', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'б', 'л', 'д', 'ж', 'ь', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ю', 'д', 'ж', 'э', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-        Using the following characters:
-        */
-        private static final int CY_SHORT_I = '\u0439'; // й
-        private static final int CY_TSE = '\u0446'; // ц
-        private static final int CY_U = '\u0443'; // у
-        private static final int CY_KA = '\u043A'; // к
-        private static final int CY_IE = '\u0435'; // е
-        private static final int CY_EN = '\u043D'; // н
-        private static final int CY_GHE = '\u0433'; // г
-        private static final int CY_SHA = '\u0448'; // ш
-        private static final int CY_SHCHA = '\u0449'; // щ
-        private static final int CY_ZE = '\u0437'; // з
-        private static final int CY_HA = '\u0445'; // х
-        private static final int CY_EF = '\u0444'; // ф
-        private static final int CY_YERU = '\u044B'; // ы
-        private static final int CY_VE = '\u0432'; // в
-        private static final int CY_A = '\u0430'; // а
-        private static final int CY_PE = '\u043F'; // п
-        private static final int CY_ER = '\u0440'; // р
-        private static final int CY_O = '\u043E'; // о
-        private static final int CY_EL = '\u043B'; // л
-        private static final int CY_DE = '\u0434'; // д
-        private static final int CY_ZHE = '\u0436'; // ж
-        private static final int CY_E = '\u044D'; // э
-        private static final int CY_YA = '\u044F'; // я
-        private static final int CY_CHE = '\u0447'; // ч
-        private static final int CY_ES = '\u0441'; // с
-        private static final int CY_EM = '\u043C'; // м
-        private static final int CY_I = '\u0438'; // и
-        private static final int CY_TE = '\u0442'; // т
-        private static final int CY_SOFT_SIGN = '\u044C'; // ь
-        private static final int CY_BE = '\u0431'; // б
-        private static final int CY_YU = '\u044E'; // ю
-        static final int[] PROXIMITY = {
-            // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
-            // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
-            // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
-            CY_SHORT_I, CY_TSE, CY_EF, CY_YERU, NUL, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_TSE, CY_SHORT_I, CY_EF, CY_YERU, CY_VE, CY_U, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_U, CY_TSE, CY_YERU, CY_VE, CY_A, CY_KA, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_KA, CY_U, CY_VE, CY_A, CY_PE, CY_IE, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_IE, CY_KA, CY_A, CY_PE, CY_ER, CY_EN, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_EN, CY_IE, CY_PE, CY_ER, CY_O, CY_GHE, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_GHE, CY_EN, CY_ER, CY_O, CY_EL, CY_SHA, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_SHA, CY_GHE, CY_O, CY_EL, CY_DE, CY_SHCHA, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_SHCHA, CY_SHA, CY_EL, CY_DE, CY_ZHE, CY_ZE, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_ZE, CY_SHCHA, CY_DE, CY_ZHE, CY_E, CY_HA, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_HA, CY_ZE, CY_ZHE, CY_E, NUL, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-            // Proximity for row 2. See comment above about size.
-            CY_EF, CY_SHORT_I, CY_TSE, CY_YERU, CY_YA, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_YERU, CY_SHORT_I, CY_TSE, CY_U, CY_EF, CY_VE, CY_YA, CY_CHE,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_VE, CY_TSE, CY_U, CY_KA, CY_YERU, CY_A, CY_YA, CY_CHE,
-                    CY_ES, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_A, CY_U, CY_KA, CY_IE, CY_VE, CY_PE, CY_CHE, CY_ES,
-                    CY_EM, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_PE, CY_KA, CY_IE, CY_EN, CY_A, CY_ER, CY_ES, CY_EM,
-                    CY_I, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_ER, CY_IE, CY_EN, CY_GHE, CY_PE, CY_O, CY_EM, CY_I,
-                    CY_TE, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_O, CY_EN, CY_GHE, CY_SHA, CY_ER, CY_EL, CY_I, CY_TE,
-                    CY_SOFT_SIGN, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_EL, CY_GHE, CY_SHA, CY_SHCHA, CY_O, CY_DE, CY_TE, CY_SOFT_SIGN,
-                    CY_BE, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_DE, CY_SHA, CY_SHCHA, CY_ZE, CY_EL, CY_ZHE, CY_SOFT_SIGN, CY_BE,
-                    CY_YU, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_ZHE, CY_SHCHA, CY_ZE, CY_HA, CY_DE, CY_E, CY_BE, CY_YU,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_E, CY_ZE, CY_HA, CY_YU, NUL, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-            // Proximity for row 3. See comment above about size.
-            CY_YA, CY_EF, CY_YERU, CY_VE, CY_CHE, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_CHE, CY_YERU, CY_VE, CY_A, CY_YA, CY_ES, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_ES, CY_VE, CY_A, CY_PE, CY_CHE, CY_EM, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_EM, CY_A, CY_PE, CY_ER, CY_ES, CY_I, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_I, CY_PE, CY_ER, CY_O, CY_EM, CY_TE, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_TE, CY_ER, CY_O, CY_EL, CY_I, CY_SOFT_SIGN, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_SOFT_SIGN, CY_O, CY_EL, CY_DE, CY_TE, CY_BE, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_BE, CY_EL, CY_DE, CY_ZHE, CY_SOFT_SIGN, CY_YU, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            CY_YU, CY_DE, CY_ZHE, CY_E, CY_BE, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-        };
-
-        static final SparseIntArray INDICES = new SparseIntArray(PROXIMITY.length / ROW_SIZE);
-
-        static {
-            buildProximityIndices(PROXIMITY, ROW_SIZE, INDICES);
-        }
-    }
-
-    private static final class Greek {
-        // TODO: The following table is solely based on the keyboard layout. Consult with Greek
-        // speakers on commonly misspelled words/letters.
-        /*
-        The Greek layout this represents looks like the following:
-            ; ς ε ρ τ υ θ ι ο π
-             α σ δ φ γ η ξ κ λ
-               ζ χ ψ ω β ν μ
-
-        This gives us the following table:
-            'ς', 'ε', 'α', 'σ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ε', 'ς', 'ρ', 'σ', 'δ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ρ', 'ε', 'τ', 'δ', 'φ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'τ', 'ρ', 'υ', 'φ', 'γ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'υ', 'τ', 'θ', 'γ', 'η', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'θ', 'υ', 'ι', 'η', 'ξ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ι', 'θ', 'ο', 'ξ', 'κ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ο', 'ι', 'π', 'κ', 'λ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'π', 'ο', 'λ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-            'α', 'ς', 'σ', 'ζ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'σ', 'ς', 'ε', 'α', 'δ', 'ζ', 'χ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'δ', 'ε', 'ρ', 'σ', 'φ', 'ζ', 'χ', 'ψ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'φ', 'ρ', 'τ', 'δ', 'γ', 'χ', 'ψ', 'ω', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'γ', 'τ', 'υ', 'φ', 'η', 'ψ', 'ω', 'β', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'η', 'υ', 'θ', 'γ', 'ξ', 'ω', 'β', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ξ', 'θ', 'ι', 'η', 'κ', 'β', 'ν', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'κ', 'ι', 'ο', 'ξ', 'λ', 'ν', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'λ', 'ο', 'π', 'κ', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-            'ζ', 'α', 'σ', 'δ', 'χ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'χ', 'σ', 'δ', 'φ', 'ζ', 'ψ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ψ', 'δ', 'φ', 'γ', 'χ', 'ω', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ω', 'φ', 'γ', 'η', 'ψ', 'β', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'β', 'γ', 'η', 'ξ', 'ω', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'ν', 'η', 'ξ', 'κ', 'β', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            'μ', 'ξ', 'κ', 'λ', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-        Using the following characters:
-        */
-        private static final int GR_FINAL_SIGMA = '\u03C2'; // ς
-        private static final int GR_EPSILON = '\u03B5'; // ε
-        private static final int GR_RHO = '\u03C1'; // ρ
-        private static final int GR_TAU = '\u03C4'; // τ
-        private static final int GR_UPSILON = '\u03C5'; // υ
-        private static final int GR_THETA = '\u03B8'; // θ
-        private static final int GR_IOTA = '\u03B9'; // ι
-        private static final int GR_OMICRON = '\u03BF'; // ο
-        private static final int GR_PI = '\u03C0'; // π
-        private static final int GR_ALPHA = '\u03B1'; // α
-        private static final int GR_SIGMA = '\u03C3'; // σ
-        private static final int GR_DELTA = '\u03B4'; // δ
-        private static final int GR_PHI = '\u03C6'; // φ
-        private static final int GR_GAMMA = '\u03B3'; // γ
-        private static final int GR_ETA = '\u03B7'; // η
-        private static final int GR_XI = '\u03BE'; // ξ
-        private static final int GR_KAPPA = '\u03BA'; // κ
-        private static final int GR_LAMDA = '\u03BB'; // λ
-        private static final int GR_ZETA = '\u03B6'; // ζ
-        private static final int GR_CHI = '\u03C7'; // χ
-        private static final int GR_PSI = '\u03C8'; // ψ
-        private static final int GR_OMEGA = '\u03C9'; // ω
-        private static final int GR_BETA = '\u03B2'; // β
-        private static final int GR_NU = '\u03BD'; // ν
-        private static final int GR_MU = '\u03BC'; // μ
-        static final int[] PROXIMITY = {
-            // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
-            // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
-            // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
-            GR_FINAL_SIGMA, GR_EPSILON, GR_ALPHA, GR_SIGMA, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_EPSILON, GR_FINAL_SIGMA, GR_RHO, GR_SIGMA, GR_DELTA, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_RHO, GR_EPSILON, GR_TAU, GR_DELTA, GR_PHI, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_TAU, GR_RHO, GR_UPSILON, GR_PHI, GR_GAMMA, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_UPSILON, GR_TAU, GR_THETA, GR_GAMMA, GR_ETA, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_THETA, GR_UPSILON, GR_IOTA, GR_ETA, GR_XI, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_IOTA, GR_THETA, GR_OMICRON, GR_XI, GR_KAPPA, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_OMICRON, GR_IOTA, GR_PI, GR_KAPPA, GR_LAMDA, NUL, NUL, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_PI, GR_OMICRON, GR_LAMDA, NUL, NUL, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-            GR_ALPHA, GR_FINAL_SIGMA, GR_SIGMA, GR_ZETA, NUL, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_SIGMA, GR_FINAL_SIGMA, GR_EPSILON, GR_ALPHA, GR_DELTA, GR_ZETA, GR_CHI, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_DELTA, GR_EPSILON, GR_RHO, GR_SIGMA, GR_PHI, GR_ZETA, GR_CHI, GR_PSI,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_PHI, GR_RHO, GR_TAU, GR_DELTA, GR_GAMMA, GR_CHI, GR_PSI, GR_OMEGA,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_GAMMA, GR_TAU, GR_UPSILON, GR_PHI, GR_ETA, GR_PSI, GR_OMEGA, GR_BETA,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_ETA, GR_UPSILON, GR_THETA, GR_GAMMA, GR_XI, GR_OMEGA, GR_BETA, GR_NU,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_XI, GR_THETA, GR_IOTA, GR_ETA, GR_KAPPA, GR_BETA, GR_NU, GR_MU,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_KAPPA, GR_IOTA, GR_OMICRON, GR_XI, GR_LAMDA, GR_NU, GR_MU, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_LAMDA, GR_OMICRON, GR_PI, GR_KAPPA, GR_MU, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
-            GR_ZETA, GR_ALPHA, GR_SIGMA, GR_DELTA, GR_CHI, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_CHI, GR_SIGMA, GR_DELTA, GR_PHI, GR_ZETA, GR_PSI, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_PSI, GR_DELTA, GR_PHI, GR_GAMMA, GR_CHI, GR_OMEGA, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_OMEGA, GR_PHI, GR_GAMMA, GR_ETA, GR_PSI, GR_BETA, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_BETA, GR_GAMMA, GR_ETA, GR_XI, GR_OMEGA, GR_NU, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_NU, GR_ETA, GR_XI, GR_KAPPA, GR_BETA, GR_MU, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            GR_MU, GR_XI, GR_KAPPA, GR_LAMDA, GR_NU, NUL, NUL, NUL,
-                    NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-            NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-        };
-
-        static final SparseIntArray INDICES = new SparseIntArray(PROXIMITY.length / ROW_SIZE);
-
-        static {
-            buildProximityIndices(PROXIMITY, ROW_SIZE, INDICES);
-        }
-    }
-
-    private static int[] getProximityForScript(final int script) {
-        switch (script) {
-        case AndroidSpellCheckerService.SCRIPT_LATIN:
-            return Latin.PROXIMITY;
-        case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
-            return Cyrillic.PROXIMITY;
-        case AndroidSpellCheckerService.SCRIPT_GREEK:
-            return Greek.PROXIMITY;
-        default:
-            throw new RuntimeException("Wrong script supplied: " + script);
-        }
-    }
-
-    private static int getIndexOfCodeForScript(final int codePoint, final int script) {
-        switch (script) {
-        case AndroidSpellCheckerService.SCRIPT_LATIN:
-            return Latin.INDICES.get(codePoint, NOT_AN_INDEX);
-        case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
-            return Cyrillic.INDICES.get(codePoint, NOT_AN_INDEX);
-        case AndroidSpellCheckerService.SCRIPT_GREEK:
-            return Greek.INDICES.get(codePoint, NOT_AN_INDEX);
-        default:
-            throw new RuntimeException("Wrong script supplied: " + script);
-        }
-    }
-
-    // Returns (Y << 16) + X to avoid creating a temporary object. This is okay because
-    // X and Y are limited to PROXIMITY_GRID_WIDTH resp. PROXIMITY_GRID_HEIGHT which is very
-    // inferior to 1 << 16
-    // As an exception, this returns NOT_A_COORDINATE_PAIR if the key is not on the grid
-    public static int getXYForCodePointAndScript(final int codePoint, final int script) {
-        final int index = getIndexOfCodeForScript(codePoint, script);
-        if (NOT_AN_INDEX == index) return NOT_A_COORDINATE_PAIR;
-        final int y = index / PROXIMITY_GRID_WIDTH;
-        final int x = index % PROXIMITY_GRID_WIDTH;
-        if (y > PROXIMITY_GRID_HEIGHT) {
-            // Safety check, should be entirely useless
-            throw new RuntimeException("Wrong y coordinate in spell checker proximity");
-        }
-        return (y << 16) + x;
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java
index 5f4c446..58c8f26 100644
--- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java
+++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java
@@ -74,14 +74,14 @@
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        final MenuItem actionItemAdd = menu.add(0, OPTIONS_MENU_ADD, 0,
+                R.string.user_dict_settings_add_menu_title).setIcon(R.drawable.ic_menu_add);
+        actionItemAdd.setShowAsAction(
+                MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
         final MenuItem actionItemDelete = menu.add(0, OPTIONS_MENU_DELETE, 0,
                 R.string.user_dict_settings_delete).setIcon(android.R.drawable.ic_menu_delete);
         actionItemDelete.setShowAsAction(
                 MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
-        final MenuItem actionItemAdd = menu.add(0, OPTIONS_MENU_ADD, 0,
-                R.string.user_dict_settings_delete).setIcon(R.drawable.ic_menu_add);
-        actionItemAdd.setShowAsAction(
-                MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java
index 36bc5ba..50dda96 100644
--- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java
+++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java
@@ -108,6 +108,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        getActivity().getActionBar().setTitle(R.string.edit_personal_dictionary);
     }
 
     @Override