From 65e4970026fd0e7964796c0e252b6d71632b634c Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Tue, 18 Sep 2012 14:06:12 +0900 Subject: Fix hackCanUseDictionaryFile. Bug: 7169473 Change-Id: I575aaa350042af076a8da5756993cdae9e73422c --- java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 9a888ade4..487315c0e 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -28,6 +28,7 @@ import android.util.Log; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; @@ -382,6 +383,8 @@ class BinaryDictionaryGetter { return false; } catch (NumberFormatException e) { return false; + } catch (BufferUnderflowException e) { + return false; } finally { if (inStream != null) { try { -- cgit v1.2.3-83-g751a From 8adc0154e6a1412e8b2a7ba5b2a67650062e0dbf Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Fri, 14 Sep 2012 12:07:39 +0900 Subject: Remove populateOptions(final ByteBuffer buffer). Change-Id: Ifc4c64c9cffe4f343c5a604c192db010a1792acc --- .../android/inputmethod/latin/BinaryDictionaryGetter.java | 12 ++++++------ .../inputmethod/latin/makedict/BinaryDictInputOutput.java | 5 ----- 2 files changed, 6 insertions(+), 11 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 487315c0e..9764df072 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -29,7 +29,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.HashMap; @@ -358,14 +357,15 @@ class BinaryDictionaryGetter { try { // Read the version of the file inStream = new FileInputStream(f); - final ByteBuffer buffer = inStream.getChannel().map( - FileChannel.MapMode.READ_ONLY, 0, f.length()); - final int magic = buffer.getInt(); + final BinaryDictInputOutput.ByteBufferWrapper buffer = + new BinaryDictInputOutput.ByteBufferWrapper(inStream.getChannel().map( + FileChannel.MapMode.READ_ONLY, 0, f.length())); + final int magic = buffer.readInt(); if (magic != FormatSpec.VERSION_2_MAGIC_NUMBER) { return false; } - final int formatVersion = buffer.getInt(); - final int headerSize = buffer.getInt(); + final int formatVersion = buffer.readInt(); + final int headerSize = buffer.readInt(); final HashMap options = CollectionUtils.newHashMap(); BinaryDictInputOutput.populateOptions(buffer, headerSize, options); diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 6f508695e..68d8bc553 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -1543,11 +1543,6 @@ public class BinaryDictInputOutput { options.put(key, value); } } - // TODO: remove this method. - public static void populateOptions(final ByteBuffer buffer, final int headerSize, - final HashMap options) { - populateOptions(new ByteBufferWrapper(buffer), headerSize, options); - } /** * Reads a buffer and returns the memory representation of the dictionary. -- cgit v1.2.3-83-g751a From 90a91272447fd64bc54e06f08f45b11c45930767 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 14 Sep 2012 16:53:01 +0900 Subject: Take space state into account for caps (A11) Bug: 6950087 Change-Id: I8a1bca24db64b4dd54db8ac74d90cf43cbdddab6 --- .../com/android/inputmethod/latin/LatinIME.java | 18 +++--- .../inputmethod/latin/RichInputConnection.java | 21 ++++++- .../com/android/inputmethod/latin/StringUtils.java | 19 ++++-- .../inputmethod/latin/StringUtilsTests.java | 67 ++++++++++++---------- 4 files changed, 79 insertions(+), 46 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index db8f269eb..b13826bfc 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -741,6 +741,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // switcher.loadKeyboard; in apps like Talk, we come here when the text is sent and the // field gets emptied and we need to re-evaluate the shift state, but not the whole layout // which would be disruptive. + // Space state must be updated before calling updateShiftState mKeyboardSwitcher.updateShiftState(); mHandler.cancelUpdateSuggestionStrip(); @@ -1114,11 +1115,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // unless needed. if (mWordComposer.isComposingWord()) return Constants.TextUtils.CAP_MODE_OFF; - // TODO: This blocking IPC call is heavy. Consider doing this without using IPC calls. - // Note: getCursorCapsMode() returns the current capitalization mode that is any - // combination of CAP_MODE_CHARACTERS, CAP_MODE_WORDS, and CAP_MODE_SENTENCES. 0 means none - // of them. - return mConnection.getCursorCapsMode(inputType, mSubtypeSwitcher.getCurrentSubtypeLocale()); + // Warning: this depends on mSpaceState, which may not be the most current value. If + // mSpaceState gets updated later, whoever called this may need to be told about it. + return mConnection.getCursorCapsMode(inputType, mSubtypeSwitcher.getCurrentSubtypeLocale(), + SPACE_STATE_PHANTOM == mSpaceState); } // Factor in auto-caps and manual caps and compute the current caps mode. @@ -1391,9 +1391,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } mConnection.commitText(text, 1); mConnection.endBatchEdit(); + // Space state must be updated before calling updateShiftState + mSpaceState = SPACE_STATE_NONE; mKeyboardSwitcher.updateShiftState(); mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT); - mSpaceState = SPACE_STATE_NONE; mEnteredText = text; } @@ -1509,8 +1510,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mConnection.setComposingText(batchInputText, 1); mExpectingUpdateSelection = true; mConnection.endBatchEdit(); - mKeyboardSwitcher.updateShiftState(); + // Space state must be updated before calling updateShiftState mSpaceState = SPACE_STATE_PHANTOM; + mKeyboardSwitcher.updateShiftState(); } private CharSequence specificTldProcessingOnTextInput(final CharSequence text) { @@ -2019,8 +2021,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mConnection.endBatchEdit(); // Don't allow cancellation of manual pick mLastComposedWord.deactivate(); + // Space state must be updated before calling updateShiftState mSpaceState = SPACE_STATE_PHANTOM; - // TODO: is this necessary? mKeyboardSwitcher.updateShiftState(); // We should show the "Touch again to save" hint if the user pressed the first entry diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index b85f9dcd7..cbc6a93fa 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -190,7 +190,23 @@ public class RichInputConnection { } } - public int getCursorCapsMode(final int inputType, final Locale locale) { + /** + * Gets the caps modes we should be in after this specific string. + * + * This returns a bit set of TextUtils#CAP_MODE_*, masked by the inputType argument. + * This method also supports faking an additional space after the string passed in argument, + * to support cases where a space will be added automatically, like in phantom space + * state for example. + * Note that for English, we are using American typography rules (which are not specific to + * American English, it's just the most common set of rules for English). + * + * @param inputType a mask of the caps modes to test for. + * @param locale what language should be considered. + * @param hasSpaceBefore if we should consider there should be a space after the string. + * @return the caps modes that should be on as a set of bits + */ + public int getCursorCapsMode(final int inputType, final Locale locale, + final boolean hasSpaceBefore) { mIC = mParent.getCurrentInputConnection(); if (null == mIC) return Constants.TextUtils.CAP_MODE_OFF; if (!TextUtils.isEmpty(mComposingText)) return Constants.TextUtils.CAP_MODE_OFF; @@ -205,7 +221,8 @@ public class RichInputConnection { } // This never calls InputConnection#getCapsMode - in fact, it's a static method that // never blocks or initiates IPC. - return StringUtils.getCapsMode(mCommittedTextBeforeComposingText, inputType, locale); + return StringUtils.getCapsMode(mCommittedTextBeforeComposingText, inputType, locale, + hasSpaceBefore); } public CharSequence getTextBeforeCursor(final int i, final int j) { diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 6dc1ea807..7b65b7343 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -197,13 +197,15 @@ public final class StringUtils { * {@link TextUtils#CAP_MODE_CHARACTERS}, {@link TextUtils#CAP_MODE_WORDS}, and * {@link TextUtils#CAP_MODE_SENTENCES}. * @param locale The locale to consider for capitalization rules + * @param hasSpaceBefore Whether we should consider there is a space inserted at the end of cs * * @return Returns the actual capitalization modes that can be in effect * at the current position, which is any combination of * {@link TextUtils#CAP_MODE_CHARACTERS}, {@link TextUtils#CAP_MODE_WORDS}, and * {@link TextUtils#CAP_MODE_SENTENCES}. */ - public static int getCapsMode(final CharSequence cs, final int reqModes, final Locale locale) { + public static int getCapsMode(final CharSequence cs, final int reqModes, final Locale locale, + final boolean hasSpaceBefore) { // Quick description of what we want to do: // CAP_MODE_CHARACTERS is always on. // CAP_MODE_WORDS is on if there is some whitespace before the cursor. @@ -230,11 +232,15 @@ public final class StringUtils { // single quote since they aren't start punctuation in the unicode sense, but should still // be skipped for English. TODO: does this depend on the language? int i; - for (i = cs.length(); i > 0; i--) { - final char c = cs.charAt(i - 1); - if (c != Keyboard.CODE_DOUBLE_QUOTE && c != Keyboard.CODE_SINGLE_QUOTE - && Character.getType(c) != Character.START_PUNCTUATION) { - break; + if (hasSpaceBefore) { + i = cs.length() + 1; + } else { + for (i = cs.length(); i > 0; i--) { + final char c = cs.charAt(i - 1); + if (c != Keyboard.CODE_DOUBLE_QUOTE && c != Keyboard.CODE_SINGLE_QUOTE + && Character.getType(c) != Character.START_PUNCTUATION) { + break; + } } } @@ -247,6 +253,7 @@ public final class StringUtils { // if the first char that's not a space or tab is a start of line (as in, either \n or // start of text). int j = i; + if (hasSpaceBefore) --j; while (j > 0 && Character.isWhitespace(cs.charAt(j - 1))) { j--; } diff --git a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java index 00cca9d3b..be3494dc7 100644 --- a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java @@ -93,22 +93,24 @@ public class StringUtilsTests extends AndroidTestCase { } private void onePathForCaps(final CharSequence cs, final int expectedResult, final int mask, - final Locale l) { + final Locale l, final boolean hasSpaceBefore) { int oneTimeResult = expectedResult & mask; - assertEquals("After >" + cs + "<", oneTimeResult, StringUtils.getCapsMode(cs, mask, l)); + assertEquals("After >" + cs + "<", oneTimeResult, + StringUtils.getCapsMode(cs, mask, l, hasSpaceBefore)); } - private void allPathsForCaps(final CharSequence cs, final int expectedResult, final Locale l) { + private void allPathsForCaps(final CharSequence cs, final int expectedResult, final Locale l, + final boolean hasSpaceBefore) { final int c = TextUtils.CAP_MODE_CHARACTERS; final int w = TextUtils.CAP_MODE_WORDS; final int s = TextUtils.CAP_MODE_SENTENCES; - onePathForCaps(cs, expectedResult, c | w | s, l); - onePathForCaps(cs, expectedResult, w | s, l); - onePathForCaps(cs, expectedResult, c | s, l); - onePathForCaps(cs, expectedResult, c | w, l); - onePathForCaps(cs, expectedResult, c, l); - onePathForCaps(cs, expectedResult, w, l); - onePathForCaps(cs, expectedResult, s, l); + onePathForCaps(cs, expectedResult, c | w | s, l, hasSpaceBefore); + onePathForCaps(cs, expectedResult, w | s, l, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c | s, l, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c | w, l, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c, l, hasSpaceBefore); + onePathForCaps(cs, expectedResult, w, l, hasSpaceBefore); + onePathForCaps(cs, expectedResult, s, l, hasSpaceBefore); } public void testGetCapsMode() { @@ -116,26 +118,31 @@ public class StringUtilsTests extends AndroidTestCase { final int w = TextUtils.CAP_MODE_WORDS; final int s = TextUtils.CAP_MODE_SENTENCES; Locale l = Locale.ENGLISH; - allPathsForCaps("", c | w | s, l); - allPathsForCaps("Word", c, l); - allPathsForCaps("Word.", c, l); - allPathsForCaps("Word ", c | w, l); - allPathsForCaps("Word. ", c | w | s, l); - allPathsForCaps("Word..", c, l); - allPathsForCaps("Word.. ", c | w | s, l); - allPathsForCaps("Word... ", c | w | s, l); - allPathsForCaps("Word ... ", c | w | s, l); - allPathsForCaps("Word . ", c | w, l); - allPathsForCaps("In the U.S ", c | w, l); - allPathsForCaps("In the U.S. ", c | w, l); - allPathsForCaps("Some stuff (e.g. ", c | w, l); - allPathsForCaps("In the U.S.. ", c | w | s, l); - allPathsForCaps("\"Word.\" ", c | w | s, l); - allPathsForCaps("\"Word\". ", c | w | s, l); - allPathsForCaps("\"Word\" ", c | w, l); + allPathsForCaps("", c | w | s, l, false); + allPathsForCaps("Word", c, l, false); + allPathsForCaps("Word.", c, l, false); + allPathsForCaps("Word ", c | w, l, false); + allPathsForCaps("Word. ", c | w | s, l, false); + allPathsForCaps("Word..", c, l, false); + allPathsForCaps("Word.. ", c | w | s, l, false); + allPathsForCaps("Word... ", c | w | s, l, false); + allPathsForCaps("Word ... ", c | w | s, l, false); + allPathsForCaps("Word . ", c | w, l, false); + allPathsForCaps("In the U.S ", c | w, l, false); + allPathsForCaps("In the U.S. ", c | w, l, false); + allPathsForCaps("Some stuff (e.g. ", c | w, l, false); + allPathsForCaps("In the U.S.. ", c | w | s, l, false); + allPathsForCaps("\"Word.\" ", c | w | s, l, false); + allPathsForCaps("\"Word\". ", c | w | s, l, false); + allPathsForCaps("\"Word\" ", c | w, l, false); + + // Test for phantom space + allPathsForCaps("Word", c | w, l, true); + allPathsForCaps("Word.", c | w | s, l, true); + l = Locale.FRENCH; - allPathsForCaps("\"Word.\" ", c | w, l); - allPathsForCaps("\"Word\". ", c | w | s, l); - allPathsForCaps("\"Word\" ", c | w, l); + allPathsForCaps("\"Word.\" ", c | w, l, false); + allPathsForCaps("\"Word\". ", c | w | s, l, false); + allPathsForCaps("\"Word\" ", c | w, l, false); } } -- cgit v1.2.3-83-g751a From 5822323514e9fe3956ce8339f4e2a801afd6b6c0 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 14 Sep 2012 18:14:46 +0900 Subject: Remove useless code (A12) All this code is done inside the StringUtils or RichInputConnection classes, where it's more logical. Since the IPC call is entirely gone now, it's no use having these guards inside Latin IME. Change-Id: Id324567e7458aed12b6f21d7114be3bd39725f15 --- java/src/com/android/inputmethod/latin/LatinIME.java | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index b13826bfc..10a6e9544 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1101,20 +1101,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final EditorInfo ei = getCurrentInputEditorInfo(); if (ei == null) return Constants.TextUtils.CAP_MODE_OFF; - final int inputType = ei.inputType; - if ((inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) { - return TextUtils.CAP_MODE_CHARACTERS; - } - - final boolean noNeedToCheckCapsMode = (inputType & (InputType.TYPE_TEXT_FLAG_CAP_SENTENCES - | InputType.TYPE_TEXT_FLAG_CAP_WORDS)) == 0; - if (noNeedToCheckCapsMode) return Constants.TextUtils.CAP_MODE_OFF; - - // Avoid making heavy round-trip IPC calls of {@link InputConnection#getCursorCapsMode} - // unless needed. - if (mWordComposer.isComposingWord()) return Constants.TextUtils.CAP_MODE_OFF; - // Warning: this depends on mSpaceState, which may not be the most current value. If // mSpaceState gets updated later, whoever called this may need to be told about it. return mConnection.getCursorCapsMode(inputType, mSubtypeSwitcher.getCurrentSubtypeLocale(), -- cgit v1.2.3-83-g751a From 6c721b5f68ee20e6d78ddd4f383fb8651827b726 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 18 Sep 2012 18:01:15 +0900 Subject: Fix a bug with surrogate characters This is a pretty bad bug :/ Bug: 7013840 Change-Id: I12c7cfa4fa9d56b2c1fee6e6222c64fe20b88fa3 --- .../com/android/inputmethod/latin/makedict/FusionDictionary.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java index 6775de8a8..98cf308c8 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java +++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java @@ -556,6 +556,7 @@ public class FusionDictionary implements Iterable { final StringBuilder checker = DBG ? new StringBuilder() : null; CharGroup currentGroup; + final int codePointCountInS = s.codePointCount(0, s.length()); do { int indexOfGroup = findIndexOfChar(node, s.codePointAt(index)); if (CHARACTER_NOT_FOUND == indexOfGroup) return null; @@ -570,12 +571,12 @@ public class FusionDictionary implements Iterable { index = newIndex; if (DBG) checker.append(new String(currentGroup.mChars, 0, currentGroup.mChars.length)); - if (index < s.length()) { + if (index < codePointCountInS) { node = currentGroup.mChildren; } - } while (null != node && index < s.length()); + } while (null != node && index < codePointCountInS); - if (index < s.length()) return null; + if (index < codePointCountInS) return null; if (!currentGroup.isTerminal()) return null; if (DBG && !s.equals(checker.toString())) return null; return currentGroup; -- cgit v1.2.3-83-g751a From d461bfd6601dfb6d4a4f78be0ff129597af895ff Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 14 Sep 2012 18:53:56 +0900 Subject: Support the gesture + phantom space case (A13) Bug: 6950087 Change-Id: I198699f6e687ac74c35b9edfe469dce880d9ecaf --- .../com/android/inputmethod/latin/RichInputConnection.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index cbc6a93fa..28c0c0f16 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -209,7 +209,16 @@ public class RichInputConnection { final boolean hasSpaceBefore) { mIC = mParent.getCurrentInputConnection(); if (null == mIC) return Constants.TextUtils.CAP_MODE_OFF; - if (!TextUtils.isEmpty(mComposingText)) return Constants.TextUtils.CAP_MODE_OFF; + if (!TextUtils.isEmpty(mComposingText)) { + if (hasSpaceBefore) { + // If we have some composing text and a space before, then we should have + // MODE_CHARACTERS and MODE_WORDS on. + return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS) & inputType; + } else { + // We have some composing text - we should be in MODE_CHARACTERS only. + return TextUtils.CAP_MODE_CHARACTERS & inputType; + } + } // TODO: this will generally work, but there may be cases where the buffer contains SOME // information but not enough to determine the caps mode accurately. This may happen after // heavy pressing of delete, for example DEFAULT_TEXT_CACHE_SIZE - 5 times or so. -- cgit v1.2.3-83-g751a From e4783f95b2ad9f46ece34103cbe4d8eb5ea8afca Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 14 Sep 2012 19:36:50 +0900 Subject: Mark 2 resolved TODOS as such (A14) Change-Id: Ifbb731f5c825675436d079db4ffbae657d71f8da --- java/src/com/android/inputmethod/latin/LatinIME.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 10a6e9544..23334d6f3 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1391,11 +1391,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (mWordComposer.isComposingWord()) { commitTyped(LastComposedWord.NOT_A_SEPARATOR); mExpectingUpdateSelection = true; - // TODO: Can we remove this? + // The following is necessary for the case where the user typed something but didn't + // manual pick it and didn't input any separator. mSpaceState = SPACE_STATE_PHANTOM; } mConnection.endBatchEdit(); - // TODO: Should handle TextUtils.CAP_MODE_CHARACTER. mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode()); } -- cgit v1.2.3-83-g751a From 75b3f81fe1bfd99083b872eb370219cb97212367 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 18 Sep 2012 18:52:05 +0900 Subject: Fix a bug with capitalizations (A15) When only one character has been typed, we should not take that as a strong symbol that everything should be upper-cased. Change-Id: I4e3a3223269e6763e3594baeaa844daa79a624ed --- java/src/com/android/inputmethod/latin/WordComposer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 4b7adf26b..7785e3fb9 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -267,7 +267,7 @@ public class WordComposer { public boolean isAllUpperCase() { return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFT_LOCKED - || (mCapsCount > 0) && (mCapsCount == size()); + || (mCapsCount > 1) && (mCapsCount == size()); } public boolean wasShiftedNoLock() { -- cgit v1.2.3-83-g751a From f8b35b9b04ae91f3a4991ea3ff745c68a17297c6 Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Tue, 18 Sep 2012 12:06:07 +0900 Subject: Log touch timing Change-Id: I45ce16c3194fac6da98486a986d23318347cad3a --- java/src/com/android/inputmethod/latin/LatinImeLogger.java | 7 ++++++- java/src/com/android/inputmethod/latin/Utils.java | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index e843848bc..a5b4c68d0 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -44,7 +44,12 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang String before, String after, int position, SuggestedWords suggestedWords) { } - public static void logOnAutoCorrection(String before, String after, int separatorCode) { + public static void logOnAutoCorrectionForTyping( + String before, String after, int separatorCode) { + } + + public static void logOnAutoCorrectionForGeometric(String before, String after, + int separatorCode, int[] xCoordinates, int[] yCoordinates, int[] relativeTimes) { } public static void logOnAutoCorrectionCancelled() { diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 1c98b92cd..63b642821 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -419,7 +419,7 @@ public final class Utils { // smileys and other multi-character keys. final int codePoint = TextUtils.isEmpty(separatorString) ? Constants.NOT_A_CODE : separatorString.codePointAt(0); - LatinImeLogger.logOnAutoCorrection(typedWord, correctedWord, codePoint); + LatinImeLogger.logOnAutoCorrectionForTyping(typedWord, correctedWord, codePoint); } public static void onAutoCorrectionCancellation() { -- cgit v1.2.3-83-g751a From e55785e682351f5379427b50cb6001b540024ced Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Tue, 18 Sep 2012 20:22:40 +0900 Subject: New flag for the internal settings Change-Id: I81e69a6cda833a0d2c59a73388321ed11e0bd5b3 --- java/src/com/android/inputmethod/latin/Settings.java | 4 ++-- java/src/com/android/inputmethod/latin/define/ProductionFlag.java | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 6251c9acd..180f6c56f 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -44,7 +44,7 @@ import com.android.inputmethodcommon.InputMethodSettingsFragment; public class Settings extends InputMethodSettingsFragment implements SharedPreferences.OnSharedPreferenceChangeListener { - public static final boolean ENABLE_EXPERIMENTAL_SETTINGS = false; + public static final boolean ENABLE_INTERNAL_SETTINGS = ProductionFlag.IS_INTERNAL; // In the same order as xml/prefs.xml public static final String PREF_GENERAL_SETTINGS = "general_settings"; @@ -220,7 +220,7 @@ public class Settings extends InputMethodSettingsFragment final boolean showUsabilityStudyModeOption = res.getBoolean(R.bool.config_enable_usability_study_mode_option) - || ProductionFlag.IS_EXPERIMENTAL || ENABLE_EXPERIMENTAL_SETTINGS; + || ProductionFlag.IS_EXPERIMENTAL || ENABLE_INTERNAL_SETTINGS; final Preference usabilityStudyPref = findPreference(PREF_USABILITY_STUDY_MODE); if (!showUsabilityStudyModeOption) { if (usabilityStudyPref != null) { diff --git a/java/src/com/android/inputmethod/latin/define/ProductionFlag.java b/java/src/com/android/inputmethod/latin/define/ProductionFlag.java index de2057669..52c066a44 100644 --- a/java/src/com/android/inputmethod/latin/define/ProductionFlag.java +++ b/java/src/com/android/inputmethod/latin/define/ProductionFlag.java @@ -22,4 +22,5 @@ public final class ProductionFlag { } public static final boolean IS_EXPERIMENTAL = false; + public static final boolean IS_INTERNAL = false; } -- cgit v1.2.3-83-g751a From 061d225fb1d110695b396a470d9ae6a9a3331003 Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Fri, 14 Sep 2012 12:38:47 +0900 Subject: Add a new option to FormatOptions. Change-Id: I8bf089bea5de46570a5e81fb1ea3ab22c07eeee1 --- .../inputmethod/latin/makedict/FormatSpec.java | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java index 1707ccc39..7b6817a25 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java +++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java @@ -41,6 +41,12 @@ public final class FormatSpec { * u | * ps * + * f | + * o | IF HAS_LINKEDLIST_NODE (defined in the file header) + * r | forward link address, 3byte + * w | the address must be positive. + * a | + * rdlinkaddress */ /* Node(CharGroup) layout is as follows: @@ -140,6 +146,7 @@ public final class FormatSpec { static final int NOT_A_VERSION_NUMBER = -1; static final int FIRST_VERSION_WITH_HEADER_SIZE = 2; static final int FIRST_VERSION_WITH_PARENT_ADDRESS = 3; + static final int FIRST_VERSION_WITH_LINKEDLIST_NODE = 3; // These options need to be the same numeric values as the one in the native reading code. static final int GERMAN_UMLAUT_PROCESSING_FLAG = 0x1; @@ -152,6 +159,7 @@ public final class FormatSpec { static final int MAX_WORD_LENGTH = Constants.Dictionary.MAX_WORD_LENGTH; static final int PARENT_ADDRESS_SIZE = 3; + static final int FORWARD_LINK_ADDRESS_SIZE = 3; static final int MASK_GROUP_ADDRESS_TYPE = 0xC0; static final int FLAG_GROUP_ADDRESS_TYPE_NOADDRESS = 0x00; @@ -187,6 +195,7 @@ public final class FormatSpec { static final int NO_CHILDREN_ADDRESS = Integer.MIN_VALUE; static final int NO_PARENT_ADDRESS = 0; + static final int NO_FORWARD_LINK_ADDRESS = 0; static final int INVALID_CHARACTER = -1; static final int MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT = 0x7F; // 127 @@ -201,16 +210,30 @@ public final class FormatSpec { public static class FormatOptions { public final int mVersion; public final boolean mHasParentAddress; + public final boolean mHasLinkedListNode; public FormatOptions(final int version) { this(version, false); } public FormatOptions(final int version, final boolean hasParentAddress) { + this(version, hasParentAddress, false); + } + public FormatOptions(final int version, final boolean hasParentAddress, + final boolean hasLinkedListNode) { mVersion = version; - if (version < FormatSpec.FIRST_VERSION_WITH_PARENT_ADDRESS && hasParentAddress) { + if (version < FIRST_VERSION_WITH_PARENT_ADDRESS && hasParentAddress) { throw new RuntimeException("Parent addresses are only supported with versions " - + FormatSpec.FIRST_VERSION_WITH_PARENT_ADDRESS + " and ulterior."); + + FIRST_VERSION_WITH_PARENT_ADDRESS + " and ulterior."); } mHasParentAddress = hasParentAddress; + + if (version < FIRST_VERSION_WITH_LINKEDLIST_NODE && hasLinkedListNode) { + throw new RuntimeException("Linked list nodes are only supported with versions " + + FIRST_VERSION_WITH_LINKEDLIST_NODE + " and ulterior."); + } + if (!hasParentAddress && hasLinkedListNode) { + throw new RuntimeException("Linked list nodes need parent addresses."); + } + mHasLinkedListNode = hasLinkedListNode; } } -- cgit v1.2.3-83-g751a From bf45dc4860ab28e97c3e7d116a642802fe960239 Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Tue, 18 Sep 2012 15:28:05 +0900 Subject: Make writePlacedNode write the linked-list node. Change-Id: I60feda815ea08cf73300fccca1ae12b97550f116 --- .../latin/makedict/BinaryDictInputOutput.java | 23 ++++++++++++++++++---- .../latin/makedict/BinaryDictIOTests.java | 14 ++++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 68d8bc553..3a5f24c86 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -370,6 +370,9 @@ public class BinaryDictInputOutput { g.mCachedSize = groupSize; size += groupSize; } + if (options.mHasLinkedListNode) { + size += FormatSpec.FORWARD_LINK_ADDRESS_SIZE; + } node.mCachedSize = size; } @@ -521,6 +524,9 @@ public class BinaryDictInputOutput { group.mCachedSize = groupSize; size += groupSize; } + if (formatOptions.mHasLinkedListNode) { + size += FormatSpec.FORWARD_LINK_ADDRESS_SIZE; + } if (node.mCachedSize != size) { node.mCachedSize = size; changed = true; @@ -532,9 +538,11 @@ public class BinaryDictInputOutput { * Computes the byte size of a list of nodes and updates each node cached position. * * @param flatNodes the array of nodes. + * @param formatOptions file format options. * @return the byte size of the entire stack. */ - private static int stackNodes(final ArrayList flatNodes) { + private static int stackNodes(final ArrayList flatNodes, + final FormatOptions formatOptions) { int nodeOffset = 0; for (Node n : flatNodes) { n.mCachedAddress = nodeOffset; @@ -544,7 +552,9 @@ public class BinaryDictInputOutput { g.mCachedAddress = groupCountSize + nodeOffset + groupOffset; groupOffset += g.mCachedSize; } - if (groupOffset + groupCountSize != n.mCachedSize) { + final int nodeSize = groupCountSize + groupOffset + + (formatOptions.mHasLinkedListNode ? FormatSpec.FORWARD_LINK_ADDRESS_SIZE : 0); + if (nodeSize != n.mCachedSize) { throw new RuntimeException("Bug : Stored and computed node size differ"); } nodeOffset += n.mCachedSize; @@ -571,7 +581,7 @@ public class BinaryDictInputOutput { final ArrayList flatNodes, final FormatOptions formatOptions) { // First get the worst sizes and offsets for (Node n : flatNodes) setNodeMaximumSize(n, formatOptions); - final int offset = stackNodes(flatNodes); + final int offset = stackNodes(flatNodes, formatOptions); MakedictLog.i("Compressing the array addresses. Original size : " + offset); MakedictLog.i("(Recursively seen size : " + offset + ")"); @@ -587,7 +597,7 @@ public class BinaryDictInputOutput { if (oldNodeSize < newNodeSize) throw new RuntimeException("Increased size ?!"); changesDone |= changed; } - stackNodes(flatNodes); + stackNodes(flatNodes, formatOptions); ++passes; if (passes > MAX_PASSES) throw new RuntimeException("Too many passes - probably a bug"); } while (changesDone); @@ -910,6 +920,11 @@ public class BinaryDictInputOutput { } } + if (formatOptions.mHasLinkedListNode) { + buffer[index] = buffer[index + 1] = buffer[index + 2] + = FormatSpec.NO_FORWARD_LINK_ADDRESS; + index += FormatSpec.FORWARD_LINK_ADDRESS_SIZE; + } if (index != node.mCachedAddress + node.mCachedSize) throw new RuntimeException( "Not the same size : written " + (index - node.mCachedAddress) + " bytes out of a node that should have " diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java index 328784b1a..a87146ee2 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java @@ -65,9 +65,12 @@ public class BinaryDictIOTests extends AndroidTestCase { private static final FormatSpec.FormatOptions VERSION2 = new FormatSpec.FormatOptions(2); private static final FormatSpec.FormatOptions VERSION3_WITHOUT_PARENTADDRESS = - new FormatSpec.FormatOptions(3, false); + new FormatSpec.FormatOptions(3, false /* hasParentAddress */); private static final FormatSpec.FormatOptions VERSION3_WITH_PARENTADDRESS = - new FormatSpec.FormatOptions(3, true); + new FormatSpec.FormatOptions(3, true /* hasParentAddress */); + private static final FormatSpec.FormatOptions VERSION3_WITH_LINKEDLIST_NODE = + new FormatSpec.FormatOptions(3, true /* hasParentAddress */, + true /* hasLinkedListNode */); private static final String[] CHARACTERS = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", @@ -236,7 +239,8 @@ public class BinaryDictIOTests extends AndroidTestCase { String result = " : buffer type = " + ((bufferType == USE_BYTE_BUFFER) ? "byte buffer" : "byte array"); result += " : version = " + formatOptions.mVersion; - return result + ", hasParentAddress = " + formatOptions.mHasParentAddress; + return result + ", hasParentAddress = " + formatOptions.mHasParentAddress + + ", hasLinkedListNode = " + formatOptions.mHasLinkedListNode; } // Tests for readDictionaryBinary and writeDictionaryBinary @@ -305,6 +309,7 @@ public class BinaryDictIOTests extends AndroidTestCase { runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION2); runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION3_WITHOUT_PARENTADDRESS); runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION3_WITH_PARENTADDRESS); + runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION3_WITH_LINKEDLIST_NODE); for (final String result : results) { Log.d(TAG, result); @@ -317,6 +322,7 @@ public class BinaryDictIOTests extends AndroidTestCase { runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION2); runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION3_WITHOUT_PARENTADDRESS); runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION3_WITH_PARENTADDRESS); + runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION3_WITH_LINKEDLIST_NODE); for (final String result : results) { Log.d(TAG, result); @@ -450,6 +456,7 @@ public class BinaryDictIOTests extends AndroidTestCase { runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION2); runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION3_WITHOUT_PARENTADDRESS); runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION3_WITH_PARENTADDRESS); + runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION3_WITH_LINKEDLIST_NODE); for (final String result : results) { Log.d(TAG, result); @@ -462,6 +469,7 @@ public class BinaryDictIOTests extends AndroidTestCase { runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION2); runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION3_WITHOUT_PARENTADDRESS); runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION3_WITH_PARENTADDRESS); + runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION3_WITH_LINKEDLIST_NODE); for (final String result : results) { Log.d(TAG, result); -- cgit v1.2.3-83-g751a From b686df15fcc95611c524318359fe9ecb4fd6f74c Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Tue, 18 Sep 2012 21:29:59 +0900 Subject: Add a new flag for linked list nodes. Change-Id: Ib2f194775cfe5ab05481ac95cd709d6e8e8dd3c6 --- .../android/inputmethod/latin/makedict/BinaryDictInputOutput.java | 6 ++++-- java/src/com/android/inputmethod/latin/makedict/FormatSpec.java | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 3a5f24c86..72d12299b 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -786,7 +786,8 @@ public class BinaryDictInputOutput { return (options.mFrenchLigatureProcessing ? FormatSpec.FRENCH_LIGATURE_PROCESSING_FLAG : 0) + (options.mGermanUmlautProcessing ? FormatSpec.GERMAN_UMLAUT_PROCESSING_FLAG : 0) + (hasBigrams ? FormatSpec.CONTAINS_BIGRAMS_FLAG : 0) - + (formatOptions.mHasParentAddress ? FormatSpec.HAS_PARENT_ADDRESS : 0); + + (formatOptions.mHasParentAddress ? FormatSpec.HAS_PARENT_ADDRESS : 0) + + (formatOptions.mHasLinkedListNode ? FormatSpec.HAS_LINKEDLIST_NODE : 0); } /** @@ -1540,7 +1541,8 @@ public class BinaryDictInputOutput { 0 != (optionsFlags & FormatSpec.GERMAN_UMLAUT_PROCESSING_FLAG), 0 != (optionsFlags & FormatSpec.FRENCH_LIGATURE_PROCESSING_FLAG)), new FormatOptions(version, - 0 != (optionsFlags & FormatSpec.HAS_PARENT_ADDRESS))); + 0 != (optionsFlags & FormatSpec.HAS_PARENT_ADDRESS), + 0 != (optionsFlags & FormatSpec.HAS_LINKEDLIST_NODE))); return header; } diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java index 7b6817a25..f8f13b197 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java +++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java @@ -150,9 +150,12 @@ public final class FormatSpec { // These options need to be the same numeric values as the one in the native reading code. static final int GERMAN_UMLAUT_PROCESSING_FLAG = 0x1; + // TODO: Make the native reading code read this variable. static final int HAS_PARENT_ADDRESS = 0x2; static final int FRENCH_LIGATURE_PROCESSING_FLAG = 0x4; static final int CONTAINS_BIGRAMS_FLAG = 0x8; + // TODO: Make the native reading code read this variable. + static final int HAS_LINKEDLIST_NODE = 0x10; // TODO: Make this value adaptative to content data, store it in the header, and // use it in the reading code. -- cgit v1.2.3-83-g751a From a149c53c8ebe1b2acb7ee92eac51ccdc364162e7 Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Wed, 19 Sep 2012 12:28:19 +0900 Subject: add limit to FusionDictionaryBufferInterface. Change-Id: Ic9ff717a9751023d47b02ff3b9d1fbf3115c2501 --- java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java | 5 +++++ .../android/inputmethod/latin/makedict/BinaryDictInputOutput.java | 6 ++++++ 2 files changed, 11 insertions(+) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java index 550e4e58b..ddbc02363 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java @@ -96,6 +96,11 @@ public class UserHistoryDictIOUtils { public void put(final byte b) { mBuffer[mPosition++] = b; } + + @Override + public int limit() { + return mBuffer.length; + } } /** diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 72d12299b..56b29ec79 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -63,6 +63,7 @@ public class BinaryDictInputOutput { public int position(); public void position(int newPosition); public void put(final byte b); + public int limit(); } public static final class ByteBufferWrapper implements FusionDictionaryBufferInterface { @@ -107,6 +108,11 @@ public class BinaryDictInputOutput { public void put(final byte b) { mBuffer.put(b); } + + @Override + public int limit() { + return mBuffer.limit(); + } } /** -- cgit v1.2.3-83-g751a From c2fdf0dfbf1c43f7ed8fdf3d91576bbf71146ef3 Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Fri, 14 Sep 2012 13:07:39 +0900 Subject: Make readNode read linked list nodes. Change-Id: Ia5eaae0653179b2eb74c53b0823beaf80377a389 --- .../latin/makedict/BinaryDictInputOutput.java | 82 +++++++++++++--------- 1 file changed, 50 insertions(+), 32 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 56b29ec79..5a0eafadb 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -1347,43 +1347,61 @@ public class BinaryDictInputOutput { final Map reverseNodeMap, final Map reverseGroupMap, final FormatOptions options) throws IOException { - final int nodeOrigin = buffer.position() - headerSize; - final int count = readCharGroupCount(buffer); final ArrayList nodeContents = new ArrayList(); - int groupOffset = nodeOrigin + getGroupCountSize(count); - for (int i = count; i > 0; --i) { - CharGroupInfo info = readCharGroup(buffer, groupOffset, options); - ArrayList shortcutTargets = info.mShortcutTargets; - ArrayList bigrams = null; - if (null != info.mBigrams) { - bigrams = new ArrayList(); - for (PendingAttribute bigram : info.mBigrams) { - final String word = getWordAtAddress( - buffer, headerSize, bigram.mAddress, options); - bigrams.add(new WeightedString(word, bigram.mFrequency)); + final int nodeOrigin = buffer.position() - headerSize; + + do { // Scan the linked-list node. + final int nodeHeadPosition = buffer.position() - headerSize; + final int count = readCharGroupCount(buffer); + int groupOffset = nodeHeadPosition + getGroupCountSize(count); + for (int i = count; i > 0; --i) { // Scan the array of CharGroup. + CharGroupInfo info = readCharGroup(buffer, groupOffset, options); + ArrayList shortcutTargets = info.mShortcutTargets; + ArrayList bigrams = null; + if (null != info.mBigrams) { + bigrams = new ArrayList(); + for (PendingAttribute bigram : info.mBigrams) { + final String word = getWordAtAddress( + buffer, headerSize, bigram.mAddress, options); + bigrams.add(new WeightedString(word, bigram.mFrequency)); + } + } + if (hasChildrenAddress(info.mChildrenAddress)) { + Node children = reverseNodeMap.get(info.mChildrenAddress); + if (null == children) { + final int currentPosition = buffer.position(); + buffer.position(info.mChildrenAddress + headerSize); + children = readNode( + buffer, headerSize, reverseNodeMap, reverseGroupMap, options); + buffer.position(currentPosition); + } + nodeContents.add( + new CharGroup(info.mCharacters, shortcutTargets, bigrams, + info.mFrequency, + 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD), + 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED), children)); + } else { + nodeContents.add( + new CharGroup(info.mCharacters, shortcutTargets, bigrams, + info.mFrequency, + 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD), + 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED))); } + groupOffset = info.mEndAddress; } - if (hasChildrenAddress(info.mChildrenAddress)) { - Node children = reverseNodeMap.get(info.mChildrenAddress); - if (null == children) { - final int currentPosition = buffer.position(); - buffer.position(info.mChildrenAddress + headerSize); - children = readNode( - buffer, headerSize, reverseNodeMap, reverseGroupMap, options); - buffer.position(currentPosition); + + // reach the end of the array. + if (options.mHasLinkedListNode) { + final int nextAddress = buffer.readUnsignedInt24(); + if (nextAddress >= 0 && nextAddress < buffer.limit()) { + buffer.position(nextAddress); + } else { + break; } - nodeContents.add( - new CharGroup(info.mCharacters, shortcutTargets, bigrams, info.mFrequency, - 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD), - 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED), children)); - } else { - nodeContents.add( - new CharGroup(info.mCharacters, shortcutTargets, bigrams, info.mFrequency, - 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD), - 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED))); } - groupOffset = info.mEndAddress; - } + } while (options.mHasLinkedListNode && + buffer.position() != FormatSpec.NO_FORWARD_LINK_ADDRESS); + final Node node = new Node(nodeContents); node.mCachedAddress = nodeOrigin; reverseNodeMap.put(node.mCachedAddress, node); -- cgit v1.2.3-83-g751a From 65feee12e5889601e375d92dfdf5f8e8fbb05092 Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Wed, 19 Sep 2012 13:53:21 +0900 Subject: Make BinaryDictIOUtils. Change-Id: I45830235ee738233e8eb2bd91d659705b698f58c --- .../inputmethod/latin/UserHistoryDictIOUtils.java | 3 +- .../latin/makedict/BinaryDictIOUtils.java | 127 +++++++++++++++++++++ .../latin/makedict/BinaryDictInputOutput.java | 107 +---------------- .../latin/makedict/BinaryDictIOTests.java | 2 +- 4 files changed, 135 insertions(+), 104 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java index ddbc02363..4a3d11aa1 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin; import android.util.Log; +import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; import com.android.inputmethod.latin.makedict.BinaryDictInputOutput; import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; @@ -167,7 +168,7 @@ public class UserHistoryDictIOUtils { final Map> bigrams = CollectionUtils.newTreeMap(); try { - BinaryDictInputOutput.readUnigramsAndBigramsBinary(buffer, unigrams, frequencies, + BinaryDictIOUtils.readUnigramsAndBigramsBinary(buffer, unigrams, frequencies, bigrams); addWordsFromWordMap(unigrams, frequencies, bigrams, dict); } catch (IOException e) { diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java new file mode 100644 index 000000000..1a85e71ce --- /dev/null +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin.makedict; + +import com.android.inputmethod.latin.makedict.BinaryDictInputOutput; +import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface; +import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; +import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Map; +import java.util.Stack; + +public class BinaryDictIOUtils { + private static final boolean DBG = false; + + private static class Position { + public static final int NOT_READ_GROUPCOUNT = -1; + + public int mAddress; + public int mNumOfCharGroup; + public int mPosition; + public int mLength; + + public Position(int address, int length) { + mAddress = address; + mLength = length; + mNumOfCharGroup = NOT_READ_GROUPCOUNT; + } + } + + /** + * Tours all node without recursive call. + */ + private static void readUnigramsAndBigramsBinaryInner( + final FusionDictionaryBufferInterface buffer, final int headerSize, + final Map words, final Map frequencies, + final Map> bigrams, + final FormatOptions formatOptions) { + int[] pushedChars = new int[FormatSpec.MAX_WORD_LENGTH + 1]; + + Stack stack = new Stack(); + int index = 0; + + Position initPos = new Position(headerSize, 0); + stack.push(initPos); + + while (!stack.empty()) { + Position p = stack.peek(); + + if (DBG) { + MakedictLog.d("read: address=" + p.mAddress + ", numOfCharGroup=" + + p.mNumOfCharGroup + ", position=" + p.mPosition + ", length=" + p.mLength); + } + + if (buffer.position() != p.mAddress) buffer.position(p.mAddress); + if (index != p.mLength) index = p.mLength; + + if (p.mNumOfCharGroup == Position.NOT_READ_GROUPCOUNT) { + p.mNumOfCharGroup = BinaryDictInputOutput.readCharGroupCount(buffer); + p.mAddress += BinaryDictInputOutput.getGroupCountSize(p.mNumOfCharGroup); + p.mPosition = 0; + } + + CharGroupInfo info = BinaryDictInputOutput.readCharGroup(buffer, + p.mAddress - headerSize, formatOptions); + for (int i = 0; i < info.mCharacters.length; ++i) { + pushedChars[index++] = info.mCharacters[i]; + } + p.mPosition++; + + if (info.mFrequency != FusionDictionary.CharGroup.NOT_A_TERMINAL) { // found word + words.put(info.mOriginalAddress, new String(pushedChars, 0, index)); + frequencies.put(info.mOriginalAddress, info.mFrequency); + if (info.mBigrams != null) bigrams.put(info.mOriginalAddress, info.mBigrams); + } + + if (p.mPosition == p.mNumOfCharGroup) { + stack.pop(); + } else { + // the node has more groups. + p.mAddress = buffer.position(); + } + + if (BinaryDictInputOutput.hasChildrenAddress(info.mChildrenAddress)) { + Position childrenPos = new Position(info.mChildrenAddress + headerSize, index); + stack.push(childrenPos); + } + } + } + + /** + * Reads unigrams and bigrams from the binary file. + * Doesn't make the memory representation of the dictionary. + * + * @param buffer the buffer to read. + * @param words the map to store the address as a key and the word as a value. + * @param frequencies the map to store the address as a key and the frequency as a value. + * @param bigrams the map to store the address as a key and the list of address as a value. + * @throws IOException + * @throws UnsupportedFormatException + */ + public static void readUnigramsAndBigramsBinary(final FusionDictionaryBufferInterface buffer, + final Map words, final Map frequencies, + final Map> bigrams) throws IOException, + UnsupportedFormatException { + // Read header + final FileHeader header = BinaryDictInputOutput.readHeader(buffer); + readUnigramsAndBigramsBinaryInner(buffer, header.mHeaderSize, words, frequencies, bigrams, + header.mFormatOptions); + } +} diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 5a0eafadb..c865702d6 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -290,7 +290,7 @@ public class BinaryDictInputOutput { * @param count the group count * @return the size of the group count, either 1 or 2 bytes. */ - private static int getGroupCountSize(final int count) { + public static int getGroupCountSize(final int count) { if (FormatSpec.MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT >= count) { return 1; } else if (FormatSpec.MAX_CHARGROUPS_IN_A_NODE >= count) { @@ -385,7 +385,7 @@ public class BinaryDictInputOutput { /** * Helper method to hide the actual value of the no children address. */ - private static boolean hasChildrenAddress(final int address) { + public static boolean hasChildrenAddress(final int address) { return FormatSpec.NO_CHILDREN_ADDRESS != address; } @@ -1105,7 +1105,7 @@ public class BinaryDictInputOutput { // readDictionaryBinary is the public entry point for them. private static final int[] CHARACTER_BUFFER = new int[FormatSpec.MAX_WORD_LENGTH]; - private static CharGroupInfo readCharGroup(final FusionDictionaryBufferInterface buffer, + public static CharGroupInfo readCharGroup(final FusionDictionaryBufferInterface buffer, final int originalGroupAddress, final FormatOptions options) { int addressPointer = originalGroupAddress; final int flags = buffer.readUnsignedByte(); @@ -1218,7 +1218,7 @@ public class BinaryDictInputOutput { /** * Reads and returns the char group count out of a buffer and forwards the pointer. */ - private static int readCharGroupCount(final FusionDictionaryBufferInterface buffer) { + public static int readCharGroupCount(final FusionDictionaryBufferInterface buffer) { final int msb = buffer.readUnsignedByte(); if (FormatSpec.MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT >= msb) { return msb; @@ -1408,103 +1408,6 @@ public class BinaryDictInputOutput { return node; } - // TODO: move these methods (readUnigramsAndBigramsBinary(|Inner)) and an inner class (Position) - // out of this class. - private static class Position { - public static final int NOT_READ_GROUPCOUNT = -1; - - public int mAddress; - public int mNumOfCharGroup; - public int mPosition; - public int mLength; - - public Position(int address, int length) { - mAddress = address; - mLength = length; - mNumOfCharGroup = NOT_READ_GROUPCOUNT; - } - } - - /** - * Tours all node without recursive call. - */ - private static void readUnigramsAndBigramsBinaryInner( - final FusionDictionaryBufferInterface buffer, final int headerSize, - final Map words, final Map frequencies, - final Map> bigrams, - final FormatOptions formatOptions) { - int[] pushedChars = new int[FormatSpec.MAX_WORD_LENGTH + 1]; - - Stack stack = new Stack(); - int index = 0; - - Position initPos = new Position(headerSize, 0); - stack.push(initPos); - - while (!stack.empty()) { - Position p = stack.peek(); - - if (DBG) { - MakedictLog.d("read: address=" + p.mAddress + ", numOfCharGroup=" + - p.mNumOfCharGroup + ", position=" + p.mPosition + ", length=" + p.mLength); - } - - if (buffer.position() != p.mAddress) buffer.position(p.mAddress); - if (index != p.mLength) index = p.mLength; - - if (p.mNumOfCharGroup == Position.NOT_READ_GROUPCOUNT) { - p.mNumOfCharGroup = readCharGroupCount(buffer); - p.mAddress += getGroupCountSize(p.mNumOfCharGroup); - p.mPosition = 0; - } - - CharGroupInfo info = readCharGroup(buffer, p.mAddress - headerSize, formatOptions); - for (int i = 0; i < info.mCharacters.length; ++i) { - pushedChars[index++] = info.mCharacters[i]; - } - p.mPosition++; - - if (info.mFrequency != FusionDictionary.CharGroup.NOT_A_TERMINAL) { // found word - words.put(info.mOriginalAddress, new String(pushedChars, 0, index)); - frequencies.put(info.mOriginalAddress, info.mFrequency); - if (info.mBigrams != null) bigrams.put(info.mOriginalAddress, info.mBigrams); - } - - if (p.mPosition == p.mNumOfCharGroup) { - stack.pop(); - } else { - // the node has more groups. - p.mAddress = buffer.position(); - } - - if (hasChildrenAddress(info.mChildrenAddress)) { - Position childrenPos = new Position(info.mChildrenAddress + headerSize, index); - stack.push(childrenPos); - } - } - } - - /** - * Reads unigrams and bigrams from the binary file. - * Doesn't make the memory representation of the dictionary. - * - * @param buffer the buffer to read. - * @param words the map to store the address as a key and the word as a value. - * @param frequencies the map to store the address as a key and the frequency as a value. - * @param bigrams the map to store the address as a key and the list of address as a value. - * @throws IOException - * @throws UnsupportedFormatException - */ - public static void readUnigramsAndBigramsBinary(final FusionDictionaryBufferInterface buffer, - final Map words, final Map frequencies, - final Map> bigrams) throws IOException, - UnsupportedFormatException { - // Read header - final FileHeader header = readHeader(buffer); - readUnigramsAndBigramsBinaryInner(buffer, header.mHeaderSize, words, frequencies, bigrams, - header.mFormatOptions); - } - /** * Helper function to get the binary format version from the header. * @throws IOException @@ -1541,7 +1444,7 @@ public class BinaryDictInputOutput { * @throws IOException * @throws UnsupportedFormatException */ - private static FileHeader readHeader(final FusionDictionaryBufferInterface buffer) + public static FileHeader readHeader(final FusionDictionaryBufferInterface buffer) throws IOException, UnsupportedFormatException { final int version = checkFormatVersion(buffer); final int optionsFlags = buffer.readUnsignedShort(); diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java index a87146ee2..4c2d3f6fe 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java @@ -391,7 +391,7 @@ public class BinaryDictIOTests extends AndroidTestCase { assertNotNull("Can't get buffer.", buffer); try { now = System.currentTimeMillis(); - BinaryDictInputOutput.readUnigramsAndBigramsBinary(buffer, resultWords, resultFreqs, + BinaryDictIOUtils.readUnigramsAndBigramsBinary(buffer, resultWords, resultFreqs, resultBigrams); diff = System.currentTimeMillis() - now; } catch (IOException e) { -- cgit v1.2.3-83-g751a From f501e4dbd2eae3ac162f319d33bae5401b232fb5 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 19 Sep 2012 16:13:08 +0900 Subject: Remove hack algorithm from GestureStroke Change-Id: Idd1c150677b989415e6fee4f543ff7639e98bed8 --- .../keyboard/internal/GestureStroke.java | 32 ---------------------- 1 file changed, 32 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java index 825134468..7a8c2409c 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java @@ -25,7 +25,6 @@ public class GestureStroke { private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private float mLength; - private float mAngle; private int mIncrementalRecognitionSize; private int mLastIncrementalBatchSize; private long mLastPointTime; @@ -40,9 +39,6 @@ public class GestureStroke { private static final int MIN_GESTURE_DURATION = 100; // msec private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH = 1.0f / 6.0f; private static final float GESTURE_RECOG_SPEED_THRESHOLD = 0.4f; // dip/msec - private static final float GESTURE_RECOG_CURVATURE_THRESHOLD = (float)(Math.PI / 4.0f); - - private static final float DOUBLE_PI = (float)(2.0f * Math.PI); public GestureStroke(final int pointerId) { mPointerId = pointerId; @@ -62,7 +58,6 @@ public class GestureStroke { public void reset() { mLength = 0; - mAngle = 0; mIncrementalRecognitionSize = 0; mLastIncrementalBatchSize = 0; mLastPointTime = 0; @@ -97,16 +92,6 @@ public class GestureStroke { mXCoordinates.add(x); mYCoordinates.add(y); mLength += dist; - final float angle = getAngle(lastX, lastY, x, y); - if (size > 1) { - final float curvature = getAngleDiff(angle, mAngle); - if (curvature > GESTURE_RECOG_CURVATURE_THRESHOLD) { - if (size > mIncrementalRecognitionSize) { - mIncrementalRecognitionSize = size; - } - } - } - mAngle = angle; } if (!isHistorical) { @@ -146,21 +131,4 @@ public class GestureStroke { // java.lang.Math due to the way the JIT optimizes java.lang.Math. return (float)Math.sqrt(dx * dx + dy * dy); } - - private static float getAngle(final int x1, final int y1, final int x2, final int y2) { - final int dx = x1 - x2; - final int dy = y1 - y2; - if (dx == 0 && dy == 0) return 0; - // Would it be faster to call atan2f() directly via JNI? Not sure about what the JIT - // does with Math.atan2(). - return (float)Math.atan2(dy, dx); - } - - private static float getAngleDiff(final float a1, final float a2) { - final float diff = Math.abs(a1 - a2); - if (diff > Math.PI) { - return DOUBLE_PI - diff; - } - return diff; - } } -- cgit v1.2.3-83-g751a From 87cecf7db61536d9f7ec07fe198d37a11b6c8407 Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Wed, 19 Sep 2012 16:18:24 +0900 Subject: Log for geometric input Change-Id: Ia0f0e38086b0be70cf2d04fc6fae48358f16e74f --- .../com/android/inputmethod/latin/LatinIME.java | 44 +++++++++++++++++----- .../android/inputmethod/latin/LatinImeLogger.java | 2 +- .../src/com/android/inputmethod/latin/Suggest.java | 4 ++ java/src/com/android/inputmethod/latin/Utils.java | 16 ++++++-- 4 files changed, 52 insertions(+), 14 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 23334d6f3..bf64b4f08 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -72,6 +72,7 @@ import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.latin.LocaleUtils.RunInLocale; +import com.android.inputmethod.latin.Utils.Stats; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.suggestions.SuggestionStripView; import com.android.inputmethod.research.ResearchLogger; @@ -148,7 +149,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private boolean mIsUserDictionaryAvailable; private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; - private WordComposer mWordComposer = new WordComposer(); + private final WordComposer mWordComposer = new WordComposer(); private RichInputConnection mConnection = new RichInputConnection(this); // Keep track of the last selection range to decide if we need to show word alternatives @@ -1331,6 +1332,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); } else { if (SPACE_STATE_PHANTOM == spaceState) { + if (ProductionFlag.IS_INTERNAL) { + if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) { + Stats.onAutoCorrection( + "", mWordComposer.getTypedWord(), " ", mWordComposer); + } + } commitTyped(LastComposedWord.NOT_A_SEPARATOR); } final int keyX, keyY; @@ -1389,6 +1396,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onStartBatchInput() { mConnection.beginBatchEdit(); if (mWordComposer.isComposingWord()) { + if (ProductionFlag.IS_INTERNAL) { + if (mWordComposer.isBatchMode()) { + Stats.onAutoCorrection("", mWordComposer.getTypedWord(), " ", mWordComposer); + } + } commitTyped(LastComposedWord.NOT_A_SEPARATOR); mExpectingUpdateSelection = true; // The following is necessary for the case where the user typed something but didn't @@ -1547,7 +1559,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } else { if (mLastComposedWord.canRevertCommit()) { - Utils.Stats.onAutoCorrectionCancellation(); + if (ProductionFlag.IS_INTERNAL) { + Stats.onAutoCorrectionCancellation(); + } revertCommit(); return; } @@ -1696,7 +1710,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (null != mSuggestionStripView) mSuggestionStripView.dismissAddToDictionaryHint(); } mHandler.postUpdateSuggestionStrip(); - Utils.Stats.onNonSeparator((char)primaryCode, x, y); + if (ProductionFlag.IS_INTERNAL) { + Utils.Stats.onNonSeparator((char)primaryCode, x, y); + } } // Returns true if we did an autocorrection, false otherwise. @@ -1760,8 +1776,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // already displayed or not, so it's okay. setPunctuationSuggestions(); } - - Utils.Stats.onSeparator((char)primaryCode, x, y); + if (ProductionFlag.IS_INTERNAL) { + Utils.Stats.onSeparator((char)primaryCode, x, y); + } mHandler.postUpdateShiftState(); return didAutoCorrect; @@ -1930,7 +1947,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen throw new RuntimeException("We have an auto-correction but the typed word " + "is empty? Impossible! I must commit suicide."); } - Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorString); + if (ProductionFlag.IS_INTERNAL) { + Stats.onAutoCorrection( + typedWord, autoCorrection.toString(), separatorString, mWordComposer); + } mExpectingUpdateSelection = true; commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separatorString); @@ -2020,8 +2040,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // If the suggestion is not in the dictionary, the hint should be shown. && !AutoCorrection.isValidWord(mSuggest.getUnigramDictionaries(), suggestion, true); - Utils.Stats.onSeparator((char)Keyboard.CODE_SPACE, - Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + if (ProductionFlag.IS_INTERNAL) { + Stats.onSeparator((char)Keyboard.CODE_SPACE, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + } if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) { mSuggestionStripView.showAddToDictionaryHint( suggestion, mCurrentSettings.mHintToSaveText); @@ -2138,8 +2160,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen previousWord.toString(), committedWord.toString()); } mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1); - Utils.Stats.onSeparator(mLastComposedWord.mSeparatorString, - Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + if (ProductionFlag.IS_INTERNAL) { + Stats.onSeparator(mLastComposedWord.mSeparatorString, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIME_revertCommit(originallyTypedWord); } diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index a5b4c68d0..9eab19c49 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -49,7 +49,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang } public static void logOnAutoCorrectionForGeometric(String before, String after, - int separatorCode, int[] xCoordinates, int[] yCoordinates, int[] relativeTimes) { + int separatorCode, InputPointers inputPointers) { } public static void logOnAutoCorrectionCancelled() { diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 0418d3166..278c4b9ce 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -306,6 +306,10 @@ public class Suggest { wordComposer, prevWordForBigram, proximityInfo, sessionId)); } + for (SuggestedWordInfo wordInfo : suggestionsSet) { + LatinImeLogger.onAddSuggestedWord(wordInfo.mWord.toString(), wordInfo.mSourceDict); + } + final ArrayList suggestionsContainer = CollectionUtils.newArrayList(suggestionsSet); final int suggestionsCount = suggestionsContainer.size(); diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 63b642821..876bc8e79 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -412,14 +412,24 @@ public final class Utils { } public static void onAutoCorrection(final String typedWord, final String correctedWord, - final String separatorString) { - if (TextUtils.isEmpty(typedWord)) return; + final String separatorString, final WordComposer wordComposer) { + final boolean isBatchMode = wordComposer.isBatchMode(); + if (!isBatchMode && TextUtils.isEmpty(typedWord)) return; // TODO: this fails when the separator is more than 1 code point long, but // the backend can't handle it yet. The only case when this happens is with // smileys and other multi-character keys. final int codePoint = TextUtils.isEmpty(separatorString) ? Constants.NOT_A_CODE : separatorString.codePointAt(0); - LatinImeLogger.logOnAutoCorrectionForTyping(typedWord, correctedWord, codePoint); + if (!isBatchMode) { + LatinImeLogger.logOnAutoCorrectionForTyping(typedWord, correctedWord, codePoint); + } else { + if (!TextUtils.isEmpty(correctedWord)) { + // We must make sure that InputPointer contains only the relative timestamps, + // not actual timestamps. + LatinImeLogger.logOnAutoCorrectionForGeometric( + "", correctedWord, codePoint, wordComposer.getInputPointers()); + } + } } public static void onAutoCorrectionCancellation() { -- cgit v1.2.3-83-g751a From ad0642cf258ca9b123f74ca0ae8bf970792908f1 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 19 Sep 2012 12:52:06 +0900 Subject: Fix a bug that would persist caps lock state ...with regards to suggestions. It's much simpler to look at whether the word is actually all capitalized or not. Bug: 7113544 Change-Id: Idc0e77b2f812964e650ade0e32b9d4c09228cb74 --- java/src/com/android/inputmethod/latin/WordComposer.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 7785e3fb9..275ebf305 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -265,9 +265,12 @@ public class WordComposer { * @return true if all user typed chars are upper case, false otherwise */ public boolean isAllUpperCase() { - return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED - || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFT_LOCKED - || (mCapsCount > 1) && (mCapsCount == size()); + if (size() <= 1) { + return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED + || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFT_LOCKED; + } else { + return mCapsCount == size(); + } } public boolean wasShiftedNoLock() { -- cgit v1.2.3-83-g751a From 4f8e451d0c5bb522eedc00a30f7b519ccfe5b704 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 19 Sep 2012 18:12:39 +0900 Subject: Show gesture floating preview text is off by default Bug: 7043127 Change-Id: Icabf080f43a5934fef3824919bb03229522d5e5a --- java/res/xml/prefs.xml | 4 +-- .../keyboard/internal/PreviewPlacerView.java | 32 ++++++++++++++-------- .../com/android/inputmethod/latin/Settings.java | 8 +++--- .../android/inputmethod/latin/SettingsValues.java | 2 +- 4 files changed, 27 insertions(+), 19 deletions(-) (limited to 'java/src') diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index ef6be3eed..f7c993d9d 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -138,11 +138,11 @@ android:persistent="true" android:defaultValue="true" /> + android:defaultValue="false" /> diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java index 3a850096f..915ce1f36 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java @@ -189,22 +189,29 @@ public class PreviewPlacerView extends RelativeLayout { } public void invalidatePointer(final PointerTracker tracker, final boolean isOldestTracker) { - GesturePreviewTrail trail; - synchronized (mGesturePreviewTrails) { - trail = mGesturePreviewTrails.get(tracker.mPointerId); - if (trail == null) { - trail = new GesturePreviewTrail(); - mGesturePreviewTrails.put(tracker.mPointerId, trail); - } - } - trail.addStroke(tracker.getGestureStrokeWithPreviewTrail(), tracker.getDownTime()); - - if (isOldestTracker) { + final boolean needsToUpdateLastPointer = + isOldestTracker && mDrawsGestureFloatingPreviewText; + if (needsToUpdateLastPointer) { mLastPointerX = tracker.getLastX(); mLastPointerY = tracker.getLastY(); } + + if (mDrawsGesturePreviewTrail) { + GesturePreviewTrail trail; + synchronized (mGesturePreviewTrails) { + trail = mGesturePreviewTrails.get(tracker.mPointerId); + if (trail == null) { + trail = new GesturePreviewTrail(); + mGesturePreviewTrails.put(tracker.mPointerId, trail); + } + } + trail.addStroke(tracker.getGestureStrokeWithPreviewTrail(), tracker.getDownTime()); + } + // TODO: Should narrow the invalidate region. - invalidate(); + if (mDrawsGesturePreviewTrail || needsToUpdateLastPointer) { + invalidate(); + } } @Override @@ -262,6 +269,7 @@ public class PreviewPlacerView extends RelativeLayout { } public void setGestureFloatingPreviewText(final String gestureFloatingPreviewText) { + if (!mDrawsGestureFloatingPreviewText) return; mGestureFloatingPreviewText = gestureFloatingPreviewText; invalidate(); } diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 180f6c56f..c2dec2593 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -77,8 +77,8 @@ public class Settings extends InputMethodSettingsFragment public static final String PREF_KEYPRESS_SOUND_VOLUME = "pref_keypress_sound_volume"; public static final String PREF_GESTURE_PREVIEW_TRAIL = "pref_gesture_preview_trail"; - public static final String PREF_GESTURE_FLOATING_PREVIEW_TEXT = - "pref_gesture_floating_preview_text"; + public static final String PREF_SHOW_GESTURE_FLOATING_PREVIEW_TEXT = + "pref_show_gesture_floating_preview_text"; public static final String PREF_INPUT_LANGUAGE = "input_language"; public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; @@ -207,7 +207,7 @@ public class Settings extends InputMethodSettingsFragment R.bool.config_gesture_input_enabled_by_build_config); final Preference gesturePreviewTrail = findPreference(PREF_GESTURE_PREVIEW_TRAIL); final Preference gestureFloatingPreviewText = findPreference( - PREF_GESTURE_FLOATING_PREVIEW_TEXT); + PREF_SHOW_GESTURE_FLOATING_PREVIEW_TEXT); if (!gestureInputEnabledByBuildConfig) { miscSettings.removePreference(findPreference(PREF_GESTURE_INPUT)); miscSettings.removePreference(gesturePreviewTrail); @@ -304,7 +304,7 @@ public class Settings extends InputMethodSettingsFragment PREF_GESTURE_INPUT, true); setPreferenceEnabled(findPreference(PREF_GESTURE_PREVIEW_TRAIL), gestureInputEnabledByUser); - setPreferenceEnabled(findPreference(PREF_GESTURE_FLOATING_PREVIEW_TEXT), + setPreferenceEnabled(findPreference(PREF_SHOW_GESTURE_FLOATING_PREVIEW_TEXT), gestureInputEnabledByUser); } } diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 5e9c870d4..d9cf2700b 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -178,7 +178,7 @@ public final class SettingsValues { && prefs.getBoolean(Settings.PREF_GESTURE_INPUT, true); mGesturePreviewTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true); mGestureFloatingPreviewTextEnabled = prefs.getBoolean( - Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true); + Settings.PREF_SHOW_GESTURE_FLOATING_PREVIEW_TEXT, false); mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect; mSuggestionVisibility = createSuggestionVisibility(res); } -- cgit v1.2.3-83-g751a From c7dc673cf0fb56015826079423ced659b9180feb Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Fri, 14 Sep 2012 18:10:39 +0900 Subject: Use Path to draw gesture preview trail This change also reduces the number of points to use as preview trail. Bug: 7167303 Change-Id: I0cf4908efa44b17b42d4fddd6725238236ac2654 --- .../inputmethod/keyboard/PointerTracker.java | 47 +++---- .../keyboard/internal/GesturePreviewTrail.java | 135 ++++++++++++++++++--- .../keyboard/internal/GestureStroke.java | 2 +- .../internal/GestureStrokeWithPreviewPoints.java | 97 +++++++++++++++ .../internal/GestureStrokeWithPreviewTrail.java | 70 ----------- .../keyboard/internal/PreviewPlacerView.java | 2 +- 6 files changed, 243 insertions(+), 110 deletions(-) create mode 100644 java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java delete mode 100644 java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index a6439c46a..2bde8d2c5 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -23,7 +23,7 @@ import android.view.MotionEvent; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.keyboard.internal.GestureStroke; -import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewTrail; +import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.InputPointers; @@ -208,7 +208,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { private static final KeyboardActionListener EMPTY_LISTENER = new KeyboardActionListener.Adapter(); - private final GestureStrokeWithPreviewTrail mGestureStrokeWithPreviewTrail; + private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints; public static void init(boolean hasDistinctMultitouch, boolean needsPhantomSuddenMoveEventHack) { @@ -293,7 +293,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { throw new NullPointerException(); } mPointerId = id; - mGestureStrokeWithPreviewTrail = new GestureStrokeWithPreviewTrail(id); + mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints(id); setKeyDetectorInner(handler.getKeyDetector()); mListener = handler.getKeyboardActionListener(); mDrawingProxy = handler.getDrawingProxy(); @@ -392,7 +392,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { private void setKeyDetectorInner(final KeyDetector keyDetector) { mKeyDetector = keyDetector; mKeyboard = keyDetector.getKeyboard(); - mGestureStrokeWithPreviewTrail.setGestureSampleLength(mKeyboard.mMostCommonKeyWidth); + mGestureStrokeWithPreviewPoints.setKeyboardGeometry(mKeyboard.mMostCommonKeyWidth); final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); if (newKey != mCurrentKey) { if (mDrawingProxy != null) { @@ -502,8 +502,8 @@ public class PointerTracker implements PointerTrackerQueue.Element { mDrawingProxy.invalidateKey(key); } - public GestureStrokeWithPreviewTrail getGestureStrokeWithPreviewTrail() { - return mGestureStrokeWithPreviewTrail; + public GestureStrokeWithPreviewPoints getGestureStrokeWithPreviewPoints() { + return mGestureStrokeWithPreviewPoints; } public int getLastX() { @@ -544,8 +544,8 @@ public class PointerTracker implements PointerTrackerQueue.Element { return (sPointerTrackerQueue == null) ? 1 : sPointerTrackerQueue.size(); } - private void startBatchInput() { - if (sInGesture || !mGestureStrokeWithPreviewTrail.isStartOfAGesture()) { + private void mayStartBatchInput() { + if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) { return; } if (DEBUG_LISTENER) { @@ -559,7 +559,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { private void updateBatchInput(final long eventTime) { synchronized (sAggregratedPointers) { - mGestureStrokeWithPreviewTrail.appendIncrementalBatchPoints(sAggregratedPointers); + mGestureStrokeWithPreviewPoints.appendIncrementalBatchPoints(sAggregratedPointers); final int size = sAggregratedPointers.getPointerSize(); if (size > sLastRecognitionPointSize && eventTime > sLastRecognitionTime + MIN_GESTURE_RECOGNITION_TIME) { @@ -575,10 +575,10 @@ public class PointerTracker implements PointerTrackerQueue.Element { mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); } - private void endBatchInput() { + private void mayEndBatchInput() { synchronized (sAggregratedPointers) { - mGestureStrokeWithPreviewTrail.appendAllBatchPoints(sAggregratedPointers); - mGestureStrokeWithPreviewTrail.reset(); + mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); + mGestureStrokeWithPreviewPoints.reset(); if (getActivePointerTrackerCount() == 1) { if (DEBUG_LISTENER) { Log.d(TAG, "onEndBatchInput: batchPoints=" @@ -601,7 +601,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { final int trackersSize = sTrackers.size(); for (int i = 0; i < trackersSize; ++i) { final PointerTracker tracker = sTrackers.get(i); - tracker.mGestureStrokeWithPreviewTrail.reset(); + tracker.mGestureStrokeWithPreviewPoints.reset(); } sAggregratedPointers.reset(); sLastRecognitionPointSize = 0; @@ -678,18 +678,21 @@ public class PointerTracker implements PointerTrackerQueue.Element { && mKeyboard.mId.isAlphabetKeyboard(); if (isAlphabetKeyboard && !mIsShowingMoreKeysPanel && key != null && Keyboard.isLetterCode(key.mCode)) { - mIsDetectingGesture = true; sGestureFirstDownTime = eventTime; - mGestureStrokeWithPreviewTrail.addPoint(x, y, 0, false /* isHistorical */); + onGestureDownEvent(x, y, eventTime); } } else if (sInGesture && activePointerTrackerCount > 1) { - mIsDetectingGesture = true; - final int elapsedTimeFromFirstDown = (int)(eventTime - sGestureFirstDownTime); - mGestureStrokeWithPreviewTrail.addPoint(x, y, elapsedTimeFromFirstDown, - false /* isHistorical */); + onGestureDownEvent(x, y, eventTime); } } + private void onGestureDownEvent(final int x, final int y, final long eventTime) { + mIsDetectingGesture = true; + final int elapsedTimeFromFirstDown = (int)(eventTime - sGestureFirstDownTime); + mGestureStrokeWithPreviewPoints.addPoint(x, y, elapsedTimeFromFirstDown, + false /* isHistorical */); + } + private void onDownEventInternal(final int x, final int y, final long eventTime) { Key key = onDownKey(x, y, eventTime); // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding @@ -726,8 +729,8 @@ public class PointerTracker implements PointerTrackerQueue.Element { final boolean isHistorical, final Key key) { final int gestureTime = (int)(eventTime - sGestureFirstDownTime); if (mIsDetectingGesture) { - mGestureStrokeWithPreviewTrail.addPoint(x, y, gestureTime, isHistorical); - startBatchInput(); + mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isHistorical); + mayStartBatchInput(); if (sInGesture && key != null) { updateBatchInput(eventTime); } @@ -919,7 +922,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { if (currentKey != null) { callListenerOnRelease(currentKey, currentKey.mCode, true); } - endBatchInput(); + mayEndBatchInput(); return; } // This event will be recognized as a regular code input. Clear unused possible batch points diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java index 4311fa775..699aaeaef 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java @@ -17,7 +17,9 @@ package com.android.inputmethod.keyboard.internal; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.Rect; +import android.graphics.RectF; import android.os.SystemClock; import com.android.inputmethod.latin.Constants; @@ -25,7 +27,7 @@ import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.ResizableIntArray; final class GesturePreviewTrail { - private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewTrail.PREVIEW_CAPACITY; + private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewPoints.PREVIEW_CAPACITY; private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); @@ -78,7 +80,7 @@ final class GesturePreviewTrail { ? DOWN_EVENT_MARKER - xCoordOrMark : xCoordOrMark; } - public void addStroke(final GestureStrokeWithPreviewTrail stroke, final long downTime) { + public void addStroke(final GestureStrokeWithPreviewPoints stroke, final long downTime) { final int trailSize = mEventTimes.getLength(); stroke.appendPreviewStroke(mEventTimes, mXCoordinates, mYCoordinates); if (mEventTimes.getLength() == trailSize) { @@ -116,6 +118,99 @@ final class GesturePreviewTrail { / params.mTrailLingerDuration, 0.0f); } + static final class WorkingSet { + // Input + // Previous point (P1) coordinates and trail radius. + public float p1x, p1y; + public float r1; + // Current point (P2) coordinates and trail radius. + public float p2x, p2y; + public float r2; + + // Output + // Closing point of arc at P1. + public float p1ax, p1ay; + // Opening point of arc at P1. + public float p1bx, p1by; + // Opening point of arc at P2. + public float p2ax, p2ay; + // Closing point of arc at P2. + public float p2bx, p2by; + // Start angle of the trail arcs. + public float aa; + // Sweep angle of the trail arc at P1. + public float a1; + public RectF arc1 = new RectF(); + // Sweep angle of the trail arc at P2. + public float a2; + public RectF arc2 = new RectF(); + } + + private static final float RIGHT_ANGLE = (float)(Math.PI / 2.0d); + private static final float RADIAN_TO_DEGREE = (float)(180.0d / Math.PI); + + private static boolean calculatePathPoints(final WorkingSet w) { + final float dx = w.p2x - w.p1x; + final float dy = w.p2y - w.p1y; + // Distance of the points. + final double l = Math.hypot(dx, dy); + if (Double.compare(0.0d, l) == 0) { + return false; + } + // Angle of the line p1-p2 + final float a = (float)Math.atan2(dy, dx); + // Difference of trail cap radius. + final float dr = w.r2 - w.r1; + // Variation of angle at trail cap. + final float ar = (float)Math.asin(dr / l); + // The start angle of trail cap arc at P1. + final float aa = a - (RIGHT_ANGLE + ar); + // The end angle of trail cap arc at P2. + final float ab = a + (RIGHT_ANGLE + ar); + final float cosa = (float)Math.cos(aa); + final float sina = (float)Math.sin(aa); + final float cosb = (float)Math.cos(ab); + final float sinb = (float)Math.sin(ab); + w.p1ax = w.p1x + w.r1 * cosa; + w.p1ay = w.p1y + w.r1 * sina; + w.p1bx = w.p1x + w.r1 * cosb; + w.p1by = w.p1y + w.r1 * sinb; + w.p2ax = w.p2x + w.r2 * cosa; + w.p2ay = w.p2y + w.r2 * sina; + w.p2bx = w.p2x + w.r2 * cosb; + w.p2by = w.p2y + w.r2 * sinb; + w.aa = aa * RADIAN_TO_DEGREE; + final float ar2degree = ar * 2.0f * RADIAN_TO_DEGREE; + w.a1 = -180.0f + ar2degree; + w.a2 = 180.0f + ar2degree; + w.arc1.set(w.p1x, w.p1y, w.p1x, w.p1y); + w.arc1.inset(-w.r1, -w.r1); + w.arc2.set(w.p2x, w.p2y, w.p2x, w.p2y); + w.arc2.inset(-w.r2, -w.r2); + return true; + } + + private static void createPath(final Path path, final WorkingSet w) { + path.rewind(); + // Trail cap at P1. + path.moveTo(w.p1x, w.p1y); + path.arcTo(w.arc1, w.aa, w.a1); + // Trail cap at P2. + path.moveTo(w.p2x, w.p2y); + path.arcTo(w.arc2, w.aa, w.a2); + // Two trapezoids connecting P1 and P2. + path.moveTo(w.p1ax, w.p1ay); + path.lineTo(w.p1x, w.p1y); + path.lineTo(w.p1bx, w.p1by); + path.lineTo(w.p2bx, w.p2by); + path.lineTo(w.p2x, w.p2y); + path.lineTo(w.p2ax, w.p2ay); + path.close(); + } + + private final WorkingSet mWorkingSet = new WorkingSet(); + private final Path mPath = new Path(); + /** * Draw gesture preview trail * @param canvas The canvas to draw the gesture preview trail @@ -147,30 +242,38 @@ final class GesturePreviewTrail { if (startIndex < trailSize) { paint.setColor(params.mTrailColor); - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeCap(Paint.Cap.ROUND); - int lastX = getXCoordValue(xCoords[startIndex]); - int lastY = yCoords[startIndex]; - float maxWidth = getWidth(sinceDown - eventTimes[startIndex], params); + paint.setStyle(Paint.Style.FILL); + final Path path = mPath; + final WorkingSet w = mWorkingSet; + w.p1x = getXCoordValue(xCoords[startIndex]); + w.p1y = yCoords[startIndex]; + int lastTime = sinceDown - eventTimes[startIndex]; + float maxWidth = getWidth(lastTime, params); + w.r1 = maxWidth / 2.0f; // Initialize bounds rectangle. - outBoundsRect.set(lastX, lastY, lastX, lastY); + outBoundsRect.set((int)w.p1x, (int)w.p1y, (int)w.p1x, (int)w.p1y); for (int i = startIndex + 1; i < trailSize - 1; i++) { - final int x = xCoords[i]; - final int y = yCoords[i]; final int elapsedTime = sinceDown - eventTimes[i]; + w.p2x = getXCoordValue(xCoords[i]); + w.p2y = yCoords[i]; // Draw trail line only when the current point isn't a down point. - if (!isDownEventXCoord(x)) { + if (!isDownEventXCoord(xCoords[i])) { final int alpha = getAlpha(elapsedTime, params); paint.setAlpha(alpha); final float width = getWidth(elapsedTime, params); - paint.setStrokeWidth(width); - canvas.drawLine(lastX, lastY, x, y, paint); + w.r2 = width / 2.0f; + if (calculatePathPoints(w)) { + createPath(path, w); + canvas.drawPath(path, paint); + outBoundsRect.union((int)w.p2x, (int)w.p2y); + } // Take union for the bounds. - outBoundsRect.union(x, y); maxWidth = Math.max(maxWidth, width); } - lastX = getXCoordValue(x); - lastY = y; + w.p1x = w.p2x; + w.p1y = w.p2y; + w.r1 = w.r2; + lastTime = elapsedTime; } // Take care of trail line width. final int inset = -((int)maxWidth + 1); diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java index 7a8c2409c..093a530d5 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java @@ -44,7 +44,7 @@ public class GestureStroke { mPointerId = pointerId; } - public void setGestureSampleLength(final int keyWidth) { + public void setKeyboardGeometry(final int keyWidth) { // TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key? mMinGestureLength = (int)(keyWidth * MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH); mMinGestureSampleLength = (int)(keyWidth * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH); diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java new file mode 100644 index 000000000..ce3914076 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java @@ -0,0 +1,97 @@ +/* + * 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.keyboard.internal; + +import com.android.inputmethod.latin.ResizableIntArray; + +public class GestureStrokeWithPreviewPoints extends GestureStroke { + public static final int PREVIEW_CAPACITY = 256; + + private final ResizableIntArray mPreviewEventTimes = new ResizableIntArray(PREVIEW_CAPACITY); + private final ResizableIntArray mPreviewXCoordinates = new ResizableIntArray(PREVIEW_CAPACITY); + private final ResizableIntArray mPreviewYCoordinates = new ResizableIntArray(PREVIEW_CAPACITY); + + private int mStrokeId; + private int mLastPreviewSize; + + private int mMinPreviewSampleLengthSquare; + private int mLastX; + private int mLastY; + + // TODO: Move this to resource. + private static final float MIN_PREVIEW_SAMPLE_LENGTH_RATIO_TO_KEY_WIDTH = 0.1f; + + public GestureStrokeWithPreviewPoints(final int pointerId) { + super(pointerId); + } + + @Override + public void reset() { + super.reset(); + mStrokeId++; + mLastPreviewSize = 0; + mPreviewEventTimes.setLength(0); + mPreviewXCoordinates.setLength(0); + mPreviewYCoordinates.setLength(0); + } + + public int getGestureStrokeId() { + return mStrokeId; + } + + public int getGestureStrokePreviewSize() { + return mPreviewEventTimes.getLength(); + } + + @Override + public void setKeyboardGeometry(final int keyWidth) { + super.setKeyboardGeometry(keyWidth); + final float sampleLength = keyWidth * MIN_PREVIEW_SAMPLE_LENGTH_RATIO_TO_KEY_WIDTH; + mMinPreviewSampleLengthSquare = (int)(sampleLength * sampleLength); + } + + private boolean needsSampling(final int x, final int y) { + final int dx = x - mLastX; + final int dy = y - mLastY; + final boolean needsSampling = (dx * dx + dy * dy >= mMinPreviewSampleLengthSquare); + if (needsSampling) { + mLastX = x; + mLastY = y; + } + return needsSampling; + } + + @Override + public void addPoint(final int x, final int y, final int time, final boolean isHistorical) { + super.addPoint(x, y, time, isHistorical); + if (mPreviewEventTimes.getLength() == 0 || isHistorical || needsSampling(x, y)) { + mPreviewEventTimes.add(time); + mPreviewXCoordinates.add(x); + mPreviewYCoordinates.add(y); + } + } + + public void appendPreviewStroke(final ResizableIntArray eventTimes, + final ResizableIntArray xCoords, final ResizableIntArray yCoords) { + final int length = mPreviewEventTimes.getLength() - mLastPreviewSize; + if (length <= 0) { + return; + } + eventTimes.append(mPreviewEventTimes, mLastPreviewSize, length); + xCoords.append(mPreviewXCoordinates, mLastPreviewSize, length); + yCoords.append(mPreviewYCoordinates, mLastPreviewSize, length); + mLastPreviewSize = mPreviewEventTimes.getLength(); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java deleted file mode 100644 index 6c1a9bc01..000000000 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewTrail.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.keyboard.internal; - -import com.android.inputmethod.latin.ResizableIntArray; - -public class GestureStrokeWithPreviewTrail extends GestureStroke { - public static final int PREVIEW_CAPACITY = 256; - - private final ResizableIntArray mPreviewEventTimes = new ResizableIntArray(PREVIEW_CAPACITY); - private final ResizableIntArray mPreviewXCoordinates = new ResizableIntArray(PREVIEW_CAPACITY); - private final ResizableIntArray mPreviewYCoordinates = new ResizableIntArray(PREVIEW_CAPACITY); - - private int mStrokeId; - private int mLastPreviewSize; - - public GestureStrokeWithPreviewTrail(final int pointerId) { - super(pointerId); - } - - @Override - public void reset() { - super.reset(); - mStrokeId++; - mLastPreviewSize = 0; - mPreviewEventTimes.setLength(0); - mPreviewXCoordinates.setLength(0); - mPreviewYCoordinates.setLength(0); - } - - public int getGestureStrokeId() { - return mStrokeId; - } - - public int getGestureStrokePreviewSize() { - return mPreviewEventTimes.getLength(); - } - - @Override - public void addPoint(final int x, final int y, final int time, final boolean isHistorical) { - super.addPoint(x, y, time, isHistorical); - mPreviewEventTimes.add(time); - mPreviewXCoordinates.add(x); - mPreviewYCoordinates.add(y); - } - - public void appendPreviewStroke(final ResizableIntArray eventTimes, - final ResizableIntArray xCoords, final ResizableIntArray yCoords) { - final int length = mPreviewEventTimes.getLength() - mLastPreviewSize; - if (length <= 0) { - return; - } - eventTimes.append(mPreviewEventTimes, mLastPreviewSize, length); - xCoords.append(mPreviewXCoordinates, mLastPreviewSize, length); - yCoords.append(mPreviewYCoordinates, mLastPreviewSize, length); - mLastPreviewSize = mPreviewEventTimes.getLength(); - } -} diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java index 915ce1f36..075a9bb0c 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java @@ -205,7 +205,7 @@ public class PreviewPlacerView extends RelativeLayout { mGesturePreviewTrails.put(tracker.mPointerId, trail); } } - trail.addStroke(tracker.getGestureStrokeWithPreviewTrail(), tracker.getDownTime()); + trail.addStroke(tracker.getGestureStrokeWithPreviewPoints(), tracker.getDownTime()); } // TODO: Should narrow the invalidate region. -- cgit v1.2.3-83-g751a From 17f7b406aa976ea147497dccac8e80c3aaaae370 Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Wed, 19 Sep 2012 20:03:13 +0900 Subject: Clear cache of user dic Change-Id: Iec2793de3fff7bf15f68f82a50331de7742b7049 --- .../AndroidWordLevelSpellCheckerSession.java | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index f4784ff1a..d9b622a18 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -16,6 +16,9 @@ package com.android.inputmethod.latin.spellcheck; +import android.content.ContentResolver; +import android.database.ContentObserver; +import android.provider.UserDictionary.Words; import android.service.textservice.SpellCheckerService.Session; import android.text.TextUtils; import android.util.Log; @@ -45,6 +48,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { private int mScript; // One of SCRIPT_LATIN or SCRIPT_CYRILLIC for now. private final AndroidSpellCheckerService mService; protected final SuggestionsCache mSuggestionsCache = new SuggestionsCache(); + private final ContentObserver mObserver; private static class SuggestionsParams { public final String[] mSuggestions; @@ -83,10 +87,23 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { mUnigramSuggestionsInfoCache.put( generateKey(query, prevWord), new SuggestionsParams(suggestions, flags)); } + + public void clearCache() { + mUnigramSuggestionsInfoCache.evictAll(); + } } AndroidWordLevelSpellCheckerSession(final AndroidSpellCheckerService service) { mService = service; + final ContentResolver cres = service.getContentResolver(); + + mObserver = new ContentObserver(null) { + @Override + public void onChange(boolean self) { + mSuggestionsCache.clearCache(); + } + }; + cres.registerContentObserver(Words.CONTENT_URI, true, mObserver); } @Override @@ -97,6 +114,12 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { mScript = AndroidSpellCheckerService.getScriptFromLocale(mLocale); } + @Override + public void onClose() { + final ContentResolver cres = mService.getContentResolver(); + cres.unregisterContentObserver(mObserver); + } + /* * Returns whether the code point is a letter that makes sense for the specified * locale for this spell checker. -- cgit v1.2.3-83-g751a From 1a4aa7e307e6090011449446c2c6770b6a0cc987 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 20 Sep 2012 10:32:56 +0900 Subject: Change to "Show language switch key" option This change deprecates "Suppress language switch key". Bug: 7037410 Change-Id: I1bc90877b4d2ee9364728959fd680dcb5b22ecbf --- java/res/values/strings.xml | 6 ++++-- java/res/xml/prefs.xml | 7 +++--- .../com/android/inputmethod/latin/Settings.java | 24 ++++++++++----------- .../android/inputmethod/latin/SettingsValues.java | 25 ++++++++++++++++------ 4 files changed, 39 insertions(+), 23 deletions(-) (limited to 'java/src') diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index bd60844a3..392a0705a 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -61,8 +61,10 @@ Switch to other input methods Language switch key covers other input methods too - - Suppress language switch key + + Language switch key + + Show when multiple input languages are enabled Key popup dismiss delay diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index f7c993d9d..3e83fc0fc 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -108,10 +108,11 @@ android:persistent="true" android:defaultValue="true" /> + android:defaultValue="true" /> Date: Thu, 20 Sep 2012 14:16:15 +0900 Subject: Move PointerTracker.MIN_GESTURE_RECOGNITION_TIME to GestureStroke Change-Id: Ib50192ed8f611fd8288ff9b7a1e0a19249cc6348 --- .../com/android/inputmethod/keyboard/PointerTracker.java | 4 +--- .../inputmethod/keyboard/internal/GestureStroke.java | 13 ++++++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 2bde8d2c5..03d610a39 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -47,8 +47,6 @@ public class PointerTracker implements PointerTrackerQueue.Element { private static boolean sGestureHandlingEnabledByInputField = false; private static boolean sGestureHandlingEnabledByUser = false; - private static final int MIN_GESTURE_RECOGNITION_TIME = 100; // msec - public interface KeyEventHandler { /** * Get KeyDetector object that is used for this PointerTracker. @@ -562,7 +560,7 @@ public class PointerTracker implements PointerTrackerQueue.Element { mGestureStrokeWithPreviewPoints.appendIncrementalBatchPoints(sAggregratedPointers); final int size = sAggregratedPointers.getPointerSize(); if (size > sLastRecognitionPointSize - && eventTime > sLastRecognitionTime + MIN_GESTURE_RECOGNITION_TIME) { + && GestureStroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) { sLastRecognitionPointSize = size; sLastRecognitionTime = eventTime; if (DEBUG_LISTENER) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java index 093a530d5..5ba57f565 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java @@ -36,10 +36,16 @@ public class GestureStroke { // TODO: Move some of these to resource. private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 0.75f; - private static final int MIN_GESTURE_DURATION = 100; // msec + private static final int MIN_GESTURE_START_DURATION = 100; // msec + private static final int MIN_GESTURE_RECOGNITION_TIME = 100; // msec private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH = 1.0f / 6.0f; private static final float GESTURE_RECOG_SPEED_THRESHOLD = 0.4f; // dip/msec + public static final boolean hasRecognitionTimePast( + final long currentTime, final long lastRecognitionTime) { + return currentTime > lastRecognitionTime + MIN_GESTURE_RECOGNITION_TIME; + } + public GestureStroke(final int pointerId) { mPointerId = pointerId; } @@ -53,7 +59,7 @@ public class GestureStroke { public boolean isStartOfAGesture() { final int size = mEventTimes.getLength(); final int downDuration = (size > 0) ? mEventTimes.get(size - 1) : 0; - return downDuration > MIN_GESTURE_DURATION && mLength > mMinGestureLength; + return downDuration > MIN_GESTURE_START_DURATION && mLength > mMinGestureLength; } public void reset() { @@ -97,7 +103,8 @@ public class GestureStroke { if (!isHistorical) { final int duration = (int)(time - mLastPointTime); if (mLastPointTime != 0 && duration > 0) { - final float speed = getDistance(mLastPointX, mLastPointY, x, y) / duration; + final float distance = getDistance(mLastPointX, mLastPointY, x, y); + final float speed = distance / duration; if (speed < GESTURE_RECOG_SPEED_THRESHOLD) { mIncrementalRecognitionSize = size; } -- cgit v1.2.3-83-g751a From b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 20 Sep 2012 15:52:40 +0900 Subject: Auto correct on gesture when typed word is 1 char long Bug: 7178462 Change-Id: I779d8ee4a957a9d1fdcc80d33257a98965dec7b8 --- java/src/com/android/inputmethod/latin/LatinIME.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index bf64b4f08..9252b0980 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1401,7 +1401,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen Stats.onAutoCorrection("", mWordComposer.getTypedWord(), " ", mWordComposer); } } - commitTyped(LastComposedWord.NOT_A_SEPARATOR); + if (mWordComposer.size() <= 1) { + // We auto-correct the previous (typed, not gestured) string iff it's one character + // long. The reason for this is, even in the middle of gesture typing, you'll still + // tap one-letter words and you want them auto-corrected (typically, "i" in English + // should become "I"). However for any longer word, we assume that the reason for + // tapping probably is that the word you intend to type is not in the dictionary, + // so we do not attempt to correct, on the assumption that if that was a dictionary + // word, the user would probably have gestured instead. + commitCurrentAutoCorrection(LastComposedWord.NOT_A_SEPARATOR); + } else { + commitTyped(LastComposedWord.NOT_A_SEPARATOR); + } mExpectingUpdateSelection = true; // The following is necessary for the case where the user typed something but didn't // manual pick it and didn't input any separator. -- cgit v1.2.3-83-g751a From d36245fad292ea660ca49f38a3ec36e07727dda5 Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Wed, 19 Sep 2012 14:38:17 +0900 Subject: Add getTerminalPosition. Change-Id: If04d779db23b1aea2cc12e5e9b8cecfcb35a5737 --- .../latin/makedict/BinaryDictIOUtils.java | 68 +++++++++++++++- .../latin/makedict/BinaryDictInputOutput.java | 5 +- .../inputmethod/latin/makedict/FormatSpec.java | 3 + .../latin/makedict/BinaryDictIOTests.java | 91 +++++++++++++++++++++- 4 files changed, 163 insertions(+), 4 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java index 1a85e71ce..7a1b9dcb7 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java @@ -16,10 +16,11 @@ package com.android.inputmethod.latin.makedict; -import com.android.inputmethod.latin.makedict.BinaryDictInputOutput; +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface; import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; +import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup; import java.io.IOException; import java.util.ArrayList; @@ -124,4 +125,69 @@ public class BinaryDictIOUtils { readUnigramsAndBigramsBinaryInner(buffer, header.mHeaderSize, words, frequencies, bigrams, header.mFormatOptions); } + + /** + * Gets the address of the last CharGroup of the exact matching word in the dictionary. + * If no match is found, returns NOT_VALID_WORD. + * + * @param buffer the buffer to read. + * @param word the word we search for. + * @return the address of the terminal node. + * @throws IOException + * @throws UnsupportedFormatException + */ + public static int getTerminalPosition(final FusionDictionaryBufferInterface buffer, + final String word) throws IOException, UnsupportedFormatException { + if (word == null) return FormatSpec.NOT_VALID_WORD; + if (buffer.position() != 0) buffer.position(0); + + final FileHeader header = BinaryDictInputOutput.readHeader(buffer); + int wordPos = 0; + final int wordLen = word.codePointCount(0, word.length()); + for (int depth = 0; depth < Constants.Dictionary.MAX_WORD_LENGTH; ++depth) { + if (wordPos >= wordLen) return FormatSpec.NOT_VALID_WORD; + int groupOffset = buffer.position() - header.mHeaderSize; + final int charGroupCount = BinaryDictInputOutput.readCharGroupCount(buffer); + groupOffset += BinaryDictInputOutput.getGroupCountSize(charGroupCount); + + for (int i = 0; i < charGroupCount; ++i) { + final int charGroupPos = buffer.position(); + final CharGroupInfo currentInfo = BinaryDictInputOutput.readCharGroup(buffer, + buffer.position(), header.mFormatOptions); + boolean same = true; + for (int p = 0, j = word.offsetByCodePoints(0, wordPos); + p < currentInfo.mCharacters.length; + ++p, j = word.offsetByCodePoints(j, 1)) { + if (wordPos + p >= wordLen + || word.codePointAt(j) != currentInfo.mCharacters[p]) { + same = false; + break; + } + } + + if (same) { + if (wordPos + currentInfo.mCharacters.length == wordLen) { + if (currentInfo.mFrequency == CharGroup.NOT_A_TERMINAL) { + return FormatSpec.NOT_VALID_WORD; + } else { + return charGroupPos; + } + } + wordPos += currentInfo.mCharacters.length; + if (currentInfo.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS) { + return FormatSpec.NOT_VALID_WORD; + } + buffer.position(currentInfo.mChildrenAddress); + break; + } + groupOffset = currentInfo.mEndAddress; + + // not found + if (i >= charGroupCount - 1) { + return FormatSpec.NOT_VALID_WORD; + } + } + } + return FormatSpec.NOT_VALID_WORD; + } } diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index c865702d6..1d3e94bb7 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -1242,8 +1242,9 @@ public class BinaryDictInputOutput { * @param formatOptions file format options. * @return the word, as a string. */ - private static String getWordAtAddress(final FusionDictionaryBufferInterface buffer, - final int headerSize, final int address, final FormatOptions formatOptions) { + /* packages for tests */ static String getWordAtAddress( + final FusionDictionaryBufferInterface buffer, final int headerSize, final int address, + final FormatOptions formatOptions) { final String cachedString = wordCache.get(address); if (null != cachedString) return cachedString; diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java index f8f13b197..adc6037bb 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java +++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java @@ -207,6 +207,9 @@ public final class FormatSpec { static final int MAX_TERMINAL_FREQUENCY = 255; static final int MAX_BIGRAM_FREQUENCY = 15; + // This option needs to be the same numeric value as the one in binary_format.h. + static final int NOT_VALID_WORD = -99; + /** * Options about file format. */ diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java index 4c2d3f6fe..24776d536 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java @@ -19,7 +19,7 @@ package com.android.inputmethod.latin.makedict; import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.UserHistoryDictIOUtils; import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface; -import com.android.inputmethod.latin.makedict.FormatSpec; +import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup; import com.android.inputmethod.latin.makedict.FusionDictionary.Node; import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; @@ -475,4 +475,93 @@ public class BinaryDictIOTests extends AndroidTestCase { Log.d(TAG, result); } } + + // Tests for getTerminalPosition + private String getWordFromBinary(final FusionDictionaryBufferInterface buffer, + final int address) { + if (buffer.position() != 0) buffer.position(0); + + FileHeader header = null; + try { + header = BinaryDictInputOutput.readHeader(buffer); + } catch (IOException e) { + return null; + } catch (UnsupportedFormatException e) { + return null; + } + if (header == null) return null; + return BinaryDictInputOutput.getWordAtAddress(buffer, header.mHeaderSize, + address - header.mHeaderSize, header.mFormatOptions); + } + + private long runGetTerminalPosition(final FusionDictionaryBufferInterface buffer, + final String word, int index, boolean contained) { + final int expectedFrequency = (UNIGRAM_FREQ + index) % 255; + long diff = -1; + int position = -1; + try { + final long now = System.nanoTime(); + position = BinaryDictIOUtils.getTerminalPosition(buffer, word); + diff = System.nanoTime() - now; + } catch (IOException e) { + Log.e(TAG, "IOException while getTerminalPosition: " + e); + } catch (UnsupportedFormatException e) { + Log.e(TAG, "UnsupportedFormatException while getTermianlPosition: " + e); + } + + assertEquals(FormatSpec.NOT_VALID_WORD != position, contained); + if (contained) assertEquals(getWordFromBinary(buffer, position), word); + return diff; + } + + public void testGetTerminalPosition() { + File file = null; + try { + file = File.createTempFile("runReadUnigrams", ".dict"); + } catch (IOException e) { + // do nothing + } + assertNotNull(file); + + final FusionDictionary dict = new FusionDictionary(new Node(), + new FusionDictionary.DictionaryOptions( + new HashMap(), false, false)); + addUnigrams(sWords.size(), dict, sWords, null /* shortcutMap */); + timeWritingDictToFile(file, dict, VERSION3_WITH_LINKEDLIST_NODE); + + final FusionDictionaryBufferInterface buffer = getBuffer(file, USE_BYTE_ARRAY); + + try { + // too long word + final String longWord = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; + assertEquals(FormatSpec.NOT_VALID_WORD, + BinaryDictIOUtils.getTerminalPosition(buffer, longWord)); + + // null + assertEquals(FormatSpec.NOT_VALID_WORD, + BinaryDictIOUtils.getTerminalPosition(buffer, null)); + + // empty string + assertEquals(FormatSpec.NOT_VALID_WORD, + BinaryDictIOUtils.getTerminalPosition(buffer, "")); + } catch (IOException e) { + } catch (UnsupportedFormatException e) { + } + + // Test a word that is contained within the dictionary. + long sum = 0; + for (int i = 0; i < sWords.size(); ++i) { + final long time = runGetTerminalPosition(buffer, sWords.get(i), i, true); + sum += time == -1 ? 0 : time; + } + Log.d(TAG, "per a search : " + (((double)sum) / sWords.size() / 1000000)); + + // Test a word that isn't contained within the dictionary. + final Random random = new Random((int)System.currentTimeMillis()); + for (int i = 0; i < 1000; ++i) { + final String word = generateWord(random.nextInt()); + if (sWords.indexOf(word) != -1) continue; + runGetTerminalPosition(buffer, word, i, false); + } + } } -- cgit v1.2.3-83-g751a From 77bcd6be3371104121fcb1fee22af44f072eda9c Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 20 Sep 2012 18:37:00 +0900 Subject: Fix stuck gesture floatin preview text Bug: 7192483 Change-Id: Ic62253180446a625330966a114a6fabf74ab4ec8 --- .../keyboard/internal/PreviewPlacerView.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java index 075a9bb0c..15170e040 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java @@ -46,7 +46,6 @@ public class PreviewPlacerView extends RelativeLayout { private final float mGestureFloatingPreviewHorizontalPadding; private final float mGestureFloatingPreviewVerticalPadding; private final float mGestureFloatingPreviewRoundRadius; - /* package */ final int mGestureFloatingPreviewTextLingerTimeout; private int mXOrigin; private int mYOrigin; @@ -78,11 +77,14 @@ public class PreviewPlacerView extends RelativeLayout { private static final int MSG_UPDATE_GESTURE_PREVIEW_TRAIL = 1; private final Params mGesturePreviewTrailParams; + private final int mGestureFloatingPreviewTextLingerTimeout; public DrawingHandler(final PreviewPlacerView outerInstance, - final Params gesturePreviewTrailParams) { + final Params gesturePreviewTrailParams, + final int getstureFloatinPreviewTextLinerTimeout) { super(outerInstance); mGesturePreviewTrailParams = gesturePreviewTrailParams; + mGestureFloatingPreviewTextLingerTimeout = getstureFloatinPreviewTextLinerTimeout; } @Override @@ -105,10 +107,8 @@ public class PreviewPlacerView extends RelativeLayout { public void dismissGestureFloatingPreviewText() { cancelDismissGestureFloatingPreviewText(); - final PreviewPlacerView placerView = getOuterInstance(); - sendMessageDelayed( - obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), - placerView.mGestureFloatingPreviewTextLingerTimeout); + sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), + mGestureFloatingPreviewTextLingerTimeout); } private void cancelUpdateGestureTrailPreview() { @@ -122,7 +122,6 @@ public class PreviewPlacerView extends RelativeLayout { } public void cancelAllMessages() { - cancelDismissGestureFloatingPreviewText(); cancelUpdateGestureTrailPreview(); } } @@ -151,12 +150,13 @@ public class PreviewPlacerView extends RelativeLayout { R.styleable.KeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f); mGestureFloatingPreviewRoundRadius = keyboardViewAttr.getDimension( R.styleable.KeyboardView_gestureFloatingPreviewRoundRadius, 0.0f); - mGestureFloatingPreviewTextLingerTimeout = keyboardViewAttr.getInt( + final int gestureFloatingPreviewTextLingerTimeout = keyboardViewAttr.getInt( R.styleable.KeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); mGesturePreviewTrailParams = new Params(keyboardViewAttr); keyboardViewAttr.recycle(); - mDrawingHandler = new DrawingHandler(this, mGesturePreviewTrailParams); + mDrawingHandler = new DrawingHandler(this, mGesturePreviewTrailParams, + gestureFloatingPreviewTextLingerTimeout); final Paint gesturePaint = new Paint(); gesturePaint.setAntiAlias(true); -- cgit v1.2.3-83-g751a From 61dcaaf17e4d1f9e941b961559a46823e6e25c99 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 20 Sep 2012 16:39:40 +0900 Subject: Use device independent parameter for gesture Change-Id: Iea95992e4482108a498f14ec595f3eacc7d7fc4b --- .../keyboard/internal/GestureStroke.java | 63 +++++++++++----------- 1 file changed, 32 insertions(+), 31 deletions(-) (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java index 5ba57f565..f0be0ee94 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java @@ -31,15 +31,18 @@ public class GestureStroke { private int mLastPointX; private int mLastPointY; - private int mMinGestureLength; - private int mMinGestureSampleLength; + private int mMinGestureLength; // pixel + private int mMinGestureSampleLength; // pixel + private int mGestureRecognitionThreshold; // pixel / sec // TODO: Move some of these to resource. private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 0.75f; private static final int MIN_GESTURE_START_DURATION = 100; // msec private static final int MIN_GESTURE_RECOGNITION_TIME = 100; // msec private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH = 1.0f / 6.0f; - private static final float GESTURE_RECOG_SPEED_THRESHOLD = 0.4f; // dip/msec + private static final float GESTURE_RECOGNITION_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH = + 5.5f; // keyWidth / sec + private static final int MSEC_PER_SEC = 1000; public static final boolean hasRecognitionTimePast( final long currentTime, final long lastRecognitionTime) { @@ -54,6 +57,8 @@ public class GestureStroke { // TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key? mMinGestureLength = (int)(keyWidth * MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH); mMinGestureSampleLength = (int)(keyWidth * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH); + mGestureRecognitionThreshold = + (int)(keyWidth * GESTURE_RECOGNITION_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH); } public boolean isStartOfAGesture() { @@ -72,45 +77,41 @@ public class GestureStroke { mYCoordinates.setLength(0); } - private void updateLastPoint(final int x, final int y, final int time) { - mLastPointTime = time; - mLastPointX = x; - mLastPointY = y; - } - public void addPoint(final int x, final int y, final int time, final boolean isHistorical) { + final boolean needsSampling; final int size = mEventTimes.getLength(); if (size == 0) { - mEventTimes.add(time); - mXCoordinates.add(x); - mYCoordinates.add(y); - if (!isHistorical) { - updateLastPoint(x, y, time); - } - return; + needsSampling = true; + } else { + final int lastIndex = size - 1; + final int lastX = mXCoordinates.get(lastIndex); + final int lastY = mYCoordinates.get(lastIndex); + final float dist = getDistance(lastX, lastY, x, y); + needsSampling = dist > mMinGestureSampleLength; + mLength += dist; } - - final int lastX = mXCoordinates.get(size - 1); - final int lastY = mYCoordinates.get(size - 1); - final float dist = getDistance(lastX, lastY, x, y); - if (dist > mMinGestureSampleLength) { + if (needsSampling) { mEventTimes.add(time); mXCoordinates.add(x); mYCoordinates.add(y); - mLength += dist; } - if (!isHistorical) { - final int duration = (int)(time - mLastPointTime); - if (mLastPointTime != 0 && duration > 0) { - final float distance = getDistance(mLastPointX, mLastPointY, x, y); - final float speed = distance / duration; - if (speed < GESTURE_RECOG_SPEED_THRESHOLD) { - mIncrementalRecognitionSize = size; - } + updateIncrementalRecognitionSize(x, y, time); + } + } + + private void updateIncrementalRecognitionSize(final int x, final int y, final int time) { + final int msecs = (int)(time - mLastPointTime); + if (msecs > 0) { + final int pixels = (int)getDistance(mLastPointX, mLastPointY, x, y); + // Equivalent to (pixels / msecs < mGestureRecognitionThreshold / MSEC_PER_SEC) + if (pixels * MSEC_PER_SEC < mGestureRecognitionThreshold * msecs) { + mIncrementalRecognitionSize = mEventTimes.getLength(); } - updateLastPoint(x, y, time); } + mLastPointTime = time; + mLastPointX = x; + mLastPointY = y; } public void appendAllBatchPoints(final InputPointers out) { -- cgit v1.2.3-83-g751a