diff options
7 files changed, 185 insertions, 82 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index ebd61505d..6003d9723 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -101,7 +101,7 @@ public class Key { /** Text to output when pressed. This can be multiple characters, like ".com" */ public final CharSequence mOutputText; /** More keys */ - public final CharSequence[] mMoreKeys; + public final String[] mMoreKeys; /** More keys maximum column number */ public final int mMaxMoreKeysColumn; @@ -255,7 +255,7 @@ public class Key { // Update row to have current x coordinate. row.setXPos(keyXPos + keyWidth); - final CharSequence[] moreKeys = style.getTextArray(keyAttr, + final String[] moreKeys = style.getTextArray(keyAttr, R.styleable.Keyboard_Key_moreKeys); // In Arabic symbol layouts, we'd like to keep digits in more keys regardless of // config_digit_more_keys_enabled. diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java index 548b5ea85..974291373 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java @@ -34,7 +34,7 @@ public class MiniKeyboard extends Keyboard { } public static class Builder extends Keyboard.Builder<Builder.MiniKeyboardParams> { - private final CharSequence[] mMoreKeys; + private final String[] mMoreKeys; public static class MiniKeyboardParams extends Keyboard.Params { /* package */int mTopRowAdjustment; @@ -230,16 +230,14 @@ public class MiniKeyboard extends Keyboard { parentKey.mX + (mParams.mDefaultKeyWidth - width) / 2, view.getMeasuredWidth()); } - private static int getMaxKeyWidth(KeyboardView view, CharSequence[] moreKeys, - int minKeyWidth) { + private static int getMaxKeyWidth(KeyboardView view, String[] moreKeys, int minKeyWidth) { final int padding = (int) view.getContext().getResources() .getDimension(R.dimen.mini_keyboard_key_horizontal_padding); Paint paint = null; int maxWidth = minKeyWidth; - for (CharSequence moreKeySpec : moreKeys) { - final CharSequence label = MoreKeySpecParser.getLabel(moreKeySpec.toString()); - // If the label is single letter, minKeyWidth is enough to hold - // the label. + for (String moreKeySpec : moreKeys) { + final String label = MoreKeySpecParser.getLabel(moreKeySpec); + // If the label is single letter, minKeyWidth is enough to hold the label. if (label != null && label.length() > 1) { if (paint == null) { paint = new Paint(); @@ -258,7 +256,7 @@ public class MiniKeyboard extends Keyboard { public MiniKeyboard build() { final MiniKeyboardParams params = mParams; for (int n = 0; n < mMoreKeys.length; n++) { - final String moreKeySpec = mMoreKeys[n].toString(); + final String moreKeySpec = mMoreKeys[n]; final int row = n / params.mNumColumns; final Key key = new Key(mResources, params, moreKeySpec, params.getX(n, row), params.getY(row), params.mDefaultKeyWidth, params.mDefaultRowHeight); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java index 5dd8340fc..0f84c4563 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java @@ -37,20 +37,22 @@ public class KeyStyles { new HashMap<String, DeclaredKeyStyle>(); private static final KeyStyle EMPTY_KEY_STYLE = new EmptyKeyStyle(); + private static final char ESCAPE_CHAR = '\\'; + public interface KeyStyle { - public CharSequence[] getTextArray(TypedArray a, int index); + public String[] getTextArray(TypedArray a, int index); public CharSequence getText(TypedArray a, int index); public int getInt(TypedArray a, int index, int defaultValue); public int getFlag(TypedArray a, int index, int defaultValue); } - /* package */ static class EmptyKeyStyle implements KeyStyle { + private static class EmptyKeyStyle implements KeyStyle { EmptyKeyStyle() { // Nothing to do. } @Override - public CharSequence[] getTextArray(TypedArray a, int index) { + public String[] getTextArray(TypedArray a, int index) { return parseTextArray(a, index); } @@ -69,64 +71,66 @@ public class KeyStyles { return a.getInt(index, defaultValue); } - protected static CharSequence[] parseTextArray(TypedArray a, int index) { + protected static String[] parseTextArray(TypedArray a, int index) { if (!a.hasValue(index)) return null; final CharSequence text = a.getText(index); - return parseCsvText(text); - } - - /* package */ static CharSequence[] parseCsvText(CharSequence text) { - final int size = text.length(); - if (size == 0) return null; - if (size == 1) return new CharSequence[] { text }; - final StringBuilder sb = new StringBuilder(); - ArrayList<CharSequence> list = null; - int start = 0; - for (int pos = 0; pos < size; pos++) { - final char c = text.charAt(pos); - if (c == ',') { - if (list == null) list = new ArrayList<CharSequence>(); - if (sb.length() == 0) { - list.add(text.subSequence(start, pos)); - } else { - list.add(sb.toString()); - sb.setLength(0); - } - start = pos + 1; - continue; - } else if (c == '\\') { - if (start == pos) { - // Skip escape character at the beginning of the value. - start++; - pos++; - } else { - if (start < pos && sb.length() == 0) - sb.append(text.subSequence(start, pos)); - pos++; - if (pos < size) - sb.append(text.charAt(pos)); - } - } else if (sb.length() > 0) { - sb.append(c); + return parseCsvText(text.toString()); + } + + } + + /* package for test */ + static String[] parseCsvText(String text) { + final int size = text.length(); + if (size == 0) return null; + if (size == 1) return new String[] { text }; + final StringBuilder sb = new StringBuilder(); + ArrayList<String> list = null; + int start = 0; + for (int pos = 0; pos < size; pos++) { + final char c = text.charAt(pos); + if (c == ',') { + if (list == null) list = new ArrayList<String>(); + if (sb.length() == 0) { + list.add(text.substring(start, pos)); + } else { + list.add(sb.toString()); + sb.setLength(0); } + start = pos + 1; + continue; + } else if (c == ESCAPE_CHAR) { + if (start == pos) { + // Skip escape character at the beginning of the value. + start++; + pos++; + } else { + if (start < pos && sb.length() == 0) + sb.append(text.subSequence(start, pos)); + pos++; + if (pos < size) + sb.append(text.charAt(pos)); + } + } else if (sb.length() > 0) { + sb.append(c); } - if (list == null) { - return new CharSequence[] { sb.length() > 0 ? sb : text.subSequence(start, size) }; - } else { - list.add(sb.length() > 0 ? sb : text.subSequence(start, size)); - return list.toArray(new CharSequence[list.size()]); - } + } + if (list == null) { + return new String[] { sb.length() > 0 ? sb.toString() : text.substring(start) }; + } else { + list.add(sb.length() > 0 ? sb.toString() : text.substring(start)); + return list.toArray(new String[list.size()]); } } - /* package */ static class DeclaredKeyStyle extends EmptyKeyStyle { + private static class DeclaredKeyStyle extends EmptyKeyStyle { private final HashMap<Integer, Object> mAttributes = new HashMap<Integer, Object>(); @Override - public CharSequence[] getTextArray(TypedArray a, int index) { + public String[] getTextArray(TypedArray a, int index) { return a.hasValue(index) - ? super.getTextArray(a, index) : (CharSequence[])mAttributes.get(index); + ? super.getTextArray(a, index) : (String[])mAttributes.get(index); } @Override diff --git a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParser.java index d29a9e5ee..d4c85c33d 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParser.java @@ -41,7 +41,7 @@ import java.util.ArrayList; public class MoreKeySpecParser { private static final String TAG = MoreKeySpecParser.class.getSimpleName(); - private static final char ESCAPE = '\\'; + private static final char ESCAPE_CHAR = '\\'; private static final String LABEL_END = "|"; private static final String PREFIX_AT = "@"; private static final String PREFIX_ICON = PREFIX_AT + "icon/"; @@ -72,14 +72,14 @@ public class MoreKeySpecParser { } private static String parseEscape(String text) { - if (text.indexOf(ESCAPE) < 0) { + if (text.indexOf(ESCAPE_CHAR) < 0) { return text; } final int length = text.length(); final StringBuilder sb = new StringBuilder(); for (int pos = 0; pos < length; pos++) { final char c = text.charAt(pos); - if (c == ESCAPE && pos + 1 < length) { + if (c == ESCAPE_CHAR && pos + 1 < length) { sb.append(text.charAt(++pos)); } else { sb.append(c); @@ -89,7 +89,7 @@ public class MoreKeySpecParser { } private static int indexOfLabelEnd(String moreKeySpec, int start) { - if (moreKeySpec.indexOf(ESCAPE, start) < 0) { + if (moreKeySpec.indexOf(ESCAPE_CHAR, start) < 0) { final int end = moreKeySpec.indexOf(LABEL_END, start); if (end == 0) { throw new MoreKeySpecParserError(LABEL_END + " at " + start + ": " + moreKeySpec); @@ -99,7 +99,7 @@ public class MoreKeySpecParser { final int length = moreKeySpec.length(); for (int pos = start; pos < length; pos++) { final char c = moreKeySpec.charAt(pos); - if (c == ESCAPE && pos + 1 < length) { + if (c == ESCAPE_CHAR && pos + 1 < length) { pos++; } else if (moreKeySpec.startsWith(LABEL_END, pos)) { return pos; @@ -200,21 +200,19 @@ public class MoreKeySpecParser { } }; - public static CharSequence[] filterOut(Resources res, CharSequence[] moreKeys, - CodeFilter filter) { + public static String[] filterOut(Resources res, String[] moreKeys, CodeFilter filter) { if (moreKeys == null || moreKeys.length < 1) { return null; } - if (moreKeys.length == 1 - && filter.shouldFilterOut(getCode(res, moreKeys[0].toString()))) { + if (moreKeys.length == 1 && filter.shouldFilterOut(getCode(res, moreKeys[0]))) { return null; } - ArrayList<CharSequence> filtered = null; + ArrayList<String> filtered = null; for (int i = 0; i < moreKeys.length; i++) { - final CharSequence moreKeySpec = moreKeys[i]; - if (filter.shouldFilterOut(getCode(res, moreKeySpec.toString()))) { + final String moreKeySpec = moreKeys[i]; + if (filter.shouldFilterOut(getCode(res, moreKeySpec))) { if (filtered == null) { - filtered = new ArrayList<CharSequence>(); + filtered = new ArrayList<String>(); for (int j = 0; j < i; j++) { filtered.add(moreKeys[j]); } @@ -229,6 +227,6 @@ public class MoreKeySpecParser { if (filtered.size() == 0) { return null; } - return filtered.toArray(new CharSequence[filtered.size()]); + return filtered.toArray(new String[filtered.size()]); } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d36140de6..78e6602d8 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1881,6 +1881,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } return; } + // We need to log before we commit, because the word composer will store away the user + // typed word. + LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), + suggestion.toString(), index, suggestions.mWords); mExpectingUpdateSelection = true; commitChosenWord(suggestion, WordComposer.COMMIT_TYPE_MANUAL_PICK); // Add the word to the auto dictionary if it's not a known word @@ -1890,10 +1894,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { addToOnlyBigramDictionary(suggestion, 1); } - // TODO: the following is fishy, because it seems there may be cases where we are not - // composing a word at all. Maybe throw an exception if !mWordComposer.isComposingWord() ? - LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), - suggestion.toString(), index, suggestions.mWords); // Follow it with a space if (mInputAttributes.mInsertSpaceOnPickSuggestionManually) { sendMagicSpace(); diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java index 4050a7123..cebe40958 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java @@ -16,8 +16,6 @@ package com.android.inputmethod.keyboard.internal; -import com.android.inputmethod.keyboard.internal.KeyStyles.EmptyKeyStyle; - import android.test.AndroidTestCase; import android.text.TextUtils; @@ -26,9 +24,8 @@ public class KeyStylesTests extends AndroidTestCase { return message + " expected:<" + expected + "> but was:<" + actual + ">"; } - private static void assertTextArray(String message, CharSequence value, - CharSequence ... expected) { - final CharSequence actual[] = EmptyKeyStyle.parseCsvText(value); + private static void assertTextArray(String message, String value, String ... expected) { + final String actual[] = KeyStyles.parseCsvText(value); if (expected.length == 0) { assertNull(message, actual); return; diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java new file mode 100644 index 000000000..18afe1198 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.content.Context; +import android.content.Intent; +import android.test.ServiceTestCase; +import android.text.InputType; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.view.View; +import android.view.inputmethod.BaseInputConnection; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; +import android.widget.FrameLayout; +import android.widget.TextView; + +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardActionListener; + +public class InputLogicTests extends ServiceTestCase<LatinIME> { + + private LatinIME mLatinIME; + private TextView mTextView; + + public InputLogicTests() { + super(LatinIME.class); + } + + @Override + protected void setUp() { + try { + super.setUp(); + } catch (Exception e) { + e.printStackTrace(); + } + mTextView = new TextView(getContext()); + mTextView.setInputType(InputType.TYPE_CLASS_TEXT); + mTextView.setEnabled(true); + setupService(); + mLatinIME = getService(); + mLatinIME.onCreate(); + final EditorInfo ei = new EditorInfo(); + final InputConnection ic = mTextView.onCreateInputConnection(ei); + final LayoutInflater inflater = + (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + final ViewGroup vg = new FrameLayout(getContext()); + final View inputView = inflater.inflate(R.layout.input_view, vg); + mLatinIME.setInputView(inputView); + mLatinIME.onBindInput(); + mLatinIME.onCreateInputView(); + mLatinIME.onStartInputView(ei, false); + mLatinIME.onCreateInputMethodInterface().startInput(ic, ei); + } + + // type(int) and type(String): helper methods to send a code point resp. a string to LatinIME. + private void type(final int codePoint) { + // onPressKey and onReleaseKey are explicitly deactivated here, but they do happen in the + // code (although multitouch/slide input and other factors make the sequencing complicated). + // They are supposed to be entirely deconnected from the input logic from LatinIME point of + // view and only delegates to the parts of the code that care. So we don't include them here + // to keep these tests as pinpoint as possible and avoid bringing it too many dependencies, + // but keep them in mind if something breaks. Commenting them out as is should work. + //mLatinIME.onPressKey(codePoint); + mLatinIME.onCodeInput(codePoint, new int[] { codePoint }, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE); + //mLatinIME.onReleaseKey(codePoint, false); + } + + private void type(final String stringToType) { + for (int i = 0; i < stringToType.length(); ++i) { + type(stringToType.codePointAt(i)); + } + } + + public void testTypeWord() { + final String wordToType = "abcd"; + type(wordToType); + assertEquals("type word", wordToType, mTextView.getText().toString()); + } + + public void testPickSuggestionThenBackspace() { + final String wordToType = "tgis"; + type(wordToType); + mLatinIME.pickSuggestionManually(0, wordToType); + type(Keyboard.CODE_DELETE); + assertEquals("press suggestion then backspace", wordToType, mTextView.getText().toString()); + } + +} |