diff options
Diffstat (limited to 'java/src')
10 files changed, 73 insertions, 21 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index f9e78bfd9..a2528e046 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -70,6 +70,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { public void startKeyRepeatTimerOf(PointerTracker tracker, int repeatCount, int delay); public void startLongPressTimerOf(PointerTracker tracker, int delay); public void cancelLongPressTimerOf(PointerTracker tracker); + public void cancelLongPressShiftKeyTimers(); public void cancelKeyTimersOf(PointerTracker tracker); public void startDoubleTapShiftKeyTimer(); public void cancelDoubleTapShiftKeyTimer(); @@ -90,6 +91,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { @Override public void cancelLongPressTimerOf(PointerTracker tracker) {} @Override + public void cancelLongPressShiftKeyTimers() {} + @Override public void cancelKeyTimersOf(PointerTracker tracker) {} @Override public void startDoubleTapShiftKeyTimer() {} @@ -1338,6 +1341,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } private void startLongPressTimer(final Key key) { + // Note that we need to cancel all active long press shift key timers if any whenever we + // start a new long press timer for both non-shift and shift keys. + sTimerProxy.cancelLongPressShiftKeyTimers(); if (sInGesture) return; if (key == null) return; if (!key.isLongPressEnabled()) return; @@ -1349,6 +1355,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (mIsInDraggingFinger && key.getMoreKeys() == null) return; final int delay = getLongPressTimeout(key.getCode()); + if (delay <= 0) return; sTimerProxy.startLongPressTimerOf(this, delay); } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index dd98c1703..0c80ce206 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -304,6 +304,7 @@ public final class KeyboardState { mSwitchActions.setSymbolsKeyboard(); mIsAlphabetMode = false; mIsSymbolShifted = false; + mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; // Reset alphabet shift state. mAlphabetShiftState.setShiftLocked(false); mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; @@ -316,6 +317,7 @@ public final class KeyboardState { mSwitchActions.setSymbolsShiftedKeyboard(); mIsAlphabetMode = false; mIsSymbolShifted = true; + mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; // Reset alphabet shift state. mAlphabetShiftState.setShiftLocked(false); mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; @@ -327,6 +329,7 @@ public final class KeyboardState { } mIsAlphabetMode = false; mIsEmojiMode = true; + mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; // Remember caps lock mode and reset alphabet shift state. mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked(); mAlphabetShiftState.setShiftLocked(false); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index 1b722c5ce..f708c2cdd 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -635,8 +635,8 @@ public final class KeyboardTextsSet { /* 118 */ "\\%,\u2030", }; - /* Language az: Azerbaijani */ - private static final String[] LANGUAGE_az = { + /* Language az_AZ: Azerbaijani (Azerbaijan) */ + private static final String[] LANGUAGE_az_AZ = { // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX /* 0 */ "\u00E2", // U+0259: "ə" LATIN SMALL LETTER SCHWA @@ -2454,8 +2454,8 @@ public final class KeyboardTextsSet { /* 53 */ "!text/double_9qm_rqm", }; - /* Language ne: Nepali */ - private static final String[] LANGUAGE_ne = { + /* Language ne_NP: Nepali (Nepal) */ + private static final String[] LANGUAGE_ne_NP = { /* 0~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, @@ -3519,7 +3519,7 @@ public final class KeyboardTextsSet { "DEFAULT", LANGUAGE_DEFAULT, /* default */ "af", LANGUAGE_af, /* Afrikaans */ "ar", LANGUAGE_ar, /* Arabic */ - "az", LANGUAGE_az, /* Azerbaijani */ + "az" /* "az_AZ" */, LANGUAGE_az_AZ, /* Azerbaijani (Azerbaijan) */ "be" /* "be_BY" */, LANGUAGE_be_BY, /* Belarusian (Belarus) */ "bg", LANGUAGE_bg, /* Bulgarian */ "ca", LANGUAGE_ca, /* Catalan */ @@ -3551,7 +3551,7 @@ public final class KeyboardTextsSet { "mk", LANGUAGE_mk, /* Macedonian */ "mn" /* "mn_MN" */, LANGUAGE_mn_MN, /* Mongolian (Mongolia) */ "nb", LANGUAGE_nb, /* Norwegian Bokmål */ - "ne", LANGUAGE_ne, /* Nepali */ + "ne" /* "ne_NP" */, LANGUAGE_ne_NP, /* Nepali (Nepal) */ "nl", LANGUAGE_nl, /* Dutch */ "pl", LANGUAGE_pl, /* Polish */ "pt", LANGUAGE_pt, /* Portuguese */ diff --git a/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java b/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java index 88d0878d1..3298a3f24 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java +++ b/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java @@ -38,8 +38,9 @@ public final class TimerHandler extends LeakGuardHandlerWrapper<Callbacks> imple private static final int MSG_TYPING_STATE_EXPIRED = 0; private static final int MSG_REPEAT_KEY = 1; private static final int MSG_LONGPRESS_KEY = 2; - private static final int MSG_DOUBLE_TAP_SHIFT_KEY = 3; - private static final int MSG_UPDATE_BATCH_INPUT = 4; + private static final int MSG_LONGPRESS_SHIFT_KEY = 3; + private static final int MSG_DOUBLE_TAP_SHIFT_KEY = 4; + private static final int MSG_UPDATE_BATCH_INPUT = 5; private final int mIgnoreAltCodeKeyTimeout; private final int mGestureRecognitionUpdateTime; @@ -66,6 +67,7 @@ public final class TimerHandler extends LeakGuardHandlerWrapper<Callbacks> imple tracker.onKeyRepeat(msg.arg1 /* code */, msg.arg2 /* repeatCount */); break; case MSG_LONGPRESS_KEY: + case MSG_LONGPRESS_SHIFT_KEY: cancelLongPressTimers(); callbacks.onLongPress(tracker); break; @@ -102,19 +104,31 @@ public final class TimerHandler extends LeakGuardHandlerWrapper<Callbacks> imple @Override public void startLongPressTimerOf(final PointerTracker tracker, final int delay) { - if (delay <= 0) { + final Key key = tracker.getKey(); + if (key == null) { return; } - sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay); + // Use a separate message id for long pressing shift key, because long press shift key + // timers should be canceled when other key is pressed. + final int messageId = (key.getCode() == Constants.CODE_SHIFT) + ? MSG_LONGPRESS_SHIFT_KEY : MSG_LONGPRESS_KEY; + sendMessageDelayed(obtainMessage(messageId, tracker), delay); } @Override public void cancelLongPressTimerOf(final PointerTracker tracker) { removeMessages(MSG_LONGPRESS_KEY, tracker); + removeMessages(MSG_LONGPRESS_SHIFT_KEY, tracker); + } + + @Override + public void cancelLongPressShiftKeyTimers() { + removeMessages(MSG_LONGPRESS_SHIFT_KEY); } private void cancelLongPressTimers() { removeMessages(MSG_LONGPRESS_KEY); + removeMessages(MSG_LONGPRESS_SHIFT_KEY); } @Override diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 0f7263d77..8b466559c 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1469,6 +1469,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert, false /* isBatchMode */); } + mWordComposer.doubleSpacePeriod(); mKeyboardSwitcher.updateShiftState(); return true; } @@ -1793,10 +1794,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); if (Character.isLetterOrDigit(codePointBeforeCursor) || currentSettingsValues.isUsuallyFollowedBySpace(codePointBeforeCursor)) { + final boolean autoShiftHasBeenOverriden = mKeyboardSwitcher.getKeyboardShiftMode() != + getCurrentAutoCapsState(); mSpaceState = SPACE_STATE_PHANTOM; + if (!autoShiftHasBeenOverriden) { + // When we change the space state, we need to update the shift state of the + // keyboard unless it has been overridden manually. This is happening for example + // after typing some letters and a period, then gesturing; the keyboard is not in + // caps mode yet, but since a gesture is starting, it should go in caps mode, + // unless the user explictly said it should not. + mKeyboardSwitcher.updateShiftState(); + } } mConnection.endBatchEdit(); - mKeyboardSwitcher.updateShiftState(); mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(getActualCapsMode(), // Prev word is 1st word before cursor getNthPreviousWordForSuggestion(currentSettingsValues, 1 /* nthPreviousWord */)); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 2f81d15d5..5ecfc67b2 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -471,7 +471,12 @@ public final class WordComposer { mCapsCount = 0; mDigitsCount = 0; mIsBatchMode = false; - mPreviousWord = mTypedWord.toString(); + final boolean isWhitespace = 1 == StringUtils.codePointCount(separatorString) + && Character.isWhitespace(separatorString.codePointAt(0)); + // If not whitespace, we don't use the previous word for suggestion. This is consistent + // with how we get the previous word for suggestion: see RichInputConnection#spaceRegex and + // LatinIME#getNthPreviousWordForSuggestion. + mPreviousWord = isWhitespace ? mTypedWord.toString() : null; mTypedWord.setLength(0); mCodePointSize = 0; mTrailingSingleQuotesCount = 0; @@ -485,6 +490,13 @@ public final class WordComposer { return lastComposedWord; } + public void doubleSpacePeriod() { + // When a period was entered with a double space, the separator we got has been + // changed by a period (see #commitWord). We should not use the previous word for + // suggestion. + mPreviousWord = null; + } + public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord, final String previousWord) { mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes; diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java index f23fe4656..af54805f7 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java +++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java @@ -188,7 +188,6 @@ public final class FormatSpec { // us to change the format during development while having testing devices remove // older files with each upgrade, while still having a readable versioning scheme. public static final int VERSION2 = 2; - public static final int VERSION3 = 3; public static final int VERSION4 = 400; static final int MINIMUM_SUPPORTED_VERSION = VERSION2; static final int MAXIMUM_SUPPORTED_VERSION = VERSION4; @@ -352,18 +351,19 @@ public final class FormatSpec { public static final String DICTIONARY_ID_ATTRIBUTE = "dictionary"; private static final String DICTIONARY_DESCRIPTION_ATTRIBUTE = "description"; public FileHeader(final int headerSize, final DictionaryOptions dictionaryOptions, - final FormatOptions formatOptions) { + final FormatOptions formatOptions) throws UnsupportedFormatException { mDictionaryOptions = dictionaryOptions; mFormatOptions = formatOptions; mBodyOffset = formatOptions.mVersion < VERSION4 ? headerSize : 0; if (null == getLocaleString()) { - throw new RuntimeException("Cannot create a FileHeader without a locale"); + throw new UnsupportedFormatException("Cannot create a FileHeader without a locale"); } if (null == getVersion()) { - throw new RuntimeException("Cannot create a FileHeader without a version"); + throw new UnsupportedFormatException( + "Cannot create a FileHeader without a version"); } if (null == getId()) { - throw new RuntimeException("Cannot create a FileHeader without an ID"); + throw new UnsupportedFormatException("Cannot create a FileHeader without an ID"); } } diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java index 665544228..e5430423d 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java @@ -68,7 +68,7 @@ public class Ver2DictEncoder implements DictEncoder { @Override public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions) throws IOException, UnsupportedFormatException { - if (formatOptions.mVersion > FormatSpec.VERSION3) { + if (formatOptions.mVersion > FormatSpec.VERSION2) { throw new UnsupportedFormatException( "The given format options has wrong version number : " + formatOptions.mVersion); diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java index a746f9945..8eaee4d9f 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java @@ -56,7 +56,8 @@ public class Ver4DictEncoder implements DictEncoder { } if (!BinaryDictionary.createEmptyDictFile(mDictPlacedDir.getAbsolutePath(), FormatSpec.VERSION4, dict.mOptions.mAttributes)) { - throw new IOException("Cannot create dictionary file"); + throw new IOException("Cannot create dictionary file : " + + mDictPlacedDir.getAbsolutePath()); } final BinaryDictionary binaryDict = new BinaryDictionary(mDictPlacedDir.getAbsolutePath(), 0l, mDictPlacedDir.length(), true /* useFullEditDistance */, diff --git a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java index b51fd9377..be0955456 100644 --- a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java @@ -40,12 +40,17 @@ public final class SpannableStringUtils { * are out of range in <code>dest</code>. */ public static void copyNonParagraphSuggestionSpansFrom(Spanned source, int start, int end, - Spannable dest, int destoff) { + Spannable dest, int destoff) { Object[] spans = source.getSpans(start, end, SuggestionSpan.class); for (int i = 0; i < spans.length; i++) { int fl = source.getSpanFlags(spans[i]); - if (0 != (fl & Spannable.SPAN_PARAGRAPH)) continue; + // We don't care about the PARAGRAPH flag in LatinIME code. However, if this flag + // is set, Spannable#setSpan will throw an exception unless the span is on the edge + // of a word. But the spans have been split into two by the getText{Before,After}Cursor + // methods, so after concatenation they may end in the middle of a word. + // Since we don't use them, we can just remove them and avoid crashing. + fl &= ~Spannable.SPAN_PARAGRAPH; int st = source.getSpanStart(spans[i]); int en = source.getSpanEnd(spans[i]); |