diff options
author | 2011-01-14 13:45:21 +0900 | |
---|---|---|
committer | 2011-01-14 13:45:21 +0900 | |
commit | e5585c1854f5faa3fbe3a998295c8dfdb28ed0c5 (patch) | |
tree | c2851f818c57bee621f519fe2d77fc2a4793f66f /java/src | |
parent | 93e4b45f6e5cc6fc5ea588e67a6c546378de5f6f (diff) | |
parent | 3481a5252d0b55e163ef353cb11d3cae6d093b04 (diff) | |
download | latinime-e5585c1854f5faa3fbe3a998295c8dfdb28ed0c5.tar.gz latinime-e5585c1854f5faa3fbe3a998295c8dfdb28ed0c5.tar.xz latinime-e5585c1854f5faa3fbe3a998295c8dfdb28ed0c5.zip |
Merge remote branch 'goog/master' into merge
Conflicts:
java/src/com/android/inputmethod/latin/BinaryDictionary.java
java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
Change-Id: Ib2b4acc9dd570d5f37b6aa455e2f07b0a884944a
Diffstat (limited to 'java/src')
19 files changed, 316 insertions, 304 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index af510b8b7..35bafea80 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -27,6 +27,8 @@ import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.Xml; +import java.util.ArrayList; + /** * Class for describing the position and characteristics of a single key in the keyboard. */ @@ -133,15 +135,15 @@ public class Key { }; /** - * Create an empty key with no attributes. * This constructor is being used only for key in mini popup keyboard. */ - public Key(Resources res, Row row, CharSequence popupCharacter, int x, int y) { - mKeyboard = row.getKeyboard(); - mHeight = row.mDefaultHeight - row.mVerticalGap; - mGap = row.mDefaultHorizontalGap; - mWidth = row.mDefaultWidth - mGap; - mEdgeFlags = row.mRowEdgeFlags; + public Key(Resources res, Keyboard keyboard, CharSequence popupCharacter, int x, int y, + int width, int edgeFlags) { + mKeyboard = keyboard; + mHeight = keyboard.getRowHeight() - keyboard.getVerticalGap(); + mGap = keyboard.getHorizontalGap(); + mWidth = width - mGap; + mEdgeFlags = edgeFlags; mHintIcon = null; mManualTemporaryUpperCaseHintIcon = null; mManualTemporaryUpperCaseCode = Keyboard.CODE_DUMMY; @@ -208,8 +210,13 @@ public class Key { style = keyStyles.getEmptyKeyStyle(); } - mPopupCharacters = style.getTextArray(keyAttr, + final CharSequence[] popupCharacters = style.getTextArray(keyAttr, R.styleable.Keyboard_Key_popupCharacters); + if (res.getBoolean(R.bool.config_digit_popup_characters_enabled)) { + mPopupCharacters = popupCharacters; + } else { + mPopupCharacters = filterOutDigitPopupCharacters(popupCharacters); + } mMaxPopupColumn = style.getInt(keyboardAttr, R.styleable.Keyboard_Key_maxPopupKeyboardColumn, mKeyboard.getMaxPopupKeyboardColumn()); @@ -256,6 +263,36 @@ public class Key { } } + private static boolean isDigitPopupCharacter(CharSequence label) { + return label.length() == 1 && Character.isDigit(label.charAt(0)); + } + + private static CharSequence[] filterOutDigitPopupCharacters(CharSequence[] popupCharacters) { + if (popupCharacters == null || popupCharacters.length < 1) + return null; + if (popupCharacters.length == 1 && isDigitPopupCharacter( + PopupCharactersParser.getLabel(popupCharacters[0].toString()))) + return null; + ArrayList<CharSequence> filtered = null; + for (int i = 0; i < popupCharacters.length; i++) { + final CharSequence popupSpec = popupCharacters[i]; + if (isDigitPopupCharacter(PopupCharactersParser.getLabel(popupSpec.toString()))) { + if (filtered == null) { + filtered = new ArrayList<CharSequence>(); + for (int j = 0; j < i; j++) + filtered.add(popupCharacters[j]); + } + } else if (filtered != null) { + filtered.add(popupSpec); + } + } + if (filtered == null) + return popupCharacters; + if (filtered.size() == 0) + return null; + return filtered.toArray(new CharSequence[filtered.size()]); + } + public Drawable getIcon() { return mIcon; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 777a79520..e7a9d8513 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -79,8 +79,7 @@ public abstract class KeyDetector { * * @return Allocates and returns an array that can hold all key indices returned by * {@link #getKeyIndexAndNearbyCodes} method. All elements in the returned array are - * initialized by {@link com.android.inputmethod.latin.LatinKeyboardView.NOT_A_KEY} - * value. + * initialized by {@link #NOT_A_KEY} value. */ public int[] newCodeArray() { int[] codes = new int[getMaxNearbyKeys()]; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index 848cc9693..734a55a79 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -19,64 +19,56 @@ package com.android.inputmethod.keyboard; public interface KeyboardActionListener { /** - * Called when the user presses a key. This is sent before the - * {@link #onKey} is called. For keys that repeat, this is only - * called once. + * Called when the user presses a key. This is sent before the {@link #onCodeInput} is called. + * For keys that repeat, this is only called once. * - * @param primaryCode - * the unicode of the key being pressed. If the touch is - * not on a valid key, the value will be zero. + * @param primaryCode the unicode of the key being pressed. If the touch is not on a valid key, + * the value will be zero. */ - void onPress(int primaryCode); + public void onPress(int primaryCode); /** - * Called when the user releases a key. This is sent after the - * {@link #onKey} is called. For keys that repeat, this is only - * called once. + * Called when the user releases a key. This is sent after the {@link #onCodeInput} is called. + * For keys that repeat, this is only called once. * - * @param primaryCode - * the code of the key that was released + * @param primaryCode the code of the key that was released */ - void onRelease(int primaryCode); + public void onRelease(int primaryCode); /** * Send a key code to the listener. * - * @param primaryCode - * this is the code of the key that was pressed - * @param keyCodes - * the codes for all the possible alternative keys with - * the primary code being the first. If the primary key - * code is a single character such as an alphabet or - * number or symbol, the alternatives will include other - * characters that may be on the same key or adjacent - * keys. These codes are useful to correct for - * accidental presses of a key adjacent to the intended - * key. - * @param x - * x-coordinate pixel of touched event. If onKey is not called by onTouchEvent, - * the value should be NOT_A_TOUCH_COORDINATE. - * @param y - * y-coordinate pixel of touched event. If onKey is not called by onTouchEvent, - * the value should be NOT_A_TOUCH_COORDINATE. + * @param primaryCode this is the code of the key that was pressed + * @param keyCodes the codes for all the possible alternative keys with the primary code being + * the first. If the primary key code is a single character such as an alphabet or + * number or symbol, the alternatives will include other characters that may be on + * the same key or adjacent keys. These codes are useful to correct for accidental + * presses of a key adjacent to the intended key. + * @param x x-coordinate pixel of touched event. If {@link #onCodeInput} is not called by + * {@link PointerTracker#onTouchEvent} or so, the value should be + * {@link #NOT_A_TOUCH_COORDINATE}. + * @param y y-coordinate pixel of touched event. If {@link #onCodeInput} is not called by + * {@link PointerTracker#onTouchEvent} or so, the value should be + * {@link #NOT_A_TOUCH_COORDINATE}. */ - void onCodeInput(int primaryCode, int[] keyCodes, int x, int y); + public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y); + + public static final int NOT_A_TOUCH_COORDINATE = -1; /** * Sends a sequence of characters to the listener. * - * @param text - * the sequence of characters to be displayed. + * @param text the sequence of characters to be displayed. */ - void onTextInput(CharSequence text); + public void onTextInput(CharSequence text); /** * Called when user released a finger outside any key. */ - void onCancelInput(); + public void onCancelInput(); /** * Called when the user quickly moves the finger from up to down. */ - void onSwipeDown(); + public void onSwipeDown(); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 76cb8ff29..331c8db6a 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -39,16 +39,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private static final boolean DEBUG = false; public static final boolean DEBUG_STATE = false; - // Changing DEFAULT_LAYOUT_ID also requires prefs_for_debug.xml to be matched with. - public static final String DEFAULT_LAYOUT_ID = "5"; + private static String sConfigDefaultKeyboardThemeId; public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902"; - private static final int[] THEMES = new int [] { + private static final int[] KEYBOARD_THEMES = { R.layout.input_basic, R.layout.input_basic_highcontrast, R.layout.input_stone_normal, R.layout.input_stone_bold, R.layout.input_gingerbread, - R.layout.input_honeycomb, // DEFAULT_LAYOUT_ID + R.layout.input_honeycomb, }; private SubtypeSwitcher mSubtypeSwitcher; @@ -111,8 +110,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha sInstance.mPrefs = prefs; sInstance.mSubtypeSwitcher = SubtypeSwitcher.getInstance(); - sInstance.mLayoutId = Integer.valueOf( - prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID)); + try { + sConfigDefaultKeyboardThemeId = ims.getString( + R.string.config_default_keyboard_theme_id); + sInstance.mLayoutId = Integer.valueOf( + prefs.getString(PREF_KEYBOARD_LAYOUT, sConfigDefaultKeyboardThemeId)); + } catch (NumberFormatException e) { + sConfigDefaultKeyboardThemeId = "0"; + sInstance.mLayoutId = 0; + } prefs.registerOnSharedPreferenceChangeListener(sInstance); } @@ -499,6 +505,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha mSymbolKeyState.onOtherKeyPressed(); } + 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(); + } + private void toggleShiftInSymbol() { if (isAlphabetMode()) return; @@ -557,11 +569,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha switch (mAutoModeSwitchState) { case AUTO_MODE_SWITCH_STATE_MOMENTARY: // Only distinct multi touch devices can be in this state. - // On non-distinct multi touch devices, mode change key is handled by {@link onKey}, - // not by {@link onPress} and {@link 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}. + // 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) { // Detected only the mode change key has been pressed, and then released. if (mIsSymbols) { @@ -572,6 +585,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } else if (getPointerCount() == 1) { // Snap back to the previous keyboard mode if the user pressed the mode change key // and slid to other key, then released the finger. + // If the user cancels the sliding input, snapping back to the previous keyboard + // mode is handled by {@link #onCancelInput}. changeKeyboardMode(); } else { // Chording input is being started. The keyboard mode will be snapped back to the @@ -609,8 +624,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha if (mInputView != null) { mInputView.closing(); } - if (THEMES.length <= layoutId) { - layoutId = Integer.valueOf(DEFAULT_LAYOUT_ID); + if (KEYBOARD_THEMES.length <= layoutId) { + layoutId = Integer.valueOf(sConfigDefaultKeyboardThemeId); } Utils.GCUtils.getInstance().reset(); @@ -618,7 +633,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { try { mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater( - ).inflate(THEMES[layoutId], null); + ).inflate(KEYBOARD_THEMES[layoutId], null); tryGC = false; } catch (OutOfMemoryError e) { Log.w(TAG, "load keyboard failed: " + e); @@ -651,7 +666,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (PREF_KEYBOARD_LAYOUT.equals(key)) { final int layoutId = Integer.valueOf( - sharedPreferences.getString(key, DEFAULT_LAYOUT_ID)); + sharedPreferences.getString(key, sConfigDefaultKeyboardThemeId)); createInputViewInternal(layoutId, false); postSetInputView(); } else if (Settings.PREF_SETTINGS_KEY.equals(key)) { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index dd552f0fc..e7dd716fb 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -79,8 +79,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { public static final int COLOR_SCHEME_WHITE = 0; public static final int COLOR_SCHEME_BLACK = 1; - public static final int NOT_A_TOUCH_COORDINATE = -1; - // Timing constants private final int mKeyRepeatInterval; @@ -550,7 +548,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } /** - * When enabled, calls to {@link KeyboardActionListener#onKey} will include key + * When enabled, calls to {@link KeyboardActionListener#onCodeInput} will include key * codes for adjacent keys. When disabled, only the primary key code will be * reported. * @param enabled whether or not the proximity correction is enabled @@ -694,7 +692,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Draw key label if (label != null) { // For characters, use large font. For labels like "Done", use small font. - final int labelSize = getLabelSizeAndSetPaint(label, key, paint); + final int labelSize = getLabelSizeAndSetPaint(label, key.mLabelOption, paint); final int labelCharHeight = getLabelCharHeight(labelSize, paint); // Vertical label text alignment. @@ -830,13 +828,13 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mDirtyRect.setEmpty(); } - private int getLabelSizeAndSetPaint(CharSequence label, Key key, Paint paint) { + public int getLabelSizeAndSetPaint(CharSequence label, int keyLabelOption, Paint paint) { // For characters, use large font. For labels like "Done", use small font. final int labelSize; final Typeface labelStyle; if (label.length() > 1) { labelSize = mLabelTextSize; - if ((key.mLabelOption & KEY_LABEL_OPTION_FONT_NORMAL) != 0) { + if ((keyLabelOption & KEY_LABEL_OPTION_FONT_NORMAL) != 0) { labelStyle = Typeface.DEFAULT; } else { labelStyle = Typeface.DEFAULT_BOLD; @@ -1106,6 +1104,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { @Override public void onCancelInput() { + mKeyboardActionListener.onCancelInput(); dismissPopupKeyboard(); } @@ -1127,7 +1126,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Remove gesture detector on mini-keyboard miniKeyboard.mGestureDetector = null; - Keyboard keyboard = new MiniKeyboardBuilder(getContext(), popupKeyboardResId, popupKey) + Keyboard keyboard = new MiniKeyboardBuilder(this, popupKeyboardResId, popupKey) .build(); miniKeyboard.setKeyboard(keyboard); miniKeyboard.setPopupParent(this); diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java index 7b079e38e..77dde8d1b 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java @@ -48,7 +48,7 @@ public class LatinKeyboard extends Keyboard { private final Drawable mButtonArrowLeftIcon; private final Drawable mButtonArrowRightIcon; private final int mSpaceBarTextShadowColor; - private int mSpaceKeyIndex = -1; + private final int[] mSpaceKeyIndexArray; private int mSpaceDragStartX; private int mSpaceDragLastDiff; private final Context mContext; @@ -92,7 +92,8 @@ public class LatinKeyboard extends Keyboard { mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right); sSpacebarVerticalCorrection = res.getDimensionPixelOffset( R.dimen.spacebar_vertical_correction); - mSpaceKeyIndex = indexOf(CODE_SPACE); + // The index of space key is available only after Keyboard constructor has finished. + mSpaceKeyIndexArray = new int[] { indexOf(CODE_SPACE) }; } /** @@ -173,7 +174,7 @@ public class LatinKeyboard extends Keyboard { @SuppressWarnings("unused") private Bitmap drawSpaceBar(int opacity, boolean isAutoCorrection) { final int width = mSpaceKey.mWidth; - final int height = mSpaceIcon.getIntrinsicHeight(); + final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight; final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(buffer); final Resources res = mContext.getResources(); @@ -230,7 +231,7 @@ public class LatinKeyboard extends Keyboard { int y = height - iconHeight; mSpaceAutoCorrectionIndicator.setBounds(x, y, x + iconWidth, y + iconHeight); mSpaceAutoCorrectionIndicator.draw(canvas); - } else { + } else if (mSpaceIcon != null) { final int iconWidth = mSpaceIcon.getIntrinsicWidth(); final int iconHeight = mSpaceIcon.getIntrinsicHeight(); int x = (width - iconWidth) / 2; @@ -418,7 +419,7 @@ public class LatinKeyboard extends Keyboard { @Override public int[] getNearestKeys(int x, int y) { if (mCurrentlyInSpace) { - return new int[] { mSpaceKeyIndex }; + return mSpaceKeyIndexArray; } else { // Avoid dead pixels at edges of the keyboard return super.getNearestKeys(Math.max(0, Math.min(x, getMinWidth() - 1)), diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index cb3b430d5..51bfbf1f9 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -62,13 +62,18 @@ public class LatinKeyboardView extends KeyboardView { } } - public void setLatinKeyboard(LatinKeyboard k) { - super.setKeyboard(k); + public void setLatinKeyboard(LatinKeyboard newKeyboard) { + final LatinKeyboard oldKeyboard = getLatinKeyboard(); + if (oldKeyboard != null) { + // Reset old keyboard state before switching to new keyboard. + oldKeyboard.keyReleased(); + } + super.setKeyboard(newKeyboard); // One-seventh of the keyboard width seems like a reasonable threshold - mJumpThresholdSquare = k.getMinWidth() / 7; + mJumpThresholdSquare = newKeyboard.getMinWidth() / 7; mJumpThresholdSquare *= mJumpThresholdSquare; // Assuming there are 4 rows, this is the coordinate of the last row - mLastRowY = (k.getHeight() * 3) / 4; + mLastRowY = (newKeyboard.getHeight() * 3) / 4; } public LatinKeyboard getLatinKeyboard() { @@ -95,8 +100,8 @@ public class LatinKeyboardView extends KeyboardView { private boolean invokeOnKey(int primaryCode) { getOnKeyboardActionListener().onCodeInput(primaryCode, null, - KeyboardView.NOT_A_TOUCH_COORDINATE, - KeyboardView.NOT_A_TOUCH_COORDINATE); + KeyboardActionListener.NOT_A_TOUCH_COORDINATE, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE); return true; } diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java index 1eb0c3f37..458a9eed4 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java @@ -16,8 +16,12 @@ package com.android.inputmethod.keyboard; +import com.android.inputmethod.latin.R; + import android.content.Context; import android.content.res.Resources; +import android.graphics.Paint; +import android.graphics.Rect; import java.util.List; @@ -25,45 +29,74 @@ public class MiniKeyboardBuilder { private final Resources mRes; private final Keyboard mKeyboard; private final CharSequence[] mPopupCharacters; + private final int mMiniKeyboardKeyHorizontalPadding; + private final int mKeyWidth; private final int mMaxColumns; private final int mNumRows; private int mColPos; private int mRowPos; - private Row mRow; private int mX; private int mY; - public MiniKeyboardBuilder(Context context, int layoutTemplateResId, Key popupKey) { + public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key popupKey) { + final Context context = view.getContext(); mRes = context.getResources(); - mKeyboard = new Keyboard(context, layoutTemplateResId, null); + final Keyboard keyboard = new Keyboard(context, layoutTemplateResId, null); + mKeyboard = keyboard; mPopupCharacters = popupKey.mPopupCharacters; - final int numKeys = mPopupCharacters.length; + mMiniKeyboardKeyHorizontalPadding = (int)mRes.getDimension( + R.dimen.mini_keyboard_key_horizontal_padding); + mKeyWidth = getMaxKeyWidth(view, mPopupCharacters, mKeyboard.getKeyWidth()); final int maxColumns = popupKey.mMaxPopupColumn; + mMaxColumns = maxColumns; + final int numKeys = mPopupCharacters.length; int numRows = numKeys / maxColumns; if (numKeys % maxColumns != 0) numRows++; - mMaxColumns = maxColumns; mNumRows = numRows; - // TODO: To determine key width we should pay attention to key label length. - mRow = new Row(mKeyboard, getRowFlags()); + keyboard.setHeight((keyboard.getRowHeight() + keyboard.getVerticalGap()) * numRows + - keyboard.getVerticalGap()); if (numRows > 1) { mColPos = numKeys % maxColumns; if (mColPos > 0) mColPos = maxColumns - mColPos; // Centering top-row keys. - mX = mColPos * (mRow.mDefaultWidth + mRow.mDefaultHorizontalGap) / 2; + mX = mColPos * (mKeyWidth + keyboard.getHorizontalGap()) / 2; } mKeyboard.setMinWidth(0); } + private int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters, int minKeyWidth) { + Paint paint = null; + Rect bounds = null; + int maxWidth = 0; + for (CharSequence popupSpec : popupCharacters) { + final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString()); + // If the label is single letter, minKeyWidth is enough to hold the label. + if (label.length() > 1) { + if (paint == null) { + paint = new Paint(); + paint.setAntiAlias(true); + } + final int labelSize = view.getLabelSizeAndSetPaint(label, 0, paint); + paint.setTextSize(labelSize); + if (bounds == null) bounds = new Rect(); + paint.getTextBounds(label.toString(), 0, label.length(), bounds); + if (maxWidth < bounds.width()) + maxWidth = bounds.width(); + } + } + return Math.max(minKeyWidth, maxWidth + mMiniKeyboardKeyHorizontalPadding); + } + public Keyboard build() { - List<Key> keys = mKeyboard.getKeys(); + final Keyboard keyboard = mKeyboard; + final List<Key> keys = keyboard.getKeys(); for (CharSequence label : mPopupCharacters) { refresh(); - final Key key = new Key(mRes, mRow, label, mX, mY); + final Key key = new Key(mRes, keyboard, label, mX, mY, mKeyWidth, getRowFlags()); keys.add(key); advance(); } - finish(); - return mKeyboard; + return keyboard; } private int getRowFlags() { @@ -76,29 +109,21 @@ public class MiniKeyboardBuilder { private void refresh() { if (mColPos >= mMaxColumns) { - final Row row = mRow; + final Keyboard keyboard = mKeyboard; // TODO: Allocate key position depending the precedence of popup characters. mX = 0; - mY += row.mDefaultHeight + row.mVerticalGap; + mY += keyboard.getRowHeight() + keyboard.getVerticalGap(); mColPos = 0; - // TODO: To determine key width we should pay attention to key label length from - // bottom to up for rows. - mRow = new Row(mKeyboard, getRowFlags()); mRowPos++; } } private void advance() { - final Row row = mRow; final Keyboard keyboard = mKeyboard; // TODO: Allocate key position depending the precedence of popup characters. - mX += row.mDefaultWidth + row.mDefaultHorizontalGap; + mX += mKeyWidth + keyboard.getHorizontalGap(); if (mX > keyboard.getMinWidth()) keyboard.setMinWidth(mX); mColPos++; } - - private void finish() { - mKeyboard.setHeight(mY + mRow.mDefaultHeight); - } -}
\ No newline at end of file +} diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index c07035d62..49f29f923 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -65,6 +65,9 @@ public class PointerTracker { private final PointerTrackerKeyState mKeyState; + // true if keyboard layout has been changed. + private boolean mKeyboardLayoutHasBeenChanged; + // true if event is already translated to a key action (long press or mini-keyboard) private boolean mKeyAlreadyProcessed; @@ -122,10 +125,14 @@ public class PointerTracker { mListener = listener; } - private void callListenerOnPress(int primaryCode) { + // Returns true if keyboard has been changed by this callback. + private boolean callListenerOnPressAndCheckKeyboardLayoutChange(int primaryCode) { if (DEBUG_LISTENER) Log.d(TAG, "onPress : " + keyCodePrintable(primaryCode)); mListener.onPress(primaryCode); + final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; + mKeyboardLayoutHasBeenChanged = false; + return keyboardLayoutHasBeenChanged; } private void callListenerOnCodeInput(int primaryCode, int[] keyCodes, int x, int y) { @@ -159,8 +166,8 @@ public class PointerTracker { mKeyboard = keyboard; mKeys = keys; mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance); - // Update current key index because keyboard layout has been changed. - mKeyState.onSetKeyboard(); + // Mark that keyboard layout has been changed. + mKeyboardLayoutHasBeenChanged = true; } public boolean isInSlidingKeyInput() { @@ -296,14 +303,16 @@ public class PointerTracker { // from modifier key, or 3) this pointer is on mini-keyboard. mIsAllowedSlidingKeyInput = mConfigSlidingKeyInputEnabled || isModifierInternal(keyIndex) || mKeyDetector instanceof MiniKeyboardKeyDetector; + mKeyboardLayoutHasBeenChanged = false; mKeyAlreadyProcessed = false; mIsRepeatableKey = false; mIsInSlidingKeyInput = false; if (isValidKeyIndex(keyIndex)) { - callListenerOnPress(mKeys[keyIndex].mCode); - // This onPress call may have changed keyboard layout and have updated mKeyIndex. - // If that's the case, mKeyIndex has been updated in setKeyboard(). - keyIndex = mKeyState.getKeyIndex(); + // This onPress call may have changed keyboard layout. Those cases are detected at + // {@link #setKeyboard}. In those cases, we should update keyIndex according to the new + // keyboard layout. + if (callListenerOnPressAndCheckKeyboardLayoutChange(mKeys[keyIndex].mCode)) + keyIndex = mKeyState.onDownKey(x, y, eventTime); } if (isValidKeyIndex(keyIndex)) { if (mKeys[keyIndex].mRepeatable) { @@ -327,13 +336,17 @@ public class PointerTracker { // TODO: down-to-up filter, if (eventTime-downTime) is less than threshold, just ignore // this move event. Otherwise fire {@link onDownEventInternal} and continue. - final int keyIndex = keyState.onMoveKey(x, y); + int keyIndex = keyState.onMoveKey(x, y); final Key oldKey = getKey(keyState.getKeyIndex()); if (isValidKeyIndex(keyIndex)) { if (oldKey == null) { // The pointer has been slid in to the new key, but the finger was not on any keys. // In this case, we must call onPress() to notify that the new key is being pressed. - callListenerOnPress(getKey(keyIndex).mCode); + // This onPress call may have changed keyboard layout. Those cases are detected at + // {@link #setKeyboard}. In those cases, we should update keyIndex according to the + // new keyboard layout. + if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex).mCode)) + keyIndex = keyState.onMoveKey(x, y); keyState.onMoveToNewKey(keyIndex, x, y); startLongPressTimer(keyIndex); } else if (!isMinorMoveBounce(x, y, keyIndex)) { @@ -344,7 +357,11 @@ public class PointerTracker { callListenerOnRelease(oldKey.mCode); mHandler.cancelLongPressTimers(); if (mIsAllowedSlidingKeyInput) { - callListenerOnPress(getKey(keyIndex).mCode); + // This onPress call may have changed keyboard layout. Those cases are detected + // at {@link #setKeyboard}. In those cases, we should update keyIndex according + // to the new keyboard layout. + if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex).mCode)) + keyIndex = keyState.onMoveKey(x, y); keyState.onMoveToNewKey(keyIndex, x, y); startLongPressTimer(keyIndex); } else { @@ -509,7 +526,7 @@ public class PointerTracker { return; } else if (mKeyboardSwitcher.isInMomentaryAutoModeSwitchState()) { // We use longer timeout for sliding finger input started from the symbols mode key. - mHandler.startLongPressTimer(mLongPressKeyTimeout * 2, keyIndex, this); + mHandler.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this); } else { mHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this); } diff --git a/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java b/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java index 8b969c70a..250bb95eb 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java @@ -106,8 +106,4 @@ package com.android.inputmethod.keyboard; mUpTime = eventTime; return onMoveKeyInternal(x, y); } - - public void onSetKeyboard() { - mKeyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(mKeyX, mKeyY, null); - } } diff --git a/java/src/com/android/inputmethod/keyboard/Row.java b/java/src/com/android/inputmethod/keyboard/Row.java index 198f02ca8..3618c0448 100644 --- a/java/src/com/android/inputmethod/keyboard/Row.java +++ b/java/src/com/android/inputmethod/keyboard/Row.java @@ -45,15 +45,6 @@ public class Row { private final Keyboard mKeyboard; - public Row(Keyboard keyboard, int rowFlags) { - this.mKeyboard = keyboard; - mDefaultHeight = keyboard.getRowHeight(); - mDefaultWidth = keyboard.getKeyWidth(); - mDefaultHorizontalGap = keyboard.getHorizontalGap(); - mVerticalGap = keyboard.getVerticalGap(); - mRowEdgeFlags = rowFlags; - } - public Row(Resources res, Keyboard keyboard, XmlResourceParser parser) { this.mKeyboard = keyboard; final int keyboardWidth = keyboard.getDisplayWidth(); diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 7ee0d77e5..af08742d3 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2008 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 @@ -17,13 +17,9 @@ package com.android.inputmethod.latin; import android.content.Context; +import android.content.res.AssetFileDescriptor; import android.util.Log; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.Channels; import java.util.Arrays; /** @@ -48,21 +44,18 @@ public class BinaryDictionary extends Dictionary { private int mDicTypeId; private int mNativeDict; - private int mDictLength; + private long mDictLength; private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES]; private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS]; private final int[] mFrequencies = new int[MAX_WORDS]; private final int[] mFrequencies_bigrams = new int[MAX_BIGRAMS]; - // Keep a reference to the native dict direct buffer in Java to avoid - // unexpected deallocation of the direct buffer. - private ByteBuffer mNativeDictDirectBuffer; static { try { System.loadLibrary("jni_latinime2"); } catch (UnsatisfiedLinkError ule) { - Log.e("BinaryDictionary", "Could not load native library jni_latinime2"); + Log.e(TAG, "Could not load native library jni_latinime"); } } @@ -71,91 +64,46 @@ public class BinaryDictionary extends Dictionary { * @param context application context for reading resources * @param resId the resource containing the raw binary dictionary */ - public BinaryDictionary(Context context, int[] resId, int dicTypeId) { - if (resId != null && resId.length > 0 && resId[0] != 0) { + public BinaryDictionary(Context context, int resId, int dicTypeId) { + if (resId != 0) { loadDictionary(context, resId); } mDicTypeId = dicTypeId; } - /** - * Create a dictionary from a byte buffer. This is used for testing. - * @param context application context for reading resources - * @param byteBuffer a ByteBuffer containing the binary dictionary - */ - public BinaryDictionary(Context context, ByteBuffer byteBuffer, int dicTypeId) { - if (byteBuffer != null) { - if (byteBuffer.isDirect()) { - mNativeDictDirectBuffer = byteBuffer; - } else { - mNativeDictDirectBuffer = ByteBuffer.allocateDirect(byteBuffer.capacity()); - byteBuffer.rewind(); - mNativeDictDirectBuffer.put(byteBuffer); - } - mDictLength = byteBuffer.capacity(); - mNativeDict = openNative(mNativeDictDirectBuffer, - TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER, - MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES); - } - mDicTypeId = dicTypeId; - } - - private native int openNative(ByteBuffer bb, int typedLetterMultiplier, - int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives); + private native int openNative(String sourceDir, long dictOffset, long dictSize, + int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, + int maxWords, int maxAlternatives); private native void closeNative(int dict); private native boolean isValidWordNative(int nativeData, char[] word, int wordLength); - private native int getSuggestionsNative(int dict, int[] inputCodes, int codesSize, + private native int getSuggestionsNative(int dict, int[] inputCodes, int codesSize, char[] outputChars, int[] frequencies, int[] nextLettersFrequencies, int nextLettersSize); private native int getBigramsNative(int dict, char[] prevWord, int prevWordLength, int[] inputCodes, int inputCodesLength, char[] outputChars, int[] frequencies, int maxWordLength, int maxBigrams, int maxAlternatives); - private final void loadDictionary(Context context, int[] resId) { - InputStream[] is = null; + private final void loadDictionary(Context context, int resId) { try { - // merging separated dictionary into one if dictionary is separated - int total = 0; - is = new InputStream[resId.length]; - for (int i = 0; i < resId.length; i++) { - is[i] = context.getResources().openRawResource(resId[i]); - total += is[i].available(); - } - - mNativeDictDirectBuffer = - ByteBuffer.allocateDirect(total).order(ByteOrder.nativeOrder()); - int got = 0; - for (int i = 0; i < resId.length; i++) { - got += Channels.newChannel(is[i]).read(mNativeDictDirectBuffer); - } - if (got != total) { - Log.e(TAG, "Read " + got + " bytes, expected " + total); - } else { - mNativeDict = openNative(mNativeDictDirectBuffer, - TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER, - MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES); - mDictLength = total; - } - } catch (IOException e) { - Log.w(TAG, "No available memory for binary dictionary"); - } finally { - try { - if (is != null) { - for (int i = 0; i < is.length; i++) { - is[i].close(); - } - } - } catch (IOException e) { - Log.w(TAG, "Failed to close input stream"); + final AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId); + if (afd == null) { + Log.e(TAG, "Found the resource but it is compressed. resId=" + resId); + return; } + mNativeDict = openNative(context.getApplicationInfo().sourceDir, + afd.getStartOffset(), afd.getLength(), + TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER, + MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES); + mDictLength = afd.getLength(); + } catch (android.content.res.Resources.NotFoundException e) { + Log.e(TAG, "Could not find the resource. resId=" + resId); + return; } } - @Override public void getBigrams(final WordComposer codes, final CharSequence previousWord, final WordCallback callback, int[] nextLettersFrequencies) { - char[] chars = previousWord.toString().toCharArray(); Arrays.fill(mOutputChars_bigrams, (char) 0); Arrays.fill(mFrequencies_bigrams, 0); @@ -225,8 +173,8 @@ public class BinaryDictionary extends Dictionary { return isValidWordNative(mNativeDict, chars, chars.length); } - public int getSize() { - return mDictLength; // This value is initialized on the call to openNative() + public long getSize() { + return mDictLength; // This value is initialized in loadDictionary() } @Override @@ -234,6 +182,7 @@ public class BinaryDictionary extends Dictionary { if (mNativeDict != 0) { closeNative(mNativeDict); mNativeDict = 0; + mDictLength = 0; } } diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index bc08df042..0fc86c335 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -146,7 +146,7 @@ public class ExpandableDictionary extends Dictionary { public Context getContext() { return mContext; } - + public int getMaxWordLength() { return MAX_WORD_LENGTH; } @@ -158,6 +158,7 @@ public class ExpandableDictionary extends Dictionary { private void addWordRec(NodeArray children, final String word, final int depth, final int frequency, Node parentNode) { final int wordLength = word.length(); + if (wordLength <= depth) return; final char c = word.charAt(depth); // Does children have the current character? final int childrenLength = children.mLength; diff --git a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java index 27e0fbe4a..faee38eda 100644 --- a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java +++ b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java @@ -99,15 +99,15 @@ public class InputLanguageSelection extends PreferenceActivity { } private boolean hasDictionary(Locale locale) { - Resources res = getResources(); - Configuration conf = res.getConfiguration(); - Locale saveLocale = conf.locale; + final Resources res = getResources(); + final Configuration conf = res.getConfiguration(); + final Locale saveLocale = conf.locale; boolean haveDictionary = false; conf.locale = locale; res.updateConfiguration(conf, res.getDisplayMetrics()); - int[] dictionaries = LatinIME.getDictionary(res); - BinaryDictionary bd = new BinaryDictionary(this, dictionaries, Suggest.DIC_MAIN); + int mainDicResId = LatinIME.getMainDictionaryResourceId(res); + BinaryDictionary bd = new BinaryDictionary(this, mainDicResId, Suggest.DIC_MAIN); // Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of // 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words. diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index c44410449..88261b60e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -347,49 +347,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } /** - * Loads a dictionary or multiple separated dictionary - * @return returns array of dictionary resource ids + * Returns a main dictionary resource id + * @return main dictionary resource id */ - public static int[] getDictionary(Resources res) { + public static int getMainDictionaryResourceId(Resources res) { + final String MAIN_DIC_NAME = "main"; String packageName = LatinIME.class.getPackage().getName(); - XmlResourceParser xrp = res.getXml(R.xml.dictionary); - ArrayList<Integer> dictionaries = new ArrayList<Integer>(); - - try { - int current = xrp.getEventType(); - while (current != XmlPullParser.END_DOCUMENT) { - if (current == XmlPullParser.START_TAG) { - String tag = xrp.getName(); - if (tag != null) { - if (tag.equals("part")) { - String dictFileName = xrp.getAttributeValue(null, "name"); - dictionaries.add(res.getIdentifier(dictFileName, "raw", packageName)); - } - } - } - xrp.next(); - current = xrp.getEventType(); - } - } catch (XmlPullParserException e) { - Log.e(TAG, "Dictionary XML parsing failure"); - } catch (IOException e) { - Log.e(TAG, "Dictionary XML IOException"); - } - - int count = dictionaries.size(); - int[] dict = new int[count]; - for (int i = 0; i < count; i++) { - dict[i] = dictionaries.get(i); - } - - return dict; + return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName); } private void initSuggest() { updateAutoTextEnabled(); String locale = mSubtypeSwitcher.getInputLocaleStr(); - Resources orig = getResources(); Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(new Locale(locale)); if (mSuggest != null) { mSuggest.close(); @@ -397,40 +367,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final SharedPreferences prefs = mPrefs; mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true); - int[] dictionaries = getDictionary(orig); - mSuggest = new Suggest(this, dictionaries); + final Resources res = mResources; + int mainDicResId = getMainDictionaryResourceId(res); + mSuggest = new Suggest(this, mainDicResId); loadAndSetAutoCorrectionThreshold(prefs); - if (mUserDictionary != null) mUserDictionary.close(); + mUserDictionary = new UserDictionary(this, locale); - if (mContactsDictionary == null) { - mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS); - } - if (mAutoDictionary != null) { - mAutoDictionary.close(); - } - mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO); - if (mUserBigramDictionary != null) { - mUserBigramDictionary.close(); - } - mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER); - mSuggest.setUserBigramDictionary(mUserBigramDictionary); mSuggest.setUserDictionary(mUserDictionary); + + mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS); mSuggest.setContactsDictionary(mContactsDictionary); + + mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO); mSuggest.setAutoDictionary(mAutoDictionary); + + mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER); + mSuggest.setUserBigramDictionary(mUserBigramDictionary); + updateCorrectionMode(); - mWordSeparators = mResources.getString(R.string.word_separators); - mSentenceSeparators = mResources.getString(R.string.sentence_separators); + mWordSeparators = res.getString(R.string.word_separators); + mSentenceSeparators = res.getString(R.string.sentence_separators); mSubtypeSwitcher.changeSystemLocale(savedLocale); } @Override public void onDestroy() { - if (mUserDictionary != null) { - mUserDictionary.close(); - } - if (mContactsDictionary != null) { - mContactsDictionary.close(); + if (mSuggest != null) { + mSuggest.close(); + mSuggest = null; } unregisterReceiver(mReceiver); mVoiceConnector.destroy(); @@ -811,11 +776,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) { if (DEBUG) { - Log.i("foo", "Received completions:"); + Log.i(TAG, "Received completions:"); final int count = (applicationSpecifiedCompletions != null) ? applicationSpecifiedCompletions.length : 0; for (int i = 0; i < count; i++) { - Log.i("foo", " #" + i + ": " + applicationSpecifiedCompletions[i]); + Log.i(TAG, " #" + i + ": " + applicationSpecifiedCompletions[i]); } } if (mApplicationSpecifiedCompletionOn) { @@ -859,10 +824,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public boolean onEvaluateFullscreenMode() { - DisplayMetrics dm = getResources().getDisplayMetrics(); + final Resources res = mResources; + DisplayMetrics dm = res.getDisplayMetrics(); float displayHeight = dm.heightPixels; // If the display is more than X inches high, don't go to fullscreen mode - float dimen = getResources().getDimension(R.dimen.max_height_for_fullscreen); + float dimen = res.getDimension(R.dimen.max_height_for_fullscreen); if (displayHeight > dimen) { return false; } else { @@ -1048,8 +1014,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return mOptionsDialog != null && mOptionsDialog.isShowing(); } - // Implementation of KeyboardViewListener - + // Implementation of {@link KeyboardActionListener}. @Override public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { long when = SystemClock.uptimeMillis(); @@ -1132,7 +1097,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen ic.commitText(text, 1); ic.endBatchEdit(); mKeyboardSwitcher.updateShiftState(); - mKeyboardSwitcher.onKey(0); // dummy key code. + mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY); mJustReverted = false; mJustAddedAutoSpace = false; mEnteredText = text; @@ -1141,6 +1106,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void onCancelInput() { // User released a finger outside any key + mKeyboardSwitcher.onCancelInput(); } private void handleBackspace() { @@ -1486,7 +1452,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } private void showSuggestions(WordComposer word) { - // long startTime = System.currentTimeMillis(); // TIME MEASUREMENT! // TODO Maybe need better way of retrieving previous word CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(), mWordSeparators); @@ -1498,9 +1463,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted && mSuggest.hasMinimalCorrection(); - CharSequence typedWord = word.getTypedWord(); + final CharSequence typedWord = word.getTypedWord(); // If we're in basic correct - boolean typedWordValid = mSuggest.isValidWord(typedWord) || + final boolean typedWordValid = mSuggest.isValidWord(typedWord) || (preferCapitalization() && mSuggest.isValidWord(typedWord.toString().toLowerCase())); if (mCorrectionMode == Suggest.CORRECTION_FULL @@ -1511,7 +1476,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen correctionAvailable &= !word.isMostlyCaps(); correctionAvailable &= !TextEntryState.isCorrecting(); - if (builder.size() > 1 || mCandidateView.isShowingAddToDictionaryHint()) { + // Basically, we update the suggestion strip only when suggestion count > 1. However, + // there is an exception: We update the suggestion strip whenever typed word's length + // is 1, regardless of suggestion count. Actually, in most cases, suggestion count is 1 + // when typed word's length is 1, but we do always need to clear the previous state when + // the user starts typing a word (i.e. typed word's length == 1). + if (typedWord.length() == 1 || builder.size() > 1 + || mCandidateView.isShowingAddToDictionaryHint()) { builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable); } else { final SuggestedWords previousSuggestions = mCandidateView.getSuggestions(); @@ -1588,8 +1559,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen LatinImeLogger.logOnManualSuggestion( "", suggestion.toString(), index, suggestions.mWords); final char primaryCode = suggestion.charAt(0); - onCodeInput(primaryCode, new int[]{primaryCode}, KeyboardView.NOT_A_TOUCH_COORDINATE, - KeyboardView.NOT_A_TOUCH_COORDINATE); + onCodeInput(primaryCode, new int[] { primaryCode }, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE); if (ic != null) { ic.endBatchEdit(); } @@ -1841,7 +1813,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void sendSpace() { sendKeyChar((char)Keyboard.CODE_SPACE); mKeyboardSwitcher.updateShiftState(); - //onKey(KEY_SPACE[0], KEY_SPACE); } public boolean preferCapitalization() { @@ -1879,7 +1850,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else if (Settings.PREF_RECORRECTION_ENABLED.equals(key)) { mReCorrectionEnabled = sharedPreferences.getBoolean( Settings.PREF_RECORRECTION_ENABLED, - getResources().getBoolean(R.bool.default_recorrection_enabled)); + mResources.getBoolean(R.bool.default_recorrection_enabled)); } } @@ -2011,11 +1982,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } private void updateSuggestionVisibility(SharedPreferences prefs) { + final Resources res = mResources; final String suggestionVisiblityStr = prefs.getString( Settings.PREF_SHOW_SUGGESTIONS_SETTING, - mResources.getString(R.string.prefs_suggestion_visibility_default_value)); + res.getString(R.string.prefs_suggestion_visibility_default_value)); for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) { - if (suggestionVisiblityStr.equals(mResources.getString(visibility))) { + if (suggestionVisiblityStr.equals(res.getString(visibility))) { mSuggestionVisibility = visibility; break; } diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index de194d21b..aaecfffdd 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -72,6 +72,6 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public static void onSetKeyboard(Keyboard kb) { } - public static void onPrintAllUsabilityStudtyLogs() { + public static void onPrintAllUsabilityStudyLogs() { } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 3539f9fa6..8d45d5b38 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -42,6 +42,7 @@ import java.util.Locale; import java.util.Map; public class SubtypeSwitcher { + // TODO: This should be configurable by resource // This flag indicates if we support language switching by swipe on space bar. // We may or may not draw the current language on space bar regardless of this flag. // @@@ @@ -105,6 +106,7 @@ public class SubtypeSwitcher { mSystemLocale = null; mInputLocale = null; mInputLocaleStr = null; + // Mode is initialized to KEYBOARD_MODE, in case that LatinIME can't obtain currentSubtype mMode = KEYBOARD_MODE; mAllEnabledSubtypesOfCurrentInputMethod = null; // TODO: Voice input should be created here diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 236590284..9ea9c2f3e 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2008 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 @@ -22,12 +22,11 @@ import android.text.TextUtils; import android.util.Log; import android.view.View; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; /** - * This class loads a dictionary and provides a list of suggestions for a given sequence of + * 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 { @@ -103,16 +102,11 @@ public class Suggest implements Dictionary.WordCallback { private int mCorrectionMode = CORRECTION_BASIC; - public Suggest(Context context, int[] dictionaryResId) { + public Suggest(Context context, int dictionaryResId) { mMainDict = new BinaryDictionary(context, dictionaryResId, DIC_MAIN); initPool(); } - public Suggest(Context context, ByteBuffer byteBuffer) { - mMainDict = new BinaryDictionary(context, byteBuffer, DIC_MAIN); - initPool(); - } - private void initPool() { for (int i = 0; i < mPrefMaxSuggestions; i++) { StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); @@ -154,7 +148,7 @@ public class Suggest implements Dictionary.WordCallback { public void setContactsDictionary(Dictionary userDictionary) { mContactsDictionary = userDictionary; } - + public void setAutoDictionary(Dictionary autoDictionary) { mAutoDictionary = autoDictionary; } @@ -232,7 +226,7 @@ public class Suggest implements Dictionary.WordCallback { if (!TextUtils.isEmpty(prevWordForBigram)) { CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); - if (mMainDict.isValidWord(lowerPrevWord)) { + if (mMainDict != null && mMainDict.isValidWord(lowerPrevWord)) { prevWordForBigram = lowerPrevWord; } if (mUserBigramDictionary != null) { @@ -383,7 +377,7 @@ public class Suggest implements Dictionary.WordCallback { return mHaveCorrection; } - private boolean compareCaseInsensitive(final String mLowerOriginalWord, + private boolean compareCaseInsensitive(final String mLowerOriginalWord, final char[] word, final int offset, final int length) { final int originalLength = mLowerOriginalWord.length(); if (originalLength == length && Character.isUpperCase(word[offset])) { @@ -456,7 +450,7 @@ public class Suggest implements Dictionary.WordCallback { System.arraycopy(priorities, pos, priorities, pos + 1, prefMaxSuggestions - pos - 1); priorities[pos] = freq; int poolSize = mStringPool.size(); - StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1) + StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1) : new StringBuilder(getApproxMaxWordLength()); sb.setLength(0); if (mIsAllUpperCase) { @@ -510,7 +504,7 @@ public class Suggest implements Dictionary.WordCallback { || (mAutoDictionary != null && mAutoDictionary.isValidWord(word)) || (mContactsDictionary != null && mContactsDictionary.isValidWord(word)); } - + private void collectGarbage(ArrayList<CharSequence> suggestions, int prefMaxSuggestions) { int poolSize = mStringPool.size(); int garbageSize = suggestions.size(); @@ -531,6 +525,23 @@ public class Suggest implements Dictionary.WordCallback { public void close() { if (mMainDict != null) { mMainDict.close(); + mMainDict = null; + } + if (mUserDictionary != null) { + mUserDictionary.close(); + mUserDictionary = null; + } + if (mUserBigramDictionary != null) { + mUserBigramDictionary.close(); + mUserBigramDictionary = null; + } + if (mContactsDictionary != null) { + mContactsDictionary.close(); + mContactsDictionary = null; + } + if (mAutoDictionary != null) { + mAutoDictionary.close(); + mAutoDictionary = null; } } } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 0e0cba9b3..56ad6c7aa 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -307,7 +307,7 @@ public class Utils { break; } UsabilityStudyLogUtils.getInstance().write(inputChar + "\t" + x + "\t" + y); - LatinImeLogger.onPrintAllUsabilityStudtyLogs(); + LatinImeLogger.onPrintAllUsabilityStudyLogs(); } public void write(final String log) { |