diff options
Diffstat (limited to 'java/src')
16 files changed, 301 insertions, 592 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java index bc9e8cdd4..1fe23a330 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.TypedArray; 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 @@ public final class KeyboardLayoutSet { 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 @@ public final class KeyboardLayoutSet { return this; } - @UsedForTesting - public void disableTouchPositionCorrectionDataForTest() { + public void disableTouchPositionCorrectionData() { mParams.mDisableTouchPositionCorrectionDataForTest = true; } @@ -413,4 +415,47 @@ public final class KeyboardLayoutSet { } } } + + 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/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 0556fddd3..2d791648e 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -25,6 +25,7 @@ import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.keyboard.internal.GestureStroke; import com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokeParams; import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints; +import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints.GestureStrokePreviewParams; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.Constants; @@ -161,6 +162,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { // Parameters for pointer handling. private static PointerTrackerParams sParams; private static GestureStrokeParams sGestureStrokeParams; + private static GestureStrokePreviewParams sGesturePreviewParams; private static boolean sNeedsPhantomSuddenMoveEventHack; // Move this threshold to resource. // TODO: Device specific parameter would be better for device specific hack? @@ -339,12 +341,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element { sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack; sParams = PointerTrackerParams.DEFAULT; sGestureStrokeParams = GestureStrokeParams.DEFAULT; + sGesturePreviewParams = GestureStrokePreviewParams.DEFAULT; sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); } public static void setParameters(final TypedArray mainKeyboardViewAttr) { sParams = new PointerTrackerParams(mainKeyboardViewAttr); sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr); + sGesturePreviewParams = new GestureStrokePreviewParams(mainKeyboardViewAttr); sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); } @@ -428,7 +432,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } mPointerId = id; mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints( - id, sGestureStrokeParams); + id, sGestureStrokeParams, sGesturePreviewParams); setKeyDetectorInner(handler.getKeyDetector()); mListener = handler.getKeyboardActionListener(); mDrawingProxy = handler.getDrawingProxy(); diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index b77e378bf..57d3fede4 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -79,23 +79,6 @@ public class ProximityInfo { 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/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java index 7a51e2568..312fd2160 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java @@ -16,6 +16,9 @@ package com.android.inputmethod.keyboard.internal; +import android.content.res.TypedArray; + +import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.ResizableIntArray; public final class GestureStrokeWithPreviewPoints extends GestureStroke { @@ -25,6 +28,8 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { private final ResizableIntArray mPreviewXCoordinates = new ResizableIntArray(PREVIEW_CAPACITY); private final ResizableIntArray mPreviewYCoordinates = new ResizableIntArray(PREVIEW_CAPACITY); + private final GestureStrokePreviewParams mPreviewParams; + private int mStrokeId; private int mLastPreviewSize; private final HermiteInterpolator mInterpolator = new HermiteInterpolator(); @@ -32,23 +37,53 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { private int mLastX; private int mLastY; - private double mMinPreviewSamplingDistance; private double mDistanceFromLastSample; - private double mInterpolationDistanceThreshold; - - // TODO: Move these constants to resource. - // TODO: Use "dp" instead of ratio to the keyWidth because table has rather large keys. - // The minimum trail distance between sample points for preview in keyWidth unit when using - // interpolation. - private static final float MIN_PREVIEW_SAMPLING_RATIO_TO_KEY_WIDTH = 0.2f; - // The angular threshold to use interpolation in radian. PI/12 is 15 degree. - private static final double INTERPOLATION_ANGULAR_THRESHOLD = Math.PI / 12.0d; - // The distance threshold to use interpolation in keyWidth unit. - private static final float INTERPOLATION_DISTANCE_THRESHOLD_TO_KEY_WIDTH = 0.5f; - private static final int MAX_INTERPOLATION_PARTITIONS = 6; - - public GestureStrokeWithPreviewPoints(final int pointerId, final GestureStrokeParams params) { - super(pointerId, params); + + public static final class GestureStrokePreviewParams { + public final double mMinSamplingDistance; // in pixel + public final double mMaxInterpolationAngularThreshold; // in radian + public final double mMaxInterpolationDistanceThreshold; // in pixel + public final int mMaxInterpolationSegments; + + public static final GestureStrokePreviewParams DEFAULT = new GestureStrokePreviewParams(); + + private static final int DEFAULT_MAX_INTERPOLATION_ANGULAR_THRESHOLD = 15; // in degree + + private GestureStrokePreviewParams() { + mMinSamplingDistance = 0.0d; + mMaxInterpolationAngularThreshold = + degreeToRadian(DEFAULT_MAX_INTERPOLATION_ANGULAR_THRESHOLD); + mMaxInterpolationDistanceThreshold = mMinSamplingDistance; + mMaxInterpolationSegments = 4; + } + + private static double degreeToRadian(final int degree) { + return (double)degree / 180.0d * Math.PI; + } + + public GestureStrokePreviewParams(final TypedArray mainKeyboardViewAttr) { + mMinSamplingDistance = mainKeyboardViewAttr.getDimension( + R.styleable.MainKeyboardView_gesturePreviewTrailMinSamplingDistance, + (float)DEFAULT.mMinSamplingDistance); + final int interpolationAngularDegree = mainKeyboardViewAttr.getInteger(R.styleable + .MainKeyboardView_gesturePreviewTrailMaxInterpolationAngularThreshold, 0); + mMaxInterpolationAngularThreshold = (interpolationAngularDegree <= 0) + ? DEFAULT.mMaxInterpolationAngularThreshold + : degreeToRadian(interpolationAngularDegree); + mMaxInterpolationDistanceThreshold = mainKeyboardViewAttr.getDimension(R.styleable + .MainKeyboardView_gesturePreviewTrailMaxInterpolationDistanceThreshold, + (float)DEFAULT.mMaxInterpolationDistanceThreshold); + mMaxInterpolationSegments = mainKeyboardViewAttr.getInteger( + R.styleable.MainKeyboardView_gesturePreviewTrailMaxInterpolationSegments, + DEFAULT.mMaxInterpolationSegments); + } + } + + public GestureStrokeWithPreviewPoints(final int pointerId, + final GestureStrokeParams strokeParams, + final GestureStrokePreviewParams previewParams) { + super(pointerId, strokeParams); + mPreviewParams = previewParams; } @Override @@ -66,19 +101,12 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { return mStrokeId; } - @Override - public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { - super.setKeyboardGeometry(keyWidth, keyboardHeight); - mMinPreviewSamplingDistance = keyWidth * MIN_PREVIEW_SAMPLING_RATIO_TO_KEY_WIDTH; - mInterpolationDistanceThreshold = keyWidth * INTERPOLATION_DISTANCE_THRESHOLD_TO_KEY_WIDTH; - } - private boolean needsSampling(final int x, final int y) { mDistanceFromLastSample += Math.hypot(x - mLastX, y - mLastY); mLastX = x; mLastY = y; final boolean isDownEvent = (mPreviewEventTimes.getLength() == 0); - if (mDistanceFromLastSample >= mMinPreviewSamplingDistance || isDownEvent) { + if (mDistanceFromLastSample >= mPreviewParams.mMinSamplingDistance || isDownEvent) { mDistanceFromLastSample = 0.0d; return true; } @@ -144,19 +172,19 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { final double m1 = Math.atan2(mInterpolator.mSlope1Y, mInterpolator.mSlope1X); final double m2 = Math.atan2(mInterpolator.mSlope2Y, mInterpolator.mSlope2X); final double deltaAngle = Math.abs(angularDiff(m2, m1)); - final int partitionsByAngle = (int)Math.ceil( - deltaAngle / INTERPOLATION_ANGULAR_THRESHOLD); + final int segmentsByAngle = (int)Math.ceil( + deltaAngle / mPreviewParams.mMaxInterpolationAngularThreshold); final double deltaDistance = Math.hypot(mInterpolator.mP1X - mInterpolator.mP2X, mInterpolator.mP1Y - mInterpolator.mP2Y); - final int partitionsByDistance = (int)Math.ceil(deltaDistance - / mInterpolationDistanceThreshold); - final int partitions = Math.min(MAX_INTERPOLATION_PARTITIONS, - Math.max(partitionsByAngle, partitionsByDistance)); + final int segmentsByDistance = (int)Math.ceil(deltaDistance + / mPreviewParams.mMaxInterpolationDistanceThreshold); + final int segments = Math.min(mPreviewParams.mMaxInterpolationSegments, + Math.max(segmentsByAngle, segmentsByDistance)); final int t1 = eventTimes.get(d1); final int dt = pt[p2] - pt[p1]; d1++; - for (int i = 1; i < partitions; i++) { - final float t = i / (float)partitions; + for (int i = 1; i < segments; i++) { + final float t = i / (float)segments; mInterpolator.interpolate(t); eventTimes.add(d1, (int)(dt * t) + t1); xCoords.add(d1, (int)mInterpolator.mInterpolatedX); diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 75c2cf2c8..b9db9a092 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -16,21 +16,26 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.latin.personalization.AccountUtils; + import android.content.ContentResolver; 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; +import java.util.List; import java.util.Locale; 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 +107,32 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { @Override public void loadDictionaryAsync() { + clearFusionDictionary(); + loadDeviceAccountsEmailAddresses(); + loadDictionaryAsyncForUri(ContactsContract.Profile.CONTENT_URI); + // TODO: Switch this URL to the newer ContactsContract too + loadDictionaryAsyncForUri(Contacts.CONTENT_URI); + } + + private void loadDeviceAccountsEmailAddresses() { + final List<String> accountVocabulary = + AccountUtils.getDeviceAccountsEmailAddresses(mContext); + if (accountVocabulary == null || accountVocabulary.isEmpty()) { + return; + } + for (String word : accountVocabulary) { + if (DEBUG) { + Log.d(TAG, "loadAccountVocabulary: " + word); + } + super.addWord(word, null /* shortcut */, FREQUENCY_FOR_CONTACTS, + false /* isNotAWord */); + } + } + + 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 +157,6 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { } 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 +200,9 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { // 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 51bd901fb..e078f03f4 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 @@ public final class WordComposer { } /** - * 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/personalization/AccountUtils.java b/java/src/com/android/inputmethod/latin/personalization/AccountUtils.java new file mode 100644 index 000000000..93687e193 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/personalization/AccountUtils.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 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. + */ + +package com.android.inputmethod.latin.personalization; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; +import android.util.Patterns; + +import java.util.ArrayList; +import java.util.List; + +public class AccountUtils { + private AccountUtils() { + // This utility class is not publicly instantiable. + } + + private static Account[] getAccounts(final Context context) { + return AccountManager.get(context).getAccounts(); + } + + public static List<String> getDeviceAccountsEmailAddresses(final Context context) { + final ArrayList<String> retval = new ArrayList<String>(); + for (final Account account : getAccounts(context)) { + final String name = account.name; + if (Patterns.EMAIL_ADDRESS.matcher(name).matches()) { + retval.add(name); + retval.add(name.split("@")[0]); + } + } + return retval; + } +} diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java index affe3a348..acb0766f2 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 @@ public final class SetupActivity extends Activity implements View.OnClickListene .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 @@ public final class SetupActivity extends Activity implements View.OnClickListene 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 @@ public final class SetupActivity extends Activity implements View.OnClickListene 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 aa60496ae..13fcaf48a 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.service.textservice.SpellCheckerService; 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 @@ public final class AndroidSpellCheckerService extends SpellCheckerService 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 @@ public final class AndroidSpellCheckerService extends SpellCheckerService 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 @@ public final class AndroidSpellCheckerService extends SpellCheckerService 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 61850e42e..16e9fb77e 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 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { } if (shouldFilterOut(inText, mScript)) { - DictAndProximity dictInfo = null; + DictAndKeyboard dictInfo = null; try { dictInfo = mDictionaryPool.pollWithDefaultTimeout(); if (!DictionaryPool.isAValidDictionary(dictInfo)) { @@ -286,7 +286,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { 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 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { 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 000000000..b77f3e2c5 --- /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 017a4f555..000000000 --- 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 27964b3c6..a20e09ee8 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 @@ import java.util.concurrent.TimeUnit; * 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 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> 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 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> } }, null); - static public boolean isAValidDictionary(final DictAndProximity dictInfo) { + static public boolean isAValidDictionary(final DictAndKeyboard dictInfo) { return null != dictInfo && dummyDict != dictInfo; } @@ -79,32 +79,32 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> } @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 final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> public void close() { synchronized(this) { mClosed = true; - for (DictAndProximity dict : this) { + for (DictAndKeyboard dict : this) { dict.mDictionary.close(); } clear(); @@ -123,7 +123,7 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> } @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 0c480eaba..000000000 --- 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 5f4c44636..58c8f266c 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 @@ public class UserDictionaryAddWordFragment extends Fragment @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 36bc5ba49..50dda9663 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 @@ public class UserDictionarySettings extends ListFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + getActivity().getActionBar().setTitle(R.string.edit_personal_dictionary); } @Override |