aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com
diff options
context:
space:
mode:
authorsatok <satok@google.com>2011-04-27 17:23:05 +0900
committersatok <satok@google.com>2011-04-27 17:23:05 +0900
commit31da2ea24bee6124feebb5fd1a010fc6c62946a0 (patch)
tree755fde89fe654f00eae61eb792bfe72661af385d /java/src/com
parent0dbb7e26d1e719251f66bf2f5034330e13bb5c3f (diff)
parent19bfef6cb0714a46a276abe45329e4abb661f76e (diff)
downloadlatinime-31da2ea24bee6124feebb5fd1a010fc6c62946a0.tar.gz
latinime-31da2ea24bee6124feebb5fd1a010fc6c62946a0.tar.xz
latinime-31da2ea24bee6124feebb5fd1a010fc6c62946a0.zip
Merge remote-tracking branch 'goog/master' into merge
Diffstat (limited to 'java/src/com')
-rw-r--r--java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java6
-rw-r--r--java/src/com/android/inputmethod/deprecated/VoiceProxy.java12
-rw-r--r--java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java24
-rw-r--r--java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java5
-rw-r--r--java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java1
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java136
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java26
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java2
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java112
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java3
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsDictionary.java8
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java2
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryCollection.java66
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFactory.java155
-rw-r--r--java/src/com/android/inputmethod/latin/EditingUtils.java2
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java8
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java15
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java20
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java18
19 files changed, 418 insertions, 203 deletions
diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
index d99f40765..1cc13f249 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
@@ -118,7 +118,7 @@ public class InputMethodManagerCompatWrapper {
}
Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList,
(imi != null ? imi.getInputMethodInfo() : null), allowsImplicitlySelectedSubtypes);
- if (retval == null || !(retval instanceof List) || ((List<?>)retval).isEmpty()) {
+ if (retval == null || !(retval instanceof List<?>) || ((List<?>)retval).isEmpty()) {
if (!FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES) {
// Returns an empty list
return Collections.emptyList();
@@ -137,7 +137,7 @@ public class InputMethodManagerCompatWrapper {
}
return subtypeList;
}
- return CompatUtils.copyInputMethodSubtypeListToWrapper((List<?>)retval);
+ return CompatUtils.copyInputMethodSubtypeListToWrapper(retval);
}
private InputMethodInfoCompatWrapper getLatinImeInputMethodInfo() {
@@ -159,7 +159,7 @@ public class InputMethodManagerCompatWrapper {
public Map<InputMethodInfoCompatWrapper, List<InputMethodSubtypeCompatWrapper>>
getShortcutInputMethodsAndSubtypes() {
Object retval = CompatUtils.invoke(mImm, null, METHOD_getShortcutInputMethodsAndSubtypes);
- if (retval == null || !(retval instanceof Map) || ((Map<?, ?>)retval).isEmpty()) {
+ if (retval == null || !(retval instanceof Map<?, ?>) || ((Map<?, ?>)retval).isEmpty()) {
if (!FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES) {
// Returns an empty map
return Collections.emptyMap();
diff --git a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
index 0d0591bd0..753dceead 100644
--- a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
+++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
@@ -754,15 +754,15 @@ public class VoiceProxy implements VoiceInput.UiListener {
}
public static class VoiceLoggerWrapper {
- private static final VoiceLoggerWrapper sInstance = new VoiceLoggerWrapper();
+ private static final VoiceLoggerWrapper sLoggerWrapperInstance = new VoiceLoggerWrapper();
private VoiceInputLogger mLogger;
public static VoiceLoggerWrapper getInstance(Context context) {
- if (sInstance.mLogger == null) {
+ if (sLoggerWrapperInstance.mLogger == null) {
// Not thread safe, but it's ok.
- sInstance.mLogger = VoiceInputLogger.getLogger(context);
+ sLoggerWrapperInstance.mLogger = VoiceInputLogger.getLogger(context);
}
- return sInstance;
+ return sLoggerWrapperInstance;
}
// private for the singleton
@@ -795,10 +795,10 @@ public class VoiceProxy implements VoiceInput.UiListener {
}
public static class VoiceInputWrapper {
- private static final VoiceInputWrapper sInstance = new VoiceInputWrapper();
+ private static final VoiceInputWrapper sInputWrapperInstance = new VoiceInputWrapper();
private VoiceInput mVoiceInput;
public static VoiceInputWrapper getInstance() {
- return sInstance;
+ return sInputWrapperInstance;
}
public void setVoiceInput(VoiceInput voiceInput, SubtypeSwitcher switcher) {
if (mVoiceInput == null && voiceInput != null) {
diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java
index ce576d0cc..a1b49b475 100644
--- a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java
+++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java
@@ -17,19 +17,17 @@
package com.android.inputmethod.deprecated.languageswitcher;
import com.android.inputmethod.keyboard.KeyboardParser;
-import com.android.inputmethod.latin.BinaryDictionary;
+import com.android.inputmethod.latin.DictionaryFactory;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.Settings;
import com.android.inputmethod.latin.SharedPreferencesCompat;
import com.android.inputmethod.latin.SubtypeSwitcher;
-import com.android.inputmethod.latin.Suggest;
import com.android.inputmethod.latin.Utils;
import org.xmlpull.v1.XmlPullParserException;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
@@ -123,24 +121,11 @@ public class InputLanguageSelection extends PreferenceActivity {
private Pair<Boolean, Boolean> hasDictionaryOrLayout(Locale locale) {
if (locale == null) return new Pair<Boolean, Boolean>(false, false);
final Resources res = getResources();
- final Configuration conf = res.getConfiguration();
- final Locale saveLocale = conf.locale;
- conf.locale = locale;
- res.updateConfiguration(conf, res.getDisplayMetrics());
- boolean hasDictionary = false;
+ final Locale saveLocale = Utils.setSystemLocale(res, locale);
+ final boolean hasDictionary = DictionaryFactory.isDictionaryAvailable(this, locale);
boolean hasLayout = false;
try {
- BinaryDictionary bd = BinaryDictionary.initDictionaryFromManager(this, Suggest.DIC_MAIN,
- locale, Utils.getMainDictionaryResourceId(res));
-
- // Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of
- // 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words.
- if (bd.getSize() > Suggest.LARGE_DICTIONARY_THRESHOLD / 4) {
- hasDictionary = true;
- }
- bd.close();
-
final String localeStr = locale.toString();
final String[] layoutCountryCodes = KeyboardParser.parseKeyboardLocale(
this, R.xml.kbd_qwerty).split(",", -1);
@@ -155,8 +140,7 @@ public class InputLanguageSelection extends PreferenceActivity {
} catch (XmlPullParserException e) {
} catch (IOException e) {
}
- conf.locale = saveLocale;
- res.updateConfiguration(conf, res.getDisplayMetrics());
+ Utils.setSystemLocale(res, saveLocale);
return new Pair<Boolean, Boolean>(hasDictionary, hasLayout);
}
diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java
index 1a606eaaf..5ef236e31 100644
--- a/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java
+++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java
@@ -16,7 +16,6 @@
package com.android.inputmethod.deprecated.languageswitcher;
-import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.Settings;
@@ -38,6 +37,7 @@ import java.util.Locale;
public class LanguageSwitcher {
private static final String TAG = LanguageSwitcher.class.getSimpleName();
+ @SuppressWarnings("unused")
private static final String KEYBOARD_MODE = "keyboard";
private static final String[] EMPTY_STIRNG_ARRAY = new String[0];
@@ -154,7 +154,6 @@ public class LanguageSwitcher {
/**
* Returns the currently selected input locale, or the display locale if no specific
* locale was selected for input.
- * @return
*/
public Locale getInputLocale() {
if (getLocaleCount() == 0) return mDefaultInputLocale;
@@ -175,7 +174,6 @@ public class LanguageSwitcher {
/**
* Returns the next input locale in the list. Wraps around to the beginning of the
* list if we're at the end of the list.
- * @return
*/
public Locale getNextInputLocale() {
if (getLocaleCount() == 0) return mDefaultInputLocale;
@@ -201,7 +199,6 @@ public class LanguageSwitcher {
/**
* Returns the previous input locale in the list. Wraps around to the end of the
* list if we're at the beginning of the list.
- * @return
*/
public Locale getPrevInputLocale() {
if (getLocaleCount() == 0) return mDefaultInputLocale;
diff --git a/java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java b/java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java
index dcd124f70..87b943426 100644
--- a/java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java
@@ -17,7 +17,6 @@
package com.android.inputmethod.deprecated.voice;
import com.android.common.speech.LoggingEvents;
-import com.android.common.userhappiness.UserHappinessSignals;
import com.android.inputmethod.deprecated.compat.VoiceInputLoggerCompatUtils;
import android.content.Context;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index e163457d8..55041154d 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -57,6 +57,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private LatinKeyboardView mInputView;
private LatinIME mInputMethodService;
+ // TODO: Combine these key state objects with auto mode switch state.
private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
@@ -75,13 +76,17 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private boolean mVoiceKeyEnabled;
private boolean mVoiceButtonOnPrimary;
- private static final int AUTO_MODE_SWITCH_STATE_ALPHA = 0;
- private static final int AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN = 1;
- private static final int AUTO_MODE_SWITCH_STATE_SYMBOL = 2;
+ // TODO: Encapsulate these state handling to separate class and combine with ShiftKeyState
+ // and ModifierKeyState.
+ private static final int SWITCH_STATE_ALPHA = 0;
+ private static final int SWITCH_STATE_SYMBOL_BEGIN = 1;
+ private static final int SWITCH_STATE_SYMBOL = 2;
// The following states are used only on the distinct multi-touch panel devices.
- private static final int AUTO_MODE_SWITCH_STATE_MOMENTARY = 3;
- private static final int AUTO_MODE_SWITCH_STATE_CHORDING = 4;
- private int mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
+ private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3;
+ private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4;
+ private static final int SWITCH_STATE_CHORDING_ALPHA = 5;
+ private static final int SWITCH_STATE_CHORDING_SYMBOL = 6;
+ private int mSwitchState = SWITCH_STATE_ALPHA;
// Indicates whether or not we have the settings key in option of settings
private boolean mSettingsKeyEnabledInSettings;
@@ -124,7 +129,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public void loadKeyboard(EditorInfo attribute, boolean voiceKeyEnabled,
boolean voiceButtonOnPrimary) {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
+ mSwitchState = SWITCH_STATE_ALPHA;
try {
loadKeyboardInternal(attribute, voiceKeyEnabled, voiceButtonOnPrimary, false);
} catch (RuntimeException e) {
@@ -164,7 +169,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id);
LatinKeyboard keyboard = (ref == null) ? null : ref.get();
if (keyboard == null) {
- final Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(
+ final Resources res = mInputMethodService.getResources();
+ final Locale savedLocale = Utils.setSystemLocale(res,
mSubtypeSwitcher.getInputLocale());
keyboard = new LatinKeyboard(mInputMethodService, id);
@@ -178,7 +184,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": "
+ ((ref == null) ? "LOAD" : "GCed") + " id=" + id);
- mSubtypeSwitcher.changeSystemLocale(savedLocale);
+ Utils.setSystemLocale(res, savedLocale);
} else if (DEBUG) {
Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT id=" + id);
}
@@ -465,6 +471,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
// In symbol mode, just toggle symbol and symbol more keyboard.
shiftKeyState.onPress();
toggleShift();
+ mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
}
}
@@ -486,6 +493,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
} else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !withSliding) {
// Shift has been pressed without chording while caps lock state.
toggleCapsLock();
+ // To be able to turn off caps lock by "double tap" on shift key, we should ignore
+ // the second tap of the "double tap" from now for a while because we just have
+ // already turned off caps lock above.
+ mInputView.startIgnoringDoubleTap();
} else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()
&& !withSliding) {
// Shift has been pressed without chording while shifted state.
@@ -496,6 +507,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
// transited from automatic temporary upper case.
toggleShift();
}
+ } else {
+ // In symbol mode, snap back to the previous keyboard mode if the user chords the shift
+ // key and another key, then releases the shift key.
+ if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) {
+ toggleShift();
+ }
}
shiftKeyState.onRelease();
}
@@ -510,7 +527,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
+ " symbolKeyState=" + mSymbolKeyState);
changeKeyboardMode();
mSymbolKeyState.onPress();
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_MOMENTARY;
+ mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
}
public void onReleaseSymbol() {
@@ -522,9 +539,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
+ " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+ " symbolKeyState=" + mSymbolKeyState);
// Snap back to the previous keyboard mode if the user chords the mode change key and
- // other key, then released the mode change key.
- if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_CHORDING)
+ // another key, then releases the mode change key.
+ if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) {
changeKeyboardMode();
+ }
mSymbolKeyState.onRelease();
}
@@ -543,8 +561,13 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public void onCancelInput() {
// Snap back to the previous keyboard mode if the user cancels sliding input.
- if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY && getPointerCount() == 1)
- changeKeyboardMode();
+ if (getPointerCount() == 1) {
+ if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
+ changeKeyboardMode();
+ } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
+ toggleShift();
+ }
+ }
}
private void toggleShiftInSymbol() {
@@ -567,8 +590,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
setKeyboard(keyboard);
}
- public boolean isInMomentaryAutoModeSwitchState() {
- return mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY;
+ public boolean isInMomentarySwitchState() {
+ return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL
+ || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
}
public boolean isVibrateAndSoundFeedbackRequired() {
@@ -582,9 +606,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private void toggleKeyboardMode() {
loadKeyboardInternal(mAttribute, mVoiceKeyEnabled, mVoiceButtonOnPrimary, !mIsSymbols);
if (mIsSymbols) {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN;
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
} else {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
+ mSwitchState = SWITCH_STATE_ALPHA;
}
}
@@ -596,28 +620,52 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return mInputView != null && mInputView.hasDistinctMultitouch();
}
+ private static boolean isSpaceCharacter(int c) {
+ return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER;
+ }
+
+ private static boolean isQuoteCharacter(int c) {
+ // Apostrophe, quotation mark.
+ if (c == '\'' || c == '"')
+ return true;
+ // \u2018: Left single quotation mark
+ // \u2019: Right single quotation mark
+ // \u201a: Single low-9 quotation mark
+ // \u201b: Single high-reversed-9 quotation mark
+ // \u201c: Left double quotation mark
+ // \u201d: Right double quotation mark
+ // \u201e: Double low-9 quotation mark
+ // \u201f: Double high-reversed-9 quotation mark
+ if (c >= '\u2018' && c <= '\u201f')
+ return true;
+ // \u00ab: Left-pointing double angle quotation mark
+ // \u00bb: Right-pointing double angle quotation mark
+ if (c == '\u00ab' || c == '\u00bb')
+ return true;
+ return false;
+ }
+
/**
* Updates state machine to figure out when to automatically snap back to the previous mode.
*/
- public void onKey(int key) {
+ public void onKey(int code) {
if (DEBUG_STATE)
- Log.d(TAG, "onKey: code=" + key + " autoModeSwitchState=" + mAutoModeSwitchState
+ Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState
+ " pointers=" + getPointerCount());
- switch (mAutoModeSwitchState) {
- case AUTO_MODE_SWITCH_STATE_MOMENTARY:
+ switch (mSwitchState) {
+ case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
// Only distinct multi touch devices can be in this state.
// On non-distinct multi touch devices, mode change key is handled by
// {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and
- // {@link LatinIME#onRelease}. So, on such devices, {@link #mAutoModeSwitchState} starts
- // from {@link #AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN}, or
- // {@link #AUTO_MODE_SWITCH_STATE_ALPHA}, not from
- // {@link #AUTO_MODE_SWITCH_STATE_MOMENTARY}.
- if (key == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+ // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts
+ // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from
+ // {@link #SWITCH_STATE_MOMENTARY}.
+ if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
// Detected only the mode change key has been pressed, and then released.
if (mIsSymbols) {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN;
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
} else {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
+ mSwitchState = SWITCH_STATE_ALPHA;
}
} else if (getPointerCount() == 1) {
// Snap back to the previous keyboard mode if the user pressed the mode change key
@@ -628,18 +676,34 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
} else {
// Chording input is being started. The keyboard mode will be snapped back to the
// previous mode in {@link onReleaseSymbol} when the mode change key is released.
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_CHORDING;
+ mSwitchState = SWITCH_STATE_CHORDING_ALPHA;
+ }
+ break;
+ case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
+ if (code == Keyboard.CODE_SHIFT) {
+ // Detected only the shift key has been pressed on symbol layout, and then released.
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
+ } else if (getPointerCount() == 1) {
+ // Snap back to the previous keyboard mode if the user pressed the shift key on
+ // symbol mode and slid to other key, then released the finger.
+ toggleShift();
+ mSwitchState = SWITCH_STATE_SYMBOL;
+ } else {
+ // Chording input is being started. The keyboard mode will be snapped back to the
+ // previous mode in {@link onReleaseShift} when the shift key is released.
+ mSwitchState = SWITCH_STATE_CHORDING_SYMBOL;
}
break;
- case AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN:
- if (key != Keyboard.CODE_SPACE && key != Keyboard.CODE_ENTER && key >= 0) {
- mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL;
+ case SWITCH_STATE_SYMBOL_BEGIN:
+ if (!isSpaceCharacter(code) && code >= 0) {
+ mSwitchState = SWITCH_STATE_SYMBOL;
}
break;
- case AUTO_MODE_SWITCH_STATE_SYMBOL:
+ case SWITCH_STATE_SYMBOL:
+ case SWITCH_STATE_CHORDING_SYMBOL:
// Snap back to alpha keyboard mode if user types one or more non-space/enter
- // characters followed by a space/enter.
- if (key == Keyboard.CODE_ENTER || key == Keyboard.CODE_SPACE) {
+ // characters followed by a space/enter or quotation mark.
+ if (isSpaceCharacter(code) || isQuoteCharacter(code)) {
changeKeyboardMode();
}
break;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index c36895258..11476e069 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -44,6 +44,7 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@@ -73,7 +74,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private static final boolean DEBUG_SHOW_ALIGN = false;
private static final boolean DEBUG_KEYBOARD_GRID = false;
- private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = false;
+ private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = true;
private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true;
public static final int COLOR_SCHEME_WHITE = 0;
@@ -189,6 +190,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private static final int MSG_REPEAT_KEY = 3;
private static final int MSG_LONGPRESS_KEY = 4;
private static final int MSG_LONGPRESS_SHIFT_KEY = 5;
+ private static final int MSG_IGNORE_DOUBLE_TAP = 6;
private boolean mInKeyRepeat;
@@ -286,6 +288,16 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
public void cancelKeyTimers() {
cancelKeyRepeatTimer();
cancelLongPressTimers();
+ removeMessages(MSG_IGNORE_DOUBLE_TAP);
+ }
+
+ public void startIgnoringDoubleTap() {
+ sendMessageDelayed(obtainMessage(MSG_IGNORE_DOUBLE_TAP),
+ ViewConfiguration.getDoubleTapTimeout());
+ }
+
+ public boolean isIgnoringDoubleTap() {
+ return hasMessages(MSG_IGNORE_DOUBLE_TAP);
}
public void cancelAllMessages() {
@@ -449,7 +461,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
final PointerTracker tracker = getPointerTracker(id);
// If the second down event is also on shift key.
if (tracker.isOnShiftKey((int)secondDown.getX(), (int)secondDown.getY())) {
- onDoubleTapShiftKey(tracker);
+ // Detected a double tap on shift key. If we are in the ignoring double tap
+ // mode, it means we have already turned off caps lock in
+ // {@link KeyboardSwitcher#onReleaseShift} .
+ final boolean ignoringDoubleTap = mHandler.isIgnoringDoubleTap();
+ if (!ignoringDoubleTap)
+ onDoubleTapShiftKey(tracker);
return true;
}
// Otherwise these events should not be handled as double tap.
@@ -468,6 +485,11 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
}
+ public void startIgnoringDoubleTap() {
+ if (ENABLE_CAPSLOCK_BY_DOUBLETAP)
+ mHandler.startIgnoringDoubleTap();
+ }
+
public void setOnKeyboardActionListener(KeyboardActionListener listener) {
mKeyboardActionListener = listener;
for (PointerTracker tracker : mPointerTrackers) {
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index e3161f610..abd1ef286 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -662,7 +662,7 @@ public class PointerTracker {
// We need not start long press timer on the key which has manual temporary upper case
// code defined and the keyboard is in manual temporary upper case mode.
return;
- } else if (mKeyboardSwitcher.isInMomentaryAutoModeSwitchState()) {
+ } else if (mKeyboardSwitcher.isInMomentarySwitchState()) {
// We use longer timeout for sliding finger input started from the symbols mode key.
mHandler.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this);
} else {
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 7e63aacdf..d95fb9638 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -21,12 +21,8 @@ import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.ProximityInfo;
import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.util.Log;
-import java.io.File;
import java.util.Arrays;
-import java.util.Locale;
/**
* Implements a static, compacted, binary dictionary of standard words.
@@ -45,16 +41,15 @@ public class BinaryDictionary extends Dictionary {
public static final int MAX_WORD_LENGTH = 48;
public static final int MAX_WORDS = 18;
+ @SuppressWarnings("unused")
private static final String TAG = "BinaryDictionary";
private static final int MAX_PROXIMITY_CHARS_SIZE = ProximityInfo.MAX_PROXIMITY_CHARS_SIZE;
private static final int MAX_BIGRAMS = 60;
private static final int TYPED_LETTER_MULTIPLIER = 2;
- private static final BinaryDictionary sInstance = new BinaryDictionary();
private int mDicTypeId;
private int mNativeDict;
- private long mDictLength;
private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_PROXIMITY_CHARS_SIZE];
private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS];
private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS];
@@ -79,95 +74,32 @@ public class BinaryDictionary extends Dictionary {
private int mFlags = 0;
- private BinaryDictionary() {
- }
-
/**
- * Initializes a dictionary from a raw resource file
- * @param context application context for reading resources
- * @param resId the resource containing the raw binary dictionary
- * @param dicTypeId the type of the dictionary being created, out of the list in Suggest.DIC_*
- * @return an initialized instance of BinaryDictionary
+ * Constructor for the binary dictionary. This is supposed to be called from the
+ * dictionary factory.
+ * All implementations should pass null into flagArray, except for testing purposes.
+ * @param context the context to access the environment from.
+ * @param filename the name of the file to read through native code.
+ * @param offset the offset of the dictionary data within the file.
+ * @param length the length of the binary data.
+ * @param flagArray the flags to limit the dictionary to, or null for default.
*/
- public static BinaryDictionary initDictionary(Context context, int resId, int dicTypeId) {
- synchronized (sInstance) {
- sInstance.closeInternal();
- try {
- final AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId);
- if (afd == null) {
- Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
- return null;
- }
- final String sourceDir = context.getApplicationInfo().sourceDir;
- final File packagePath = new File(sourceDir);
- // TODO: Come up with a way to handle a directory.
- if (!packagePath.isFile()) {
- Log.e(TAG, "sourceDir is not a file: " + sourceDir);
- return null;
- }
- sInstance.loadDictionary(sourceDir, afd.getStartOffset(), afd.getLength());
- sInstance.mDicTypeId = dicTypeId;
- } catch (android.content.res.Resources.NotFoundException e) {
- Log.e(TAG, "Could not find the resource. resId=" + resId);
- return null;
- }
- }
- sInstance.mFlags = Flag.initFlags(ALL_FLAGS, context, SubtypeSwitcher.getInstance());
- return sInstance;
- }
-
- /* package for test */ static BinaryDictionary initDictionary(Context context, File dictionary,
- long startOffset, long length, int dicTypeId, Flag[] flagArray) {
- synchronized (sInstance) {
- sInstance.closeInternal();
- if (dictionary.isFile()) {
- sInstance.loadDictionary(dictionary.getAbsolutePath(), startOffset, length);
- sInstance.mDicTypeId = dicTypeId;
- } else {
- Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath());
- return null;
- }
- }
- sInstance.mFlags = Flag.initFlags(flagArray, context, null);
- return sInstance;
+ public BinaryDictionary(final Context context,
+ final String filename, final long offset, final long length, Flag[] flagArray) {
+ // Note: at the moment a binary dictionary is always of the "main" type.
+ // Initializing this here will help transitioning out of the scheme where
+ // the Suggest class knows everything about every single dictionary.
+ mDicTypeId = Suggest.DIC_MAIN;
+ // TODO: Stop relying on the state of SubtypeSwitcher, get it as a parameter
+ mFlags = Flag.initFlags(null == flagArray ? ALL_FLAGS : flagArray, context,
+ SubtypeSwitcher.getInstance());
+ loadDictionary(filename, offset, length);
}
static {
Utils.loadNativeLibrary();
}
- /**
- * Initializes a dictionary from a dictionary pack.
- *
- * This searches for a content provider providing a dictionary pack for the specified
- * locale. If none is found, it falls back to using the resource passed as fallBackResId
- * as a dictionary.
- * @param context application context for reading resources
- * @param dicTypeId the type of the dictionary being created, out of the list in Suggest.DIC_*
- * @param locale the locale for which to create the dictionary
- * @param fallBackResId the id of the resource to use as a fallback if no pack is found
- * @return an initialized instance of BinaryDictionary
- */
- public static BinaryDictionary initDictionaryFromManager(Context context, int dicTypeId,
- Locale locale, int fallbackResId) {
- if (null == locale) {
- Log.e(TAG, "No locale defined for dictionary");
- return initDictionary(context, fallbackResId, dicTypeId);
- }
- synchronized (sInstance) {
- sInstance.closeInternal();
-
- final AssetFileAddress dictFile = BinaryDictionaryGetter.getDictionaryFile(locale,
- context, fallbackResId);
- if (null != dictFile) {
- sInstance.loadDictionary(dictFile.mFilename, dictFile.mOffset, dictFile.mLength);
- sInstance.mDicTypeId = dicTypeId;
- }
- }
- sInstance.mFlags = Flag.initFlags(ALL_FLAGS, context, SubtypeSwitcher.getInstance());
- return sInstance;
- }
-
private native int openNative(String sourceDir, long dictOffset, long dictSize,
int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength,
int maxWords, int maxAlternatives);
@@ -184,7 +116,6 @@ public class BinaryDictionary extends Dictionary {
mNativeDict = openNative(path, startOffset, length,
TYPED_LETTER_MULTIPLIER, FULL_WORD_SCORE_MULTIPLIER,
MAX_WORD_LENGTH, MAX_WORDS, MAX_PROXIMITY_CHARS_SIZE);
- mDictLength = length;
}
@Override
@@ -278,10 +209,6 @@ public class BinaryDictionary extends Dictionary {
return isValidWordNative(mNativeDict, chars, chars.length);
}
- public long getSize() {
- return mDictLength; // This value is initialized in loadDictionary()
- }
-
@Override
public synchronized void close() {
closeInternal();
@@ -291,7 +218,6 @@ public class BinaryDictionary extends Dictionary {
if (mNativeDict != 0) {
closeNative(mNativeDict);
mNativeDict = 0;
- mDictLength = 0;
}
}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 72512c7e1..c4e098a0c 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -65,9 +65,6 @@ class BinaryDictionaryGetter {
* If that fails:
* - Returns null.
* @return The address of a valid file, or null.
- * @throws FileNotFoundException if a dictionary provider returned a file name, but the
- * file cannot be found.
- * @throws IOException if there was an I/O problem reading or copying a file.
*/
public static AssetFileAddress getDictionaryFile(Locale locale, Context context,
int fallbackResId) {
diff --git a/java/src/com/android/inputmethod/latin/ContactsDictionary.java b/java/src/com/android/inputmethod/latin/ContactsDictionary.java
index 048f72dc5..bdb68cac7 100644
--- a/java/src/com/android/inputmethod/latin/ContactsDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsDictionary.java
@@ -95,6 +95,14 @@ public class ContactsDictionary extends ExpandableDictionary {
mLastLoadedContacts = SystemClock.uptimeMillis();
}
+ @Override
+ public void getBigrams(final WordComposer codes, final CharSequence previousWord,
+ final WordCallback callback) {
+ // Do not return bigrams from Contacts when nothing was typed.
+ if (codes.size() <= 0) return;
+ super.getBigrams(codes, previousWord, callback);
+ }
+
private void addWords(Cursor cursor) {
clearDictionary();
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index ac43d6477..c7737b9a2 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -61,7 +61,7 @@ public abstract class Dictionary {
* words are added through the callback object.
* @param composer the key sequence to match
* @param callback the callback object to send matched words to as possible candidates
- * @see WordCallback#addWord(char[], int, int)
+ * @see WordCallback#addWord(char[], int, int, int, int, DataType)
*/
abstract public void getWords(final WordComposer composer, final WordCallback callback);
diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
new file mode 100644
index 000000000..4b64e5344
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Class for a collection of dictionaries that behave like one dictionary.
+ */
+public class DictionaryCollection extends Dictionary {
+
+ protected final List<Dictionary> mDictionaries;
+
+ public DictionaryCollection() {
+ mDictionaries = new CopyOnWriteArrayList<Dictionary>();
+ }
+
+ public DictionaryCollection(Dictionary... dictionaries) {
+ mDictionaries = new CopyOnWriteArrayList<Dictionary>(dictionaries);
+ }
+
+ @Override
+ public void getWords(final WordComposer composer, final WordCallback callback) {
+ for (final Dictionary dict : mDictionaries)
+ dict.getWords(composer, callback);
+ }
+
+ @Override
+ public void getBigrams(final WordComposer composer, final CharSequence previousWord,
+ final WordCallback callback) {
+ for (final Dictionary dict : mDictionaries)
+ dict.getBigrams(composer, previousWord, callback);
+ }
+
+ @Override
+ public boolean isValidWord(CharSequence word) {
+ for (final Dictionary dict : mDictionaries)
+ if (dict.isValidWord(word)) return true;
+ return false;
+ }
+
+ @Override
+ public void close() {
+ for (final Dictionary dict : mDictionaries)
+ dict.close();
+ }
+
+ public void addDictionary(Dictionary newDict) {
+ mDictionaries.add(newDict);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
new file mode 100644
index 000000000..2dbd582f3
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -0,0 +1,155 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.io.File;
+import java.util.Locale;
+
+/**
+ * Factory for dictionary instances.
+ */
+public class DictionaryFactory {
+
+ private static String TAG = DictionaryFactory.class.getSimpleName();
+
+ /**
+ * Initializes a dictionary from a dictionary pack.
+ *
+ * This searches for a content provider providing a dictionary pack for the specified
+ * locale. If none is found, it falls back to using the resource passed as fallBackResId
+ * as a dictionary.
+ * @param context application context for reading resources
+ * @param locale the locale for which to create the dictionary
+ * @param fallbackResId the id of the resource to use as a fallback if no pack is found
+ * @return an initialized instance of Dictionary
+ */
+ public static Dictionary createDictionaryFromManager(Context context, Locale locale,
+ int fallbackResId) {
+ if (null == locale) {
+ Log.e(TAG, "No locale defined for dictionary");
+ return new DictionaryCollection(createBinaryDictionary(context, fallbackResId));
+ }
+
+ final AssetFileAddress dictFile = BinaryDictionaryGetter.getDictionaryFile(locale,
+ context, fallbackResId);
+ if (null == dictFile) return null;
+ return new DictionaryCollection(new BinaryDictionary(context,
+ dictFile.mFilename, dictFile.mOffset, dictFile.mLength, null));
+ }
+
+ /**
+ * Initializes a dictionary from a raw resource file
+ * @param context application context for reading resources
+ * @param resId the resource containing the raw binary dictionary
+ * @return an initialized instance of BinaryDictionary
+ */
+ protected static BinaryDictionary createBinaryDictionary(Context context, int resId) {
+ AssetFileDescriptor afd = null;
+ try {
+ // TODO: IMPORTANT: Do not create a dictionary from a placeholder.
+ afd = context.getResources().openRawResourceFd(resId);
+ if (afd == null) {
+ Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
+ return null;
+ }
+ if (!isFullDictionary(afd)) return null;
+ final String sourceDir = context.getApplicationInfo().sourceDir;
+ final File packagePath = new File(sourceDir);
+ // TODO: Come up with a way to handle a directory.
+ if (!packagePath.isFile()) {
+ Log.e(TAG, "sourceDir is not a file: " + sourceDir);
+ return null;
+ }
+ return new BinaryDictionary(context,
+ sourceDir, afd.getStartOffset(), afd.getLength(), null);
+ } catch (android.content.res.Resources.NotFoundException e) {
+ Log.e(TAG, "Could not find the resource. resId=" + resId);
+ return null;
+ } finally {
+ if (null != afd) {
+ try {
+ afd.close();
+ } catch (java.io.IOException e) {
+ /* IOException on close ? What am I supposed to do ? */
+ }
+ }
+ }
+ }
+
+ /**
+ * Create a dictionary from passed data. This is intended for unit tests only.
+ * @param context the test context to create this data from.
+ * @param dictionary the file to read
+ * @param startOffset the offset in the file where the data starts
+ * @param length the length of the data
+ * @param flagArray the flags to use with this data for testing
+ * @return the created dictionary, or null.
+ */
+ public static Dictionary createDictionaryForTest(Context context, File dictionary,
+ long startOffset, long length, Flag[] flagArray) {
+ if (dictionary.isFile()) {
+ return new BinaryDictionary(context, dictionary.getAbsolutePath(), startOffset, length,
+ flagArray);
+ } else {
+ Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath());
+ return null;
+ }
+ }
+
+ /**
+ * Find out whether a dictionary is available for this locale.
+ * @param context the context on which to check resources.
+ * @param locale the locale to check for.
+ * @return whether a (non-placeholder) dictionary is available or not.
+ */
+ public static boolean isDictionaryAvailable(Context context, Locale locale) {
+ final Resources res = context.getResources();
+ final Locale saveLocale = Utils.setSystemLocale(res, locale);
+
+ final int resourceId = Utils.getMainDictionaryResourceId(res);
+ final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
+ final boolean hasDictionary = isFullDictionary(afd);
+ try {
+ if (null != afd) afd.close();
+ } catch (java.io.IOException e) {
+ /* Um, what can we do here exactly? */
+ }
+
+ Utils.setSystemLocale(res, saveLocale);
+ return hasDictionary;
+ }
+
+ // TODO: Find the Right Way to find out whether the resource is a placeholder or not.
+ // Suggestion : strip the locale, open the placeholder file and store its offset.
+ // Upon opening the file, if it's the same offset, then it's the placeholder.
+ private static final long PLACEHOLDER_LENGTH = 34;
+ /**
+ * Finds out whether the data pointed out by an AssetFileDescriptor is a full
+ * dictionary (as opposed to null, or to a place holder).
+ * @param afd the file descriptor to test, or null
+ * @return true if the dictionary is a real full dictionary, false if it's null or a placeholder
+ */
+ protected static boolean isFullDictionary(final AssetFileDescriptor afd) {
+ return (afd != null && afd.getLength() > PLACEHOLDER_LENGTH);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/EditingUtils.java b/java/src/com/android/inputmethod/latin/EditingUtils.java
index ea281f5b8..39e7e402f 100644
--- a/java/src/com/android/inputmethod/latin/EditingUtils.java
+++ b/java/src/com/android/inputmethod/latin/EditingUtils.java
@@ -73,7 +73,7 @@ public class EditingUtils {
/**
* @param connection connection to the current text field.
- * @param sep characters which may separate words
+ * @param separators characters which may separate words
* @return the word that surrounds the cursor, including up to one trailing
* separator. For example, if the field contains "he|llo world", where |
* represents the cursor, then "hello " will be returned.
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 28fd6aad7..39bc78e20 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -112,7 +112,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private static final int DELAY_UPDATE_SUGGESTIONS = 180;
private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300;
- private static final int DELAY_UPDATE_SHIFT_STATE = 300;
+ private static final int DELAY_UPDATE_SHIFT_STATE = 100;
private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
// How many continuous deletes at which to start deleting at a higher speed.
@@ -470,14 +470,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
final Locale keyboardLocale = new Locale(localeStr);
- final Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(keyboardLocale);
+ final Resources res = mResources;
+ final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale);
if (mSuggest != null) {
mSuggest.close();
}
final SharedPreferences prefs = mPrefs;
mQuickFixes = isQuickFixesEnabled(prefs);
- final Resources res = mResources;
int mainDicResId = Utils.getMainDictionaryResourceId(res);
mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
loadAndSetAutoCorrectionThreshold(prefs);
@@ -499,7 +499,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mWordSeparators = res.getString(R.string.word_separators);
mSentenceSeparators = res.getString(R.string.sentence_separators);
- mSubtypeSwitcher.changeSystemLocale(savedLocale);
+ Utils.setSystemLocale(res, savedLocale);
}
/* package private */ void resetSuggestMainDict() {
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index 158977927..d8012087b 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -475,19 +475,6 @@ public class SubtypeSwitcher {
}
}
- /**
- * Change system locale for this application
- * @param newLocale
- * @return oldLocale
- */
- public Locale changeSystemLocale(Locale newLocale) {
- Configuration conf = mResources.getConfiguration();
- Locale oldLocale = conf.locale;
- conf.locale = newLocale;
- mResources.updateConfiguration(conf, mResources.getDisplayMetrics());
- return oldLocale;
- }
-
public boolean isKeyboardMode() {
return KEYBOARD_MODE.equals(getCurrentSubtypeMode());
}
@@ -608,7 +595,7 @@ public class SubtypeSwitcher {
}
public static String getMiddleDisplayLanguage(Locale locale) {
- return toTitleCase(locale.getDisplayLanguage(new Locale(locale.getLanguage())));
+ return toTitleCase((new Locale(locale.getLanguage()).getDisplayLanguage(locale)));
}
public static String getShortDisplayLanguage(Locale locale) {
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 15743ee2d..ca75866c0 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -56,7 +56,7 @@ public class Suggest implements Dictionary.WordCallback {
/**
* Maximum possible bigram frequency. Will depend on how many bits are being used in data
- * structure. Maximum bigram freqeuncy will get the BIGRAM_MULTIPLIER_MAX as the multiplier.
+ * structure. Maximum bigram frequency will get the BIGRAM_MULTIPLIER_MAX as the multiplier.
*/
public static final int MAXIMUM_BIGRAM_FREQUENCY = 127;
@@ -75,13 +75,11 @@ public class Suggest implements Dictionary.WordCallback {
public static final String DICT_KEY_USER_BIGRAM = "user_bigram";
public static final String DICT_KEY_WHITELIST ="whitelist";
- public static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
-
private static final boolean DBG = LatinImeLogger.sDBG;
private AutoCorrection mAutoCorrection;
- private BinaryDictionary mMainDict;
+ private Dictionary mMainDict;
private WhitelistDictionary mWhiteListDictionary;
private final Map<String, Dictionary> mUnigramDictionaries = new HashMap<String, Dictionary>();
private final Map<String, Dictionary> mBigramDictionaries = new HashMap<String, Dictionary>();
@@ -108,17 +106,17 @@ public class Suggest implements Dictionary.WordCallback {
private int mCorrectionMode = CORRECTION_BASIC;
public Suggest(Context context, int dictionaryResId, Locale locale) {
- init(context, BinaryDictionary.initDictionaryFromManager(context, DIC_MAIN, locale,
+ init(context, DictionaryFactory.createDictionaryFromManager(context, locale,
dictionaryResId));
}
/* package for test */ Suggest(Context context, File dictionary, long startOffset, long length,
Flag[] flagArray) {
- init(null, BinaryDictionary.initDictionary(context, dictionary, startOffset, length,
- DIC_MAIN, flagArray));
+ init(null, DictionaryFactory.createDictionaryForTest(context, dictionary, startOffset,
+ length, flagArray));
}
- private void init(Context context, BinaryDictionary mainDict) {
+ private void init(Context context, Dictionary mainDict) {
if (mainDict != null) {
mMainDict = mainDict;
mUnigramDictionaries.put(DICT_KEY_MAIN, mainDict);
@@ -133,8 +131,8 @@ public class Suggest implements Dictionary.WordCallback {
}
public void resetMainDict(Context context, int dictionaryResId, Locale locale) {
- final BinaryDictionary newMainDict = BinaryDictionary.initDictionaryFromManager(context,
- DIC_MAIN, locale, dictionaryResId);
+ final Dictionary newMainDict = DictionaryFactory.createDictionaryFromManager(
+ context, locale, dictionaryResId);
mMainDict = newMainDict;
if (null == newMainDict) {
mUnigramDictionaries.remove(DICT_KEY_MAIN);
@@ -165,7 +163,7 @@ public class Suggest implements Dictionary.WordCallback {
}
public boolean hasMainDictionary() {
- return mMainDict != null && mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD;
+ return mMainDict != null;
}
public Map<String, Dictionary> getUnigramDictionaries() {
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 9244e4560..47890e643 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -23,6 +23,7 @@ import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.inputmethodservice.InputMethodService;
import android.os.AsyncTask;
@@ -43,11 +44,13 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.Locale;
public class Utils {
private static final String TAG = Utils.class.getSimpleName();
private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4;
private static boolean DBG = LatinImeLogger.sDBG;
+ private static boolean DBG_EDIT_DISTANCE = false;
private Utils() {
// Intentional empty constructor for utility class.
@@ -289,7 +292,7 @@ public class Utils {
}
}
}
- if (LatinImeLogger.sDBG) {
+ if (DBG_EDIT_DISTANCE) {
Log.d(TAG, "editDistance:" + s + "," + t);
for (int i = 0; i < dp.length; ++i) {
StringBuffer sb = new StringBuffer();
@@ -338,6 +341,7 @@ public class Utils {
private static final int MAX_INITIAL_SCORE = 255;
private static final int TYPED_LETTER_MULTIPLIER = 2;
private static final int FULL_WORD_MULTIPLIER = 2;
+ private static final int S_INT_MAX = 2147483647;
public static double calcNormalizedScore(CharSequence before, CharSequence after, int score) {
final int beforeLength = before.length();
final int afterLength = after.length();
@@ -352,7 +356,7 @@ public class Utils {
}
}
if (spaceCount == afterLength) return 0;
- final double maximumScore = MAX_INITIAL_SCORE
+ final double maximumScore = score == S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE
* Math.pow(
TYPED_LETTER_MULTIPLIER, Math.min(beforeLength, afterLength - spaceCount))
* FULL_WORD_MULTIPLIER;
@@ -648,6 +652,14 @@ public class Utils {
/** Convert pixel to DIP */
public static int dipToPixel(float scale, int dip) {
- return (int) ((float) dip * scale + 0.5);
+ return (int) (dip * scale + 0.5);
+ }
+
+ public static Locale setSystemLocale(Resources res, Locale newLocale) {
+ final Configuration conf = res.getConfiguration();
+ final Locale saveLocale = conf.locale;
+ conf.locale = newLocale;
+ res.updateConfiguration(conf, res.getDisplayMetrics());
+ return saveLocale;
}
}