diff options
Diffstat (limited to 'java/src')
27 files changed, 213 insertions, 711 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index ea3f6236a..13e909c7e 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -16,17 +16,9 @@ package com.android.inputmethod.keyboard; -import android.util.Log; - -import java.util.Arrays; -import java.util.List; public class KeyDetector { - private static final String TAG = KeyDetector.class.getSimpleName(); - private static final boolean DEBUG = false; - public static final int NOT_A_CODE = -1; - private static final int ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE = 2; private final int mKeyHysteresisDistanceSquared; @@ -34,12 +26,6 @@ public class KeyDetector { private int mCorrectionX; private int mCorrectionY; private boolean mProximityCorrectOn; - private int mProximityThresholdSquare; - - // working area - private static final int MAX_NEARBY_KEYS = 12; - private final int[] mDistances = new int[MAX_NEARBY_KEYS]; - private final Key[] mNeighborKeys = new Key[MAX_NEARBY_KEYS]; /** * This class handles key detection. @@ -57,8 +43,6 @@ public class KeyDetector { mCorrectionX = (int)correctionX; mCorrectionY = (int)correctionY; mKeyboard = keyboard; - final int threshold = keyboard.mMostCommonKeyWidth; - mProximityThresholdSquare = threshold * threshold; } public int getKeyHysteresisDistanceSquared() { @@ -87,169 +71,11 @@ public class KeyDetector { return mProximityCorrectOn; } - public void setProximityThreshold(int threshold) { - mProximityThresholdSquare = threshold * threshold; - } - public boolean alwaysAllowsSlidingInput() { return false; } /** - * Computes maximum size of the array that can contain all nearby key codes returned by - * {@link #getNearbyCodes}. - * - * @return Returns maximum size of the array that can contain all nearby key codes returned - * by {@link #getNearbyCodes}. - */ - protected int getMaxNearbyKeys() { - return MAX_NEARBY_KEYS; - } - - /** - * Allocates array that can hold all key codes returned by {@link #getNearbyCodes} - * method. The maximum size of the array should be computed by {@link #getMaxNearbyKeys}. - * - * @return Allocates and returns an array that can hold all key codes returned by - * {@link #getNearbyCodes} method. All elements in the returned array are - * initialized by {@link #NOT_A_CODE} value. - */ - public int[] newCodeArray() { - int[] codes = new int[getMaxNearbyKeys()]; - Arrays.fill(codes, NOT_A_CODE); - return codes; - } - - private void initializeNearbyKeys() { - Arrays.fill(mDistances, Integer.MAX_VALUE); - Arrays.fill(mNeighborKeys, null); - } - - /** - * Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance. - * If the distance of two keys are the same, the key which the point is on should be considered - * as a closer one. - * - * @param key the key to be inserted into the nearby keys buffer. - * @param distance distance between the key's edge and user touched point. - * @param isOnKey true if the point is on the key. - * @return order of the key in the nearby buffer, 0 if it is the nearest key. - */ - private int sortNearbyKeys(Key key, int distance, boolean isOnKey) { - final int[] distances = mDistances; - final Key[] neighborKeys = mNeighborKeys; - for (int insertPos = 0; insertPos < distances.length; insertPos++) { - final int comparingDistance = distances[insertPos]; - if (distance < comparingDistance || (distance == comparingDistance && isOnKey)) { - final int nextPos = insertPos + 1; - if (nextPos < distances.length) { - System.arraycopy(distances, insertPos, distances, nextPos, - distances.length - nextPos); - System.arraycopy(neighborKeys, insertPos, neighborKeys, nextPos, - neighborKeys.length - nextPos); - } - distances[insertPos] = distance; - neighborKeys[insertPos] = key; - return insertPos; - } - } - return distances.length; - } - - private void getNearbyKeyCodes(final int primaryCode, final int[] allCodes) { - final Key[] neighborKeys = mNeighborKeys; - final int maxCodesSize = allCodes.length; - - // allCodes[0] should always have the key code even if it is a non-letter key. - if (neighborKeys[0] == null) { - allCodes[0] = NOT_A_CODE; - return; - } - - int numCodes = 0; - for (int j = 0; j < neighborKeys.length && numCodes < maxCodesSize; j++) { - final Key key = neighborKeys[j]; - if (key == null) - break; - final int code = key.mCode; - // filter out a non-letter key from nearby keys - if (code < Keyboard.CODE_SPACE) - continue; - allCodes[numCodes++] = code; - } - if (maxCodesSize <= numCodes) { - return; - } - - final int code = (primaryCode == NOT_A_CODE) ? allCodes[0] : primaryCode; - if (code == NOT_A_CODE) { - return; - } - final List<Integer> additionalChars = mKeyboard.getAdditionalProximityChars().get(code); - if (additionalChars == null || additionalChars.size() == 0) { - return; - } - int currentCodesSize = numCodes; - allCodes[numCodes++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE; - if (maxCodesSize <= numCodes) { - return; - } - // TODO: This is O(N^2). Assuming additionalChars.size() is up to 4 or 5. - for (int i = 0; i < additionalChars.size(); ++i) { - final int additionalChar = additionalChars.get(i); - boolean contains = false; - for (int j = 0; j < currentCodesSize; ++j) { - if (additionalChar == allCodes[j]) { - contains = true; - break; - } - } - if (!contains) { - allCodes[numCodes++] = additionalChar; - if (maxCodesSize <= numCodes) { - return; - } - } - } - } - - /** - * Finds all possible nearby key codes around a touch event point and returns the nearest key. - * The algorithm to determine the nearby keys depends on the threshold set by - * {@link #setProximityThreshold(int)} and the mode set by - * {@link #setProximityCorrectionEnabled(boolean)}. - * - * @param x The x-coordinate of a touch point - * @param y The y-coordinate of a touch point - * @param allCodes All nearby key codes except functional key are returned in this array - */ - // TODO: Move this method to native code. - public void getNearbyCodes(int x, int y, final int[] allCodes) { - final int touchX = getTouchX(x); - final int touchY = getTouchY(y); - - initializeNearbyKeys(); - Key primaryKey = null; - for (final Key key : mKeyboard.getNearestKeys(touchX, touchY)) { - final boolean isOnKey = key.isOnKey(touchX, touchY); - final int distance = key.squaredDistanceToEdge(touchX, touchY); - if (isOnKey || (mProximityCorrectOn && distance < mProximityThresholdSquare)) { - final int insertedPosition = sortNearbyKeys(key, distance, isOnKey); - if (insertedPosition == 0 && isOnKey) { - primaryKey = key; - } - } - } - - getNearbyKeyCodes(primaryKey != null ? primaryKey.mCode : NOT_A_CODE, allCodes); - if (DEBUG) { - Log.d(TAG, "x=" + x + " y=" + y - + " primary=" + printableCode(primaryKey) - + " codes=" + printableCodes(allCodes)); - } - } - - /** * Detect the key whose hitbox the touch point is in. * * @param x The x-coordinate of a touch point @@ -260,12 +86,19 @@ public class KeyDetector { final int touchX = getTouchX(x); final int touchY = getTouchY(y); - for (final Key key : mKeyboard.getNearestKeys(touchX, touchY)) { - if (key.isOnKey(touchX, touchY)) { - return key; + int minDistance = Integer.MAX_VALUE; + Key primaryKey = null; + for (final Key key: mKeyboard.getNearestKeys(touchX, touchY)) { + final boolean isOnKey = key.isOnKey(touchX, touchY); + final int distance = key.squaredDistanceToEdge(touchX, touchY); + // To take care of hitbox overlaps, we compare mCode here too. + if (primaryKey == null || distance < minDistance + || (distance == minDistance && isOnKey && key.mCode > primaryKey.mCode)) { + minDistance = distance; + primaryKey = key; } } - return null; + return primaryKey; } public static String printableCode(Key key) { @@ -277,14 +110,9 @@ public class KeyDetector { boolean addDelimiter = false; for (final int code : codes) { if (code == NOT_A_CODE) break; - if (code == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { - sb.append(" | "); - addDelimiter = false; - } else { - if (addDelimiter) sb.append(", "); - sb.append(Keyboard.printableCode(code)); - addDelimiter = true; - } + if (addDelimiter) sb.append(", "); + sb.append(Keyboard.printableCode(code)); + addDelimiter = true; } return "[" + sb + "]"; } diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 973f64b4d..2b1cc43cd 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; -import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -42,8 +41,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; -import java.util.List; -import java.util.Map; /** * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard @@ -133,8 +130,6 @@ public class Keyboard { private final ProximityInfo mProximityInfo; - private final Map<Integer, List<Integer>> mAdditionalProximityChars; - public Keyboard(Params params) { mId = params.mId; mThemeId = params.mThemeId; @@ -153,12 +148,10 @@ public class Keyboard { mAltCodeKeysWhileTyping = params.mAltCodeKeysWhileTyping.toArray( new Key[params.mAltCodeKeysWhileTyping.size()]); mIconsSet = params.mIconsSet; - mAdditionalProximityChars = params.mAdditionalProximityChars; mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(), params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, - mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection, - params.mAdditionalProximityChars); + mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection); } public ProximityInfo getProximityInfo() { @@ -230,9 +223,6 @@ public class Keyboard { public final ArrayList<Key> mShiftKeys = new ArrayList<Key>(); public final ArrayList<Key> mAltCodeKeysWhileTyping = new ArrayList<Key>(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); - // TODO: Should be in Key instead of Keyboard.Params? - public final Map<Integer, List<Integer>> mAdditionalProximityChars = - new HashMap<Integer, List<Integer>>(); public KeyboardSet.KeysCache mKeysCache; @@ -368,10 +358,6 @@ public class Keyboard { return mProximityInfo.getNearestKeys(adjustedX, adjustedY); } - public Map<Integer, List<Integer>> getAdditionalProximityChars() { - return mAdditionalProximityChars; - } - public static String printableCode(int code) { switch (code) { case CODE_SHIFT: return "shift"; @@ -630,7 +616,6 @@ public class Keyboard { mParams = params; setTouchPositionCorrectionData(context, params); - setAdditionalProximityChars(context, params); params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); @@ -653,25 +638,6 @@ public class Keyboard { params.mTouchPositionCorrection.load(data); } - private static void setAdditionalProximityChars(Context context, Params params) { - final String[] additionalChars = - context.getResources().getStringArray(R.array.additional_proximitychars); - int currentPrimaryIndex = 0; - for (int i = 0; i < additionalChars.length; ++i) { - final String additionalChar = additionalChars[i]; - if (TextUtils.isEmpty(additionalChar)) { - currentPrimaryIndex = 0; - } else if (currentPrimaryIndex == 0) { - currentPrimaryIndex = additionalChar.charAt(0); - params.mAdditionalProximityChars.put( - currentPrimaryIndex, new ArrayList<Integer>()); - } else if (currentPrimaryIndex != 0) { - final int c = additionalChar.charAt(0); - params.mAdditionalProximityChars.get(currentPrimaryIndex).add(c); - } - } - } - public void setAutoGenerate(KeyboardSet.KeysCache keysCache) { mParams.mKeysCache = keysCache; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java index 680ff0d25..52096c843 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java @@ -42,7 +42,6 @@ import java.io.IOException; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Locale; -import java.util.Map; /** * This class represents a set of keyboards. Each of them represents a different keyboard @@ -75,7 +74,7 @@ public class KeyboardSet { } public static class KeysCache { - private final Map<Key, Key> mMap; + private final HashMap<Key, Key> mMap; public KeysCache() { mMap = new HashMap<Key, Key>(); @@ -108,7 +107,7 @@ public class KeyboardSet { int mOrientation; int mWidth; // KeyboardSet element id to keyboard layout XML id map. - final Map<Integer, Integer> mKeyboardSetElementIdToXmlIdMap = + final HashMap<Integer, Integer> mKeyboardSetElementIdToXmlIdMap = new HashMap<Integer, Integer>(); Params() {} } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 343842552..b869059e4 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -480,7 +480,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke super.setKeyboard(keyboard); mKeyDetector.setKeyboard( keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); - mKeyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); PointerTracker.setKeyDetector(mKeyDetector); mTouchScreenRegulator.setKeyboard(keyboard); mMoreKeysPanelCache.clear(); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java index 6c8d02016..cd4e3001e 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java @@ -33,34 +33,6 @@ public class MoreKeysDetector extends KeyDetector { } @Override - protected int getMaxNearbyKeys() { - // No nearby key will be returned. - return 1; - } - - @Override - public void getNearbyCodes(int x, int y, final int[] allCodes) { - final int touchX = getTouchX(x); - final int touchY = getTouchY(y); - - Key nearestKey = null; - int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; - for (final Key key : getKeyboard().mKeys) { - final int dist = key.squaredDistanceToEdge(touchX, touchY); - if (dist < nearestDist) { - nearestKey = key; - nearestDist = dist; - } - } - - if (nearestKey != null) { - allCodes[0] = nearestKey.mCode; - } else { - allCodes[0] = NOT_A_CODE; - } - } - - @Override public Key detectHitKey(int x, int y) { final int touchX = getTouchX(x); final int touchY = getTouchY(y); diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index 61d75e278..442413c0c 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -24,10 +24,7 @@ import com.android.inputmethod.latin.JniUtils; import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.List; -import java.util.Map; public class ProximityInfo { public static final int MAX_PROXIMITY_CHARS_SIZE = 16; @@ -50,8 +47,7 @@ public class ProximityInfo { ProximityInfo(String localeStr, int gridWidth, int gridHeight, int minWidth, int height, int mostCommonKeyWidth, int mostCommonKeyHeight, final Key[] keys, - TouchPositionCorrection touchPositionCorrection, - Map<Integer, List<Integer>> additionalProximityChars) { + TouchPositionCorrection touchPositionCorrection) { if (TextUtils.isEmpty(localeStr)) { mLocaleStr = ""; } else { @@ -72,12 +68,11 @@ public class ProximityInfo { return; } computeNearestNeighbors( - mostCommonKeyWidth, keys, touchPositionCorrection, additionalProximityChars); + mostCommonKeyWidth, keys, touchPositionCorrection); } public static ProximityInfo createDummyProximityInfo() { - return new ProximityInfo("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null, - Collections.<Integer, List<Integer>> emptyMap()); + return new ProximityInfo("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null); } public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) { @@ -184,8 +179,7 @@ public class ProximityInfo { } private void computeNearestNeighbors(int defaultWidth, final Key[] keys, - TouchPositionCorrection touchPositionCorrection, - Map<Integer, List<Integer>> additionalProximityChars) { + TouchPositionCorrection touchPositionCorrection) { final HashMap<Integer, Key> keyCodeMap = new HashMap<Integer, Key>(); for (final Key key : keys) { keyCodeMap.put(key.mCode, key); @@ -207,27 +201,6 @@ public class ProximityInfo { neighborKeys[count++] = key; } } - int currentCodesSize = count; - for (int i = 0; i < currentCodesSize; ++i) { - final int c = neighborKeys[i].mCode; - final List<Integer> additionalChars = additionalProximityChars.get(c); - if (additionalChars == null || additionalChars.size() == 0) { - continue; - } - for (int j = 0; j < additionalChars.size(); ++j) { - final int additionalChar = additionalChars.get(j); - boolean contains = false; - for (int k = 0; k < count; ++k) { - if(additionalChar == neighborKeys[k].mCode) { - contains = true; - break; - } - } - if (!contains) { - neighborKeys[count++] = keyCodeMap.get(additionalChar); - } - } - } mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] = Arrays.copyOfRange(neighborKeys, 0, count); } diff --git a/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java b/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java index 62a9259f9..347383f95 100644 --- a/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java +++ b/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java @@ -17,12 +17,12 @@ package com.android.inputmethod.keyboard; import android.content.Context; -import android.os.Build; import android.util.Log; import android.view.MotionEvent; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.Utils; public class SuddenJumpingTouchEventHandler { private static final String TAG = SuddenJumpingTouchEventHandler.class.getSimpleName(); @@ -49,18 +49,8 @@ public class SuddenJumpingTouchEventHandler { public SuddenJumpingTouchEventHandler(Context context, ProcessMotionEvent view) { mView = view; - final String[] deviceList = context.getResources().getStringArray( - R.array.sudden_jumping_touch_event_device_list); - mNeedsSuddenJumpingHack = needsSuddenJumpingHack(Build.HARDWARE, deviceList); - } - - private static boolean needsSuddenJumpingHack(String deviceName, String[] deviceList) { - for (String device : deviceList) { - if (device.equalsIgnoreCase(deviceName)) { - return true; - } - } - return false; + mNeedsSuddenJumpingHack = Boolean.parseBoolean(Utils.getDeviceOverrideValue( + context.getResources(), R.array.sudden_jumping_touch_event_device_list, "false")); } public void setKeyboard(Keyboard newKeyboard) { diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index 9c35f8f6f..ef88f9906 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -20,7 +20,7 @@ import android.text.TextUtils; import android.util.Log; import java.util.ArrayList; -import java.util.Map; +import java.util.HashMap; public class AutoCorrection { private static final boolean DBG = LatinImeLogger.sDBG; @@ -30,7 +30,7 @@ public class AutoCorrection { // Purely static class: can't instantiate. } - public static CharSequence computeAutoCorrectionWord(Map<String, Dictionary> dictionaries, + public static CharSequence computeAutoCorrectionWord(HashMap<String, Dictionary> dictionaries, WordComposer wordComposer, ArrayList<CharSequence> suggestions, int[] sortedScores, CharSequence consideredWord, double autoCorrectionThreshold, CharSequence whitelistedWord) { @@ -47,7 +47,7 @@ public class AutoCorrection { } public static boolean isValidWord( - Map<String, Dictionary> dictionaries, CharSequence word, boolean ignoreCase) { + HashMap<String, Dictionary> dictionaries, CharSequence word, boolean ignoreCase) { if (TextUtils.isEmpty(word)) { return false; } @@ -72,7 +72,7 @@ public class AutoCorrection { } public static boolean allowsToBeAutoCorrected( - Map<String, Dictionary> dictionaries, CharSequence word, boolean ignoreCase) { + HashMap<String, Dictionary> dictionaries, CharSequence word, boolean ignoreCase) { final WhitelistDictionary whitelistDictionary = (WhitelistDictionary)dictionaries.get(Suggest.DICT_KEY_WHITELIST); // If "word" is in the whitelist dictionary, it should not be auto corrected. @@ -87,9 +87,9 @@ public class AutoCorrection { return whiteListedWord != null; } - private static boolean hasAutoCorrectionForConsideredWord(Map<String, Dictionary> dictionaries, - WordComposer wordComposer, ArrayList<CharSequence> suggestions, - CharSequence consideredWord) { + private static boolean hasAutoCorrectionForConsideredWord( + HashMap<String, Dictionary> dictionaries, WordComposer wordComposer, + ArrayList<CharSequence> suggestions, CharSequence consideredWord) { if (TextUtils.isEmpty(consideredWord)) return false; return wordComposer.size() > 1 && suggestions.size() > 0 && !allowsToBeAutoCorrected(dictionaries, consideredWord, false); diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 31ff4e7b4..dfc8c8e9d 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -149,6 +149,9 @@ public class BinaryDictionary extends Dictionary { int count = getBigramsNative(mNativeDict, chars, chars.length, mInputCodes, codesSize, mOutputChars_bigrams, mBigramScores, MAX_WORD_LENGTH, MAX_BIGRAMS, MAX_PROXIMITY_CHARS_SIZE); + if (count > MAX_BIGRAMS) { + count = MAX_BIGRAMS; + } for (int j = 0; j < count; ++j) { if (codesSize > 0 && mBigramScores[j] < 1) break; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java index 9ffc7d0a2..8ec440500 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java @@ -196,8 +196,8 @@ public class BinaryDictionaryFileDumper { } finally { // Ignore exceptions while closing files. try { - // afd.close() will close inputStream, we should not call inputStream.close(). - if (null != afd) afd.close(); + // inputStream.close() will close afd, we should not call afd.close(). + if (null != inputStream) inputStream.close(); } catch (Exception e) { Log.e(TAG, "Exception while closing a cross-process file descriptor : " + e); } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 79441c557..1c24cd11d 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -25,7 +25,6 @@ import android.util.Log; import java.io.File; import java.util.ArrayList; -import java.util.List; import java.util.Locale; /** @@ -264,9 +263,9 @@ class BinaryDictionaryGetter { * - Gets a file name from the fallback resource passed as an argument. * If that fails: * - Returns null. - * @return The address of a valid file, or null. + * @return The list of addresses of valid dictionary files, or null. */ - public static List<AssetFileAddress> getDictionaryFiles(final Locale locale, + public static ArrayList<AssetFileAddress> getDictionaryFiles(final Locale locale, final Context context, final int fallbackResId) { // cacheWordListsFromContentProvider returns the list of files it copied to local diff --git a/java/src/com/android/inputmethod/latin/DebugSettings.java b/java/src/com/android/inputmethod/latin/DebugSettings.java index 870b33f9a..23d63b42a 100644 --- a/java/src/com/android/inputmethod/latin/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/DebugSettings.java @@ -30,7 +30,7 @@ import com.android.inputmethod.keyboard.KeyboardSwitcher; public class DebugSettings extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener { - private static final String TAG = "DebugSettings"; + private static final String TAG = DebugSettings.class.getSimpleName(); private static final String DEBUG_MODE_KEY = "debug_mode"; public static final String FORCE_NON_DISTINCT_MULTITOUCH_KEY = "force_non_distinct_multitouch"; diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index c19a5a718..5de770a4a 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -22,7 +22,6 @@ import android.util.Log; import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -30,7 +29,7 @@ import java.util.concurrent.CopyOnWriteArrayList; */ public class DictionaryCollection extends Dictionary { private final String TAG = DictionaryCollection.class.getSimpleName(); - protected final List<Dictionary> mDictionaries; + protected final CopyOnWriteArrayList<Dictionary> mDictionaries; public DictionaryCollection() { mDictionaries = new CopyOnWriteArrayList<Dictionary>(); diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index 7a81f7bd5..77c685c50 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -22,8 +22,8 @@ import android.content.res.Resources; import android.util.Log; import java.io.File; +import java.util.ArrayList; import java.util.LinkedList; -import java.util.List; import java.util.Locale; /** @@ -52,8 +52,8 @@ public class DictionaryFactory { return new DictionaryCollection(createBinaryDictionary(context, fallbackResId, locale)); } - final List<Dictionary> dictList = new LinkedList<Dictionary>(); - final List<AssetFileAddress> assetFileList = + final LinkedList<Dictionary> dictList = new LinkedList<Dictionary>(); + final ArrayList<AssetFileAddress> assetFileList = BinaryDictionaryGetter.getDictionaryFiles(locale, context, fallbackResId); if (null != assetFileList) { for (final AssetFileAddress f : assetFileList) { diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java index f7afed2a5..06c70c42c 100644 --- a/java/src/com/android/inputmethod/latin/InputAttributes.java +++ b/java/src/com/android/inputmethod/latin/InputAttributes.java @@ -95,6 +95,7 @@ public class InputAttributes { } } + @SuppressWarnings("unused") private void dumpFlags(final int inputType) { Log.i(TAG, "Input class:"); final int inputClass = inputType & InputType.TYPE_MASK_CLASS; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 7c08377be..e67f0ea05 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -73,7 +73,6 @@ import com.android.inputmethod.latin.suggestions.SuggestionsView; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.List; import java.util.Locale; /** @@ -203,8 +202,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private boolean mShouldSwitchToLastSubtype = true; private UserDictionary mUserDictionary; - private UserBigramDictionary mUserBigramDictionary; - private UserUnigramDictionary mUserUnigramDictionary; + private UserHistoryDictionary mUserHistoryDictionary; private boolean mIsUserDictionaryAvailable; private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; @@ -528,13 +526,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar resetContactsDictionary(oldContactsDictionary); - mUserUnigramDictionary - = new UserUnigramDictionary(this, this, localeStr, Suggest.DIC_USER_UNIGRAM); - mSuggest.setUserUnigramDictionary(mUserUnigramDictionary); - - mUserBigramDictionary - = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER_BIGRAM); - mSuggest.setUserBigramDictionary(mUserBigramDictionary); + mUserHistoryDictionary + = new UserHistoryDictionary(this, this, localeStr, Suggest.DIC_USER_HISTORY); + mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); LocaleUtils.setSystemLocale(res, savedLocale); } @@ -776,8 +770,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) inputView.closing(); - if (mUserUnigramDictionary != null) mUserUnigramDictionary.flushPendingWrites(); - if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites(); + if (mUserHistoryDictionary != null) mUserHistoryDictionary.flushPendingWrites(); } private void onFinishInputViewInternal(boolean finishingInput) { @@ -923,7 +916,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return; } - final List<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = + final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = SuggestedWords.getFromApplicationSpecifiedCompletions( applicationSpecifiedCompletions); final SuggestedWords suggestedWords = new SuggestedWords( @@ -1295,7 +1288,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mDeleteCount++; mExpectingUpdateSelection = true; mShouldSwitchToLastSubtype = true; - LatinImeLogger.logOnDelete(); + LatinImeLogger.logOnDelete(x, y); break; case Keyboard.CODE_SHIFT: case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: @@ -1995,9 +1988,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar setSuggestionStripShown(isSuggestionsStripVisible()); } - /** - * Adds to the UserBigramDictionary and/or UserUnigramDictionary - */ private void addToUserHistoryDictionary(final CharSequence suggestion) { if (suggestion == null || suggestion.length() < 1) return; @@ -2009,19 +1999,16 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return; } - if (null != mUserUnigramDictionary) { - mUserUnigramDictionary.addUnigram(suggestion.toString()); - } - - if (mUserBigramDictionary != null) { + if (mUserHistoryDictionary != null) { final InputConnection ic = getCurrentInputConnection(); + final CharSequence prevWord; if (null != ic) { - final CharSequence prevWord = - EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators); - if (null != prevWord) { - mUserBigramDictionary.addBigramPair(prevWord.toString(), suggestion.toString()); - } + prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators); + } else { + prevWord = null; } + mUserHistoryDictionary.addToUserHistory(null == prevWord ? null : prevWord.toString(), + suggestion.toString()); } } diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index 5390ee39e..079f3b5dd 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -22,8 +22,6 @@ import android.view.inputmethod.EditorInfo; import com.android.inputmethod.keyboard.Keyboard; -import java.util.List; - public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener { public static boolean sDBG = false; @@ -53,7 +51,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public static void logOnAutoCorrectionCancelled() { } - public static void logOnDelete() { + public static void logOnDelete(int x, int y) { } public static void logOnInputChar() { diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 4346a3671..c1335fdfe 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -19,19 +19,15 @@ package com.android.inputmethod.latin; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; -import android.os.Build; import android.util.Log; import android.view.inputmethod.EditorInfo; -import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.keyboard.internal.KeySpecParser; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.List; import java.util.Locale; public class SettingsValues { @@ -325,14 +321,8 @@ public class SettingsValues { return volume; } - final String[] volumePerHardwareList = res.getStringArray(R.array.keypress_volumes); - final String hardwarePrefix = Build.HARDWARE + ","; - for (final String element : volumePerHardwareList) { - if (element.startsWith(hardwarePrefix)) { - return Float.parseFloat(element.substring(element.lastIndexOf(',') + 1)); - } - } - return -1.0f; + return Float.parseFloat( + Utils.getDeviceOverrideValue(res, R.array.keypress_volumes, "-1.0f")); } // Likewise @@ -343,15 +333,9 @@ public class SettingsValues { if (ms >= 0) { return ms; } - final String[] durationPerHardwareList = res.getStringArray( - R.array.keypress_vibration_durations); - final String hardwarePrefix = Build.HARDWARE + ","; - for (final String element : durationPerHardwareList) { - if (element.startsWith(hardwarePrefix)) { - return (int)Long.parseLong(element.substring(element.lastIndexOf(',') + 1)); - } - } - return -1; + + return Integer.parseInt( + Utils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations, "-1")); } // Likewise diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 69754d769..9ae2506f4 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -30,15 +30,12 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; -import java.util.Map; -import java.util.Set; /** * This class loads a dictionary and provides a list of suggestions for a given sequence of * characters. This includes corrections and completions. */ public class Suggest implements Dictionary.WordCallback { - public static final String TAG = Suggest.class.getSimpleName(); public static final int APPROX_MAX_WORD_LENGTH = 32; @@ -65,9 +62,8 @@ public class Suggest implements Dictionary.WordCallback { public static final int DIC_USER_TYPED = 0; public static final int DIC_MAIN = 1; public static final int DIC_USER = 2; - public static final int DIC_USER_UNIGRAM = 3; + public static final int DIC_USER_HISTORY = 3; public static final int DIC_CONTACTS = 4; - public static final int DIC_USER_BIGRAM = 5; public static final int DIC_WHITELIST = 6; // If you add a type of dictionary, increment DIC_TYPE_LAST_ID // TODO: this value seems unused. Remove it? @@ -76,10 +72,10 @@ public class Suggest implements Dictionary.WordCallback { public static final String DICT_KEY_CONTACTS = "contacts"; // User dictionary, the system-managed one. public static final String DICT_KEY_USER = "user"; - // User unigram dictionary, internal to LatinIME - public static final String DICT_KEY_USER_UNIGRAM = "user_unigram"; - // User bigram dictionary, internal to LatinIME - public static final String DICT_KEY_USER_BIGRAM = "user_bigram"; + // User history dictionary for the unigram map, internal to LatinIME + public static final String DICT_KEY_USER_HISTORY_UNIGRAM = "history_unigram"; + // User history dictionary for the bigram map, internal to LatinIME + public static final String DICT_KEY_USER_HISTORY_BIGRAM = "history_bigram"; public static final String DICT_KEY_WHITELIST ="whitelist"; private static final boolean DBG = LatinImeLogger.sDBG; @@ -87,8 +83,10 @@ public class Suggest implements Dictionary.WordCallback { private Dictionary mMainDict; private ContactsDictionary mContactsDict; private WhitelistDictionary mWhiteListDictionary; - private final Map<String, Dictionary> mUnigramDictionaries = new HashMap<String, Dictionary>(); - private final Map<String, Dictionary> mBigramDictionaries = new HashMap<String, Dictionary>(); + private final HashMap<String, Dictionary> mUnigramDictionaries = + new HashMap<String, Dictionary>(); + private final HashMap<String, Dictionary> mBigramDictionaries = + new HashMap<String, Dictionary>(); private int mPrefMaxSuggestions = 18; @@ -142,7 +140,7 @@ public class Suggest implements Dictionary.WordCallback { initWhitelistAndAutocorrectAndPool(context, locale); } - private static void addOrReplaceDictionary(Map<String, Dictionary> dictionaries, String key, + private static void addOrReplaceDictionary(HashMap<String, Dictionary> dictionaries, String key, Dictionary dict) { final Dictionary oldDict = (dict == null) ? dictionaries.remove(key) @@ -177,7 +175,7 @@ public class Suggest implements Dictionary.WordCallback { return mContactsDict; } - public Map<String, Dictionary> getUnigramDictionaries() { + public HashMap<String, Dictionary> getUnigramDictionaries() { return mUnigramDictionaries; } @@ -204,12 +202,11 @@ public class Suggest implements Dictionary.WordCallback { addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_CONTACTS, contactsDictionary); } - public void setUserUnigramDictionary(Dictionary userUnigramDictionary) { - addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_USER_UNIGRAM, userUnigramDictionary); - } - - public void setUserBigramDictionary(Dictionary userBigramDictionary) { - addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_USER_BIGRAM, userBigramDictionary); + public void setUserHistoryDictionary(Dictionary userHistoryDictionary) { + addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_USER_HISTORY_UNIGRAM, + userHistoryDictionary); + addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_USER_HISTORY_BIGRAM, + userHistoryDictionary); } public void setAutoCorrectionThreshold(double threshold) { @@ -348,7 +345,7 @@ public class Suggest implements Dictionary.WordCallback { // At second character typed, search the unigrams (scores being affected by bigrams) for (final String key : mUnigramDictionaries.keySet()) { // Skip UserUnigramDictionary and WhitelistDictionary to lookup - if (key.equals(DICT_KEY_USER_UNIGRAM) || key.equals(DICT_KEY_WHITELIST)) + if (key.equals(DICT_KEY_USER_HISTORY_UNIGRAM) || key.equals(DICT_KEY_WHITELIST)) continue; final Dictionary dictionary = mUnigramDictionaries.get(key); dictionary.getWords(wordComposerForLookup, this, proximityInfo); @@ -563,7 +560,7 @@ public class Suggest implements Dictionary.WordCallback { } public void close() { - final Set<Dictionary> dictionaries = new HashSet<Dictionary>(); + final HashSet<Dictionary> dictionaries = new HashSet<Dictionary>(); dictionaries.addAll(mUnigramDictionaries.values()); dictionaries.addAll(mBigramDictionaries.values()); for (final Dictionary dictionary : dictionaries) { diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index b63bc6c29..ef8e58e0c 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -21,22 +21,20 @@ import android.view.inputmethod.CompletionInfo; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; -import java.util.List; public class SuggestedWords { public static final SuggestedWords EMPTY = new SuggestedWords( - Collections.<SuggestedWordInfo>emptyList(), false, false, false, false, false); + new ArrayList<SuggestedWordInfo>(0), false, false, false, false, false); public final boolean mTypedWordValid; public final boolean mHasAutoCorrectionCandidate; public final boolean mIsPunctuationSuggestions; public final boolean mAllowsToBeAutoCorrected; public final boolean mIsObsoleteSuggestions; - private final List<SuggestedWordInfo> mSuggestedWordInfoList; + private final ArrayList<SuggestedWordInfo> mSuggestedWordInfoList; - public SuggestedWords(final List<SuggestedWordInfo> suggestedWordInfoList, + public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList, final boolean typedWordValid, final boolean hasAutoCorrectionCandidate, final boolean allowsToBeAutoCorrected, @@ -82,7 +80,7 @@ public class SuggestedWords { } public static ArrayList<SuggestedWordInfo> getFromCharSequenceList( - final List<CharSequence> wordList) { + final ArrayList<CharSequence> wordList) { final ArrayList<SuggestedWordInfo> result = new ArrayList<SuggestedWordInfo>(); for (CharSequence word : wordList) { if (null != word) result.add(new SuggestedWordInfo(word)); @@ -90,7 +88,7 @@ public class SuggestedWords { return result; } - public static List<SuggestedWordInfo> getFromApplicationSpecifiedCompletions( + public static ArrayList<SuggestedWordInfo> getFromApplicationSpecifiedCompletions( final CompletionInfo[] infos) { final ArrayList<SuggestedWordInfo> result = new ArrayList<SuggestedWordInfo>(); for (CompletionInfo info : infos) { diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index 52a31f2e6..4e798460c 100644 --- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -31,12 +31,11 @@ import java.util.HashSet; import java.util.Iterator; /** - * Stores all the pairs user types in databases. Prune the database if the size - * gets too big. Unlike AutoDictionary, it even stores the pairs that are already - * in the dictionary. + * Locally gathers stats about the words user types and various other signals like auto-correction + * cancellation or manual picks. This allows the keyboard to adapt to the typist over time. */ -public class UserBigramDictionary extends ExpandableDictionary { - private static final String TAG = "UserBigramDictionary"; +public class UserHistoryDictionary extends ExpandableDictionary { + private static final String TAG = "UserHistoryDictionary"; /** Any pair being typed or picked */ private static final int FREQUENCY_FOR_TYPED = 2; @@ -45,14 +44,14 @@ public class UserBigramDictionary extends ExpandableDictionary { private static final int FREQUENCY_MAX = 127; /** Maximum number of pairs. Pruning will start when databases goes above this number. */ - private static int sMaxUserBigrams = 10000; + private static int sMaxHistoryBigrams = 10000; /** * When it hits maximum bigram pair, it will delete until you are left with - * only (sMaxUserBigrams - sDeleteUserBigrams) pairs. + * only (sMaxHistoryBigrams - sDeleteHistoryBigrams) pairs. * Do not keep this number small to avoid deleting too often. */ - private static int sDeleteUserBigrams = 1000; + private static int sDeleteHistoryBigrams = 1000; /** * Database version should increase if the database structure changes @@ -64,7 +63,7 @@ public class UserBigramDictionary extends ExpandableDictionary { /** Name of the words table in the database */ private static final String MAIN_TABLE_NAME = "main"; // TODO: Consume less space by using a unique id for locale instead of the whole - // 2-5 character string. (Same TODO from AutoDictionary) + // 2-5 character string. private static final String MAIN_COLUMN_ID = BaseColumns._ID; private static final String MAIN_COLUMN_WORD1 = "word1"; private static final String MAIN_COLUMN_WORD2 = "word2"; @@ -114,8 +113,16 @@ public class UserBigramDictionary extends ExpandableDictionary { @Override public boolean equals(Object bigram) { - Bigram bigram2 = (Bigram) bigram; - return (mWord1.equals(bigram2.mWord1) && mWord2.equals(bigram2.mWord2)); + if (!(bigram instanceof Bigram)) { + return false; + } + final Bigram bigram2 = (Bigram) bigram; + final boolean eq1 = + mWord1 == null ? bigram2.mWord1 == null : mWord1.equals(bigram2.mWord1); + if (!eq1) { + return false; + } + return mWord2 == null ? bigram2.mWord2 == null : mWord2.equals(bigram2.mWord2); } @Override @@ -124,15 +131,15 @@ public class UserBigramDictionary extends ExpandableDictionary { } } - public void setDatabaseMax(int maxUserBigram) { - sMaxUserBigrams = maxUserBigram; + public void setDatabaseMax(int maxHistoryBigram) { + sMaxHistoryBigrams = maxHistoryBigram; } - public void setDatabaseDelete(int deleteUserBigram) { - sDeleteUserBigrams = deleteUserBigram; + public void setDatabaseDelete(int deleteHistoryBigram) { + sDeleteHistoryBigrams = deleteHistoryBigram; } - public UserBigramDictionary(Context context, LatinIME ime, String locale, int dicTypeId) { + public UserHistoryDictionary(Context context, LatinIME ime, String locale, int dicTypeId) { super(context, dicTypeId); mIme = ime; mLocale = locale; @@ -155,19 +162,39 @@ public class UserBigramDictionary extends ExpandableDictionary { } /** - * Pair will be added to the userbigram database. + * Return whether the passed charsequence is in the dictionary. + */ + @Override + public boolean isValidWord(final CharSequence word) { + // TODO: figure out what is the correct thing to do here. + return false; + } + + /** + * Pair will be added to the user history dictionary. + * + * The first word may be null. That means we don't know the context, in other words, + * it's only a unigram. The first word may also be an empty string : this means start + * context, as in beginning of a sentence for example. + * The second word may not be null (a NullPointerException would be thrown). */ - public int addBigramPair(String word1, String word2) { + public int addToUserHistory(final String word1, String word2) { // remove caps if second word is autocapitalized if (mIme != null && mIme.isAutoCapitalized()) { word2 = Character.toLowerCase(word2.charAt(0)) + word2.substring(1); } + super.addWord(word2, FREQUENCY_FOR_TYPED); // Do not insert a word as a bigram of itself - if (word1.equals(word2)) { + if (word2.equals(word1)) { return 0; } - int freq = super.addBigram(word1, word2, FREQUENCY_FOR_TYPED); + int freq; + if (null == word1) { + freq = FREQUENCY_FOR_TYPED; + } else { + freq = super.addBigram(word1, word2, FREQUENCY_FOR_TYPED); + } if (freq > FREQUENCY_MAX) freq = FREQUENCY_MAX; synchronized (mPendingWritesLock) { if (freq == FREQUENCY_FOR_TYPED || mPendingWrites.isEmpty()) { @@ -225,7 +252,10 @@ public class UserBigramDictionary extends ExpandableDictionary { int frequency = cursor.getInt(frequencyIndex); // Safeguard against adding really long words. Stack may overflow due // to recursive lookup - if (word1.length() < MAX_WORD_LENGTH && word2.length() < MAX_WORD_LENGTH) { + if (null == word1) { + super.addWord(word2, frequency); + } else if (word1.length() < MAX_WORD_LENGTH + && word2.length() < MAX_WORD_LENGTH) { super.setBigram(word1, word2, frequency); } cursor.moveToNext(); @@ -324,8 +354,8 @@ public class UserBigramDictionary extends ExpandableDictionary { try { int totalRowCount = c.getCount(); // prune out old data if we have too much data - if (totalRowCount > sMaxUserBigrams) { - int numDeleteRows = (totalRowCount - sMaxUserBigrams) + sDeleteUserBigrams; + if (totalRowCount > sMaxHistoryBigrams) { + int numDeleteRows = (totalRowCount - sMaxHistoryBigrams) + sDeleteHistoryBigrams; int pairIdColumnId = c.getColumnIndex(FREQ_COLUMN_PAIR_ID); c.moveToFirst(); int count = 0; @@ -367,13 +397,23 @@ public class UserBigramDictionary extends ExpandableDictionary { // Write all the entries to the db Iterator<Bigram> iterator = mMap.iterator(); while (iterator.hasNext()) { + // TODO: this process of making a text search for each pair each time + // is terribly inefficient. Optimize this. Bigram bi = iterator.next(); // find pair id - Cursor c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID }, - MAIN_COLUMN_WORD1 + "=? AND " + MAIN_COLUMN_WORD2 + "=? AND " - + MAIN_COLUMN_LOCALE + "=?", - new String[] { bi.mWord1, bi.mWord2, mLocale }, null, null, null); + final Cursor c; + if (null != bi.mWord1) { + c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID }, + MAIN_COLUMN_WORD1 + "=? AND " + MAIN_COLUMN_WORD2 + "=? AND " + + MAIN_COLUMN_LOCALE + "=?", + new String[] { bi.mWord1, bi.mWord2, mLocale }, null, null, null); + } else { + c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID }, + MAIN_COLUMN_WORD1 + " IS NULL AND " + MAIN_COLUMN_WORD2 + "=? AND " + + MAIN_COLUMN_LOCALE + "=?", + new String[] { bi.mWord2, mLocale }, null, null, null); + } int pairId; if (c.moveToFirst()) { diff --git a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java deleted file mode 100644 index 2fc395c3e..000000000 --- a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2010 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; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteQueryBuilder; -import android.os.AsyncTask; -import android.provider.BaseColumns; -import android.util.Log; - -import java.util.HashMap; -import java.util.Map.Entry; -import java.util.Set; - -/** - * This class (inherited from the old AutoDictionary) is used for user history - * based dictionary. It stores words that the user typed to supply a provision - * for suggesting and re-ordering of candidates. - */ -public class UserUnigramDictionary extends ExpandableDictionary { - static final boolean ENABLE_USER_UNIGRAM_DICTIONARY = false; - - // Weight added to a user picking a new word from the suggestion strip - static final int FREQUENCY_FOR_PICKED = 3; - // Weight added to a user typing a new word that doesn't get corrected (or is reverted) - static final int FREQUENCY_FOR_TYPED = 1; - // If the user touches a typed word 2 times or more, it will become valid. - private static final int VALIDITY_THRESHOLD = 2 * FREQUENCY_FOR_PICKED; - - private LatinIME mIme; - // Locale for which this user unigram dictionary is storing words - private String mLocale; - - private HashMap<String,Integer> mPendingWrites = new HashMap<String,Integer>(); - private final Object mPendingWritesLock = new Object(); - - // TODO: we should probably change the database name - private static final String DATABASE_NAME = "auto_dict.db"; - private static final int DATABASE_VERSION = 1; - - // These are the columns in the dictionary - // TODO: Consume less space by using a unique id for locale instead of the whole - // 2-5 character string. - private static final String COLUMN_ID = BaseColumns._ID; - private static final String COLUMN_WORD = "word"; - private static final String COLUMN_FREQUENCY = "freq"; - private static final String COLUMN_LOCALE = "locale"; - - /** Sort by descending order of frequency. */ - public static final String DEFAULT_SORT_ORDER = COLUMN_FREQUENCY + " DESC"; - - /** Name of the words table in the database */ - private static final String USER_UNIGRAM_DICT_TABLE_NAME = "words"; - - private static HashMap<String, String> sDictProjectionMap; - - static { - if (ENABLE_USER_UNIGRAM_DICTIONARY) { - sDictProjectionMap = new HashMap<String, String>(); - sDictProjectionMap.put(COLUMN_ID, COLUMN_ID); - sDictProjectionMap.put(COLUMN_WORD, COLUMN_WORD); - sDictProjectionMap.put(COLUMN_FREQUENCY, COLUMN_FREQUENCY); - sDictProjectionMap.put(COLUMN_LOCALE, COLUMN_LOCALE); - } - } - - private static DatabaseHelper sOpenHelper = null; - - public UserUnigramDictionary(Context context, LatinIME ime, String locale, int dicTypeId) { - super(context, dicTypeId); - // Super must be first statement of the constructor... I'd like not to do it if the - // user unigram dictionary is not enabled, but Java won't let me. - if (!ENABLE_USER_UNIGRAM_DICTIONARY) return; - mIme = ime; - mLocale = locale; - if (sOpenHelper == null) { - sOpenHelper = new DatabaseHelper(getContext()); - } - if (mLocale != null && mLocale.length() > 1) { - loadDictionary(); - } - } - - @Override - public synchronized boolean isValidWord(CharSequence word) { - if (!ENABLE_USER_UNIGRAM_DICTIONARY) return false; - final int frequency = getWordFrequency(word); - return frequency >= VALIDITY_THRESHOLD; - } - - @Override - public void close() { - super.close(); - if (!ENABLE_USER_UNIGRAM_DICTIONARY) return; - flushPendingWrites(); - // Don't close the database as locale changes will require it to be reopened anyway - // Also, the database is written to somewhat frequently, so it needs to be kept alive - // throughout the life of the process. - // mOpenHelper.close(); - } - - @Override - public void loadDictionaryAsync() { - if (!ENABLE_USER_UNIGRAM_DICTIONARY) return; - // Load the words that correspond to the current input locale - final Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale }); - if (null == cursor) return; - try { - if (cursor.moveToFirst()) { - int wordIndex = cursor.getColumnIndex(COLUMN_WORD); - int frequencyIndex = cursor.getColumnIndex(COLUMN_FREQUENCY); - while (!cursor.isAfterLast()) { - String word = cursor.getString(wordIndex); - int frequency = cursor.getInt(frequencyIndex); - // Safeguard against adding really long words. Stack may overflow due - // to recursive lookup - if (word.length() < getMaxWordLength()) { - super.addWord(word, frequency); - } - cursor.moveToNext(); - } - } - } finally { - cursor.close(); - } - } - - public void addUnigram(String newWord) { - if (!ENABLE_USER_UNIGRAM_DICTIONARY) return; - final int addFrequency = FREQUENCY_FOR_TYPED; - String word = newWord; - final int length = word.length(); - // Don't add very short or very long words. - if (length < 2 || length > getMaxWordLength()) return; - if (mIme.isAutoCapitalized()) { - // Remove caps before adding - word = Character.toLowerCase(word.charAt(0)) + word.substring(1); - } - int freq = getWordFrequency(word); - freq = freq < 0 ? addFrequency : freq + addFrequency; - super.addWord(word, freq); - - synchronized (mPendingWritesLock) { - // Write a null frequency if it is to be deleted from the db - mPendingWrites.put(word, freq == 0 ? null : new Integer(freq)); - } - } - - /** - * Schedules a background thread to write any pending words to the database. - */ - public void flushPendingWrites() { - if (!ENABLE_USER_UNIGRAM_DICTIONARY) return; - synchronized (mPendingWritesLock) { - // Nothing pending? Return - if (mPendingWrites.isEmpty()) return; - // Create a background thread to write the pending entries - new UpdateDbTask(sOpenHelper, mPendingWrites, mLocale).execute(); - // Create a new map for writing new entries into while the old one is written to db - mPendingWrites = new HashMap<String, Integer>(); - } - } - - /** - * This class helps open, create, and upgrade the database file. - */ - private static class DatabaseHelper extends SQLiteOpenHelper { - - DatabaseHelper(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + USER_UNIGRAM_DICT_TABLE_NAME + " (" - + COLUMN_ID + " INTEGER PRIMARY KEY," - + COLUMN_WORD + " TEXT," - + COLUMN_FREQUENCY + " INTEGER," - + COLUMN_LOCALE + " TEXT" - + ");"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - Log.w("UserUnigramDictionary", "Upgrading database from version " + oldVersion + " to " - + newVersion + ", which will destroy all old data"); - db.execSQL("DROP TABLE IF EXISTS " + USER_UNIGRAM_DICT_TABLE_NAME); - onCreate(db); - } - } - - private static Cursor query(String selection, String[] selectionArgs) { - SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); - qb.setTables(USER_UNIGRAM_DICT_TABLE_NAME); - qb.setProjectionMap(sDictProjectionMap); - - // Get the database and run the query - try { - SQLiteDatabase db = sOpenHelper.getReadableDatabase(); - Cursor c = qb.query(db, null, selection, selectionArgs, null, null, - DEFAULT_SORT_ORDER); - return c; - } catch (android.database.sqlite.SQLiteCantOpenDatabaseException e) { - // Can't open the database : presumably we can't access storage. That may happen - // when the device is wedged; do a best effort to still start the keyboard. - return null; - } - } - - /** - * Async task to write pending words to the database so that it stays in sync with - * the in-memory trie. - */ - private static class UpdateDbTask extends AsyncTask<Void, Void, Void> { - private final HashMap<String, Integer> mMap; - private final DatabaseHelper mDbHelper; - private final String mLocale; - - public UpdateDbTask(DatabaseHelper openHelper, HashMap<String, Integer> pendingWrites, - String locale) { - mMap = pendingWrites; - mLocale = locale; - mDbHelper = openHelper; - } - - @Override - protected Void doInBackground(Void... v) { - SQLiteDatabase db = null; - try { - db = mDbHelper.getWritableDatabase(); - } catch (android.database.sqlite.SQLiteCantOpenDatabaseException e) { - // With no access to the DB, this is moot. Do nothing: we'll exit through the - // test for null == db. - } - if (null == db) return null; - // Write all the entries to the db - Set<Entry<String,Integer>> mEntries = mMap.entrySet(); - for (Entry<String,Integer> entry : mEntries) { - Integer freq = entry.getValue(); - db.delete(USER_UNIGRAM_DICT_TABLE_NAME, COLUMN_WORD + "=? AND " + COLUMN_LOCALE - + "=?", new String[] { entry.getKey(), mLocale }); - if (freq != null) { - db.insert(USER_UNIGRAM_DICT_TABLE_NAME, null, - getContentValues(entry.getKey(), freq, mLocale)); - } - } - return null; - } - - private static ContentValues getContentValues(String word, int frequency, String locale) { - ContentValues values = new ContentValues(4); - values.put(COLUMN_WORD, word); - values.put(COLUMN_FREQUENCY, frequency); - values.put(COLUMN_LOCALE, locale); - return values; - } - } -} diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index a7de47c58..708634529 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -19,9 +19,11 @@ package com.android.inputmethod.latin; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -43,6 +45,7 @@ import java.io.PrintWriter; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.HashMap; public class Utils { private Utils() { @@ -260,8 +263,8 @@ public class Utils { } } - public static void writeBackSpace() { - UsabilityStudyLogUtils.getInstance().write("<backspace>\t0\t0"); + public static void writeBackSpace(int x, int y) { + UsabilityStudyLogUtils.getInstance().write("<backspace>\t" + x + "\t" + y); } public void writeChar(char c, int x, int y) { @@ -465,4 +468,23 @@ public class Utils { if (TextUtils.isEmpty(info)) return null; return info; } + + private static final String HARDWARE_PREFIX = Build.HARDWARE + ","; + private static final HashMap<Integer, String> sDeviceOverrideValueMap = + new HashMap<Integer, String>(); + + public static String getDeviceOverrideValue(Resources res, int overrideResId, String defValue) { + final Integer key = overrideResId; + if (!sDeviceOverrideValueMap.containsKey(key)) { + String overrideValue = defValue; + for (final String element : res.getStringArray(overrideResId)) { + if (element.startsWith(HARDWARE_PREFIX)) { + overrideValue = element.substring(HARDWARE_PREFIX.length()); + break; + } + } + sDeviceOverrideValueMap.put(key, overrideValue); + } + return sDeviceOverrideValueMap.get(key); + } } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index a9609310c..9f23f174f 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -140,8 +140,9 @@ public class WordComposer { keyX = x; keyY = y; } else { - codes = keyDetector.newCodeArray(); - keyDetector.getNearbyCodes(x, y, codes); + final Key key = keyDetector.detectHitKey(x, y); + // TODO: Pass an integer instead of an integer array + codes = new int[] { key != null ? key.mCode : NOT_A_CODE }; keyX = keyDetector.getTouchX(x); keyY = keyDetector.getTouchY(y); } @@ -202,9 +203,8 @@ public class WordComposer { if (key.mCode == codePoint) { final int x = key.mX + key.mWidth / 2; final int y = key.mY + key.mHeight / 2; - final int[] codes = keyDetector.newCodeArray(); - keyDetector.getNearbyCodes(x, y, codes); - add(codePoint, codes, x, y); + // TODO: Pass an integer instead of an integer array + add(codePoint, new int[] { key.mCode }, x, y); return; } } @@ -216,7 +216,7 @@ public class WordComposer { * Set the currently composing word to the one passed as an argument. * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. */ - public void setComposingWord(final CharSequence word, final Keyboard keyboard, + private void setComposingWord(final CharSequence word, final Keyboard keyboard, final KeyDetector keyDetector) { reset(); final int length = word.length(); @@ -233,7 +233,6 @@ public class WordComposer { final KeyDetector keyDetector = new KeyDetector(0); keyDetector.setKeyboard(keyboard, 0, 0); keyDetector.setProximityCorrectionEnabled(true); - keyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); setComposingWord(word, keyboard, keyDetector); } diff --git a/java/src/com/android/inputmethod/latin/XmlParseUtils.java b/java/src/com/android/inputmethod/latin/XmlParseUtils.java index e14c71cb5..481cdfa47 100644 --- a/java/src/com/android/inputmethod/latin/XmlParseUtils.java +++ b/java/src/com/android/inputmethod/latin/XmlParseUtils.java @@ -24,6 +24,10 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; public class XmlParseUtils { + private XmlParseUtils() { + // This utility class is not publicly instantiable. + } + @SuppressWarnings("serial") public static class ParseException extends XmlPullParserException { public ParseException(String msg, XmlPullParser parser) { diff --git a/java/src/com/android/inputmethod/latin/makedict/Dummy.java b/java/src/com/android/inputmethod/latin/makedict/Dummy.java new file mode 100644 index 000000000..27ea5ace6 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/makedict/Dummy.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2012 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.makedict; + +public class Dummy { + +} diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java index f6c1b163c..06fda44fa 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java @@ -65,7 +65,6 @@ import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.Utils; import java.util.ArrayList; -import java.util.List; public class SuggestionsView extends RelativeLayout implements OnClickListener, OnLongClickListener { @@ -143,9 +142,9 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, public final float mMinMoreSuggestionsWidth; public final int mMoreSuggestionsBottomGap; - private final List<TextView> mWords; - private final List<View> mDividers; - private final List<TextView> mInfos; + private final ArrayList<TextView> mWords; + private final ArrayList<View> mDividers; + private final ArrayList<TextView> mInfos; private final int mColorValidTypedWord; private final int mColorTypedWord; @@ -173,7 +172,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, private final TextView mHintToSaveView; public SuggestionsViewParams(Context context, AttributeSet attrs, int defStyle, - List<TextView> words, List<View> dividers, List<TextView> infos) { + ArrayList<TextView> words, ArrayList<View> dividers, ArrayList<TextView> infos) { mWords = words; mDividers = dividers; mInfos = infos; |