diff options
15 files changed, 100 insertions, 44 deletions
diff --git a/java/Android.mk b/java/Android.mk index b580624d7..9b8b2b448 100644 --- a/java/Android.mk +++ b/java/Android.mk @@ -25,7 +25,7 @@ LOCAL_CERTIFICATE := shared LOCAL_JNI_SHARED_LIBRARIES := libjni_latinime -LOCAL_STATIC_JAVA_LIBRARIES := android-common inputmethod-common android-support-v4 +LOCAL_STATIC_JAVA_LIBRARIES := android-common inputmethod-common android-support-v4 jsr305 # Do not compress dictionary files to mmap dict data runtime LOCAL_AAPT_FLAGS := -0 .dict diff --git a/java/src/com/android/inputmethod/event/Combiner.java b/java/src/com/android/inputmethod/event/Combiner.java index 8b808c6b3..fee93f0c6 100644 --- a/java/src/com/android/inputmethod/event/Combiner.java +++ b/java/src/com/android/inputmethod/event/Combiner.java @@ -18,6 +18,8 @@ package com.android.inputmethod.event; import java.util.ArrayList; +import javax.annotation.Nonnull; + /** * A generic interface for combiners. Combiners are objects that transform chains of input events * into committable strings and manage feedback to show to the user on the combining state. @@ -33,6 +35,7 @@ public interface Combiner { * @param event the event to combine with the existing state. * @return the resulting event. */ + @Nonnull Event processEvent(ArrayList<Event> previousEvents, Event event); /** diff --git a/java/src/com/android/inputmethod/event/CombinerChain.java b/java/src/com/android/inputmethod/event/CombinerChain.java index 61bc11b39..f69bf4fd0 100644 --- a/java/src/com/android/inputmethod/event/CombinerChain.java +++ b/java/src/com/android/inputmethod/event/CombinerChain.java @@ -24,6 +24,8 @@ import com.android.inputmethod.latin.Constants; import java.util.ArrayList; import java.util.HashMap; +import javax.annotation.Nonnull; + /** * This class implements the logic chain between receiving events and generating code points. * @@ -81,22 +83,29 @@ public class CombinerChain { } /** - * Pass a new event through the whole chain. + * Process an event through the combining chain, and return a processed event to apply. * @param previousEvents the list of previous events in this composition * @param newEvent the new event to process + * @return the processed event. It may be the same event, or a consumed event, or a completely + * new event. However it may never be null. */ - public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) { + @Nonnull + public Event processEvent(final ArrayList<Event> previousEvents, final Event newEvent) { final ArrayList<Event> modifiablePreviousEvents = new ArrayList<>(previousEvents); Event event = newEvent; for (final Combiner combiner : mCombiners) { // A combiner can never return more than one event; it can return several // code points, but they should be encapsulated within one event. event = combiner.processEvent(modifiablePreviousEvents, event); - if (null == event) { - // Combiners return null if they eat the event. - break; - } } + return event; + } + + /** + * Apply a processed event. + * @param event the event to be applied + */ + public void applyProcessedEvent(final Event event) { if (null != event) { // TODO: figure out the generic way of doing this if (Constants.CODE_DELETE == event.mKeyCode) { diff --git a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java index bef4d8594..d816247d8 100644 --- a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java +++ b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java @@ -23,6 +23,8 @@ import com.android.inputmethod.latin.Constants; import java.util.ArrayList; +import javax.annotation.Nonnull; + /** * A combiner that handles dead keys. */ @@ -31,13 +33,13 @@ public class DeadKeyCombiner implements Combiner { final StringBuilder mDeadSequence = new StringBuilder(); @Override + @Nonnull public Event processEvent(final ArrayList<Event> previousEvents, final Event event) { - if (null == event) return null; // Just in case some combiner is broken if (TextUtils.isEmpty(mDeadSequence)) { if (event.isDead()) { mDeadSequence.appendCodePoint(event.mCodePoint); } - return event; + return Event.createConsumedEvent(event); } else { // TODO: Allow combining for several dead chars rather than only the first one. // The framework doesn't know how to do this now. diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java index d257441e0..98c827423 100644 --- a/java/src/com/android/inputmethod/event/Event.java +++ b/java/src/com/android/inputmethod/event/Event.java @@ -67,6 +67,8 @@ public class Event { final private static int FLAG_DEAD = 0x1; // This event is coming from a key repeat, software or hardware. final private static int FLAG_REPEAT = 0x2; + // This event has already been consumed. + final private static int FLAG_CONSUMED = 0x4; final private int mEventType; // The type of event - one of the constants above // The code point associated with the event, if relevant. This is a unicode code point, and @@ -219,6 +221,17 @@ public class Event { null /* next */); } + /** + * Creates an event identical to the passed event, but that has already been consumed. + * @param source the event to copy the properties of. + * @return an identical event marked as consumed. + */ + public static Event createConsumedEvent(final Event source) { + return new Event(source.mEventType, source.mText, source.mCodePoint, source.mKeyCode, + source.mX, source.mY, source.mSuggestedWordInfo, source.mFlags | FLAG_CONSUMED, + source.mNextEvent); + } + public static Event createNotHandledEvent() { return new Event(EVENT_TYPE_NOT_HANDLED, null /* text */, NOT_A_CODE_POINT, NOT_A_KEY_CODE, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, @@ -241,6 +254,8 @@ public class Event { return 0 != (FLAG_REPEAT & mFlags); } + public boolean isConsumed() { return 0 != (FLAG_CONSUMED & mFlags); } + // Returns whether this is a fake key press from the suggestion strip. This happens with // punctuation signs selected from the suggestion strip. public boolean isSuggestionStripPress() { diff --git a/java/src/com/android/inputmethod/event/MyanmarReordering.java b/java/src/com/android/inputmethod/event/MyanmarReordering.java index 32919932d..dcd06c899 100644 --- a/java/src/com/android/inputmethod/event/MyanmarReordering.java +++ b/java/src/com/android/inputmethod/event/MyanmarReordering.java @@ -21,6 +21,8 @@ import com.android.inputmethod.latin.Constants; import java.util.ArrayList; import java.util.Arrays; +import javax.annotation.Nonnull; + /** * A combiner that reorders input for Myanmar. */ @@ -111,7 +113,7 @@ public class MyanmarReordering implements Combiner { * Clears the currently combining stream of events and returns the resulting software text * event corresponding to the stream. Optionally adds a new event to the cleared stream. * @param newEvent the new event to add to the stream. null if none. - * @return the resulting software text event. Null if none. + * @return the resulting software text event. Never null. */ private Event clearAndGetResultingEvent(final Event newEvent) { final CharSequence combinedText; @@ -124,18 +126,19 @@ public class MyanmarReordering implements Combiner { if (null != newEvent) { mCurrentEvents.add(newEvent); } - return null == combinedText ? null + return null == combinedText ? Event.createConsumedEvent(newEvent) : Event.createSoftwareTextEvent(combinedText, Event.NOT_A_KEY_CODE); } @Override + @Nonnull public Event processEvent(ArrayList<Event> previousEvents, Event newEvent) { final int codePoint = newEvent.mCodePoint; if (VOWEL_E == codePoint) { final Event lastEvent = getLastEvent(); if (null == lastEvent) { mCurrentEvents.add(newEvent); - return null; + return Event.createConsumedEvent(newEvent); } else if (isConsonantOrMedial(lastEvent.mCodePoint)) { final Event resultingEvent = clearAndGetResultingEvent(null); mCurrentEvents.add(Event.createSoftwareKeypressEvent(ZERO_WIDTH_NON_JOINER, @@ -151,7 +154,7 @@ public class MyanmarReordering implements Combiner { final Event lastEvent = getLastEvent(); if (null == lastEvent) { mCurrentEvents.add(newEvent); - return null; + return Event.createConsumedEvent(newEvent); } else if (VOWEL_E == lastEvent.mCodePoint) { final int eventSize = mCurrentEvents.size(); if (eventSize >= 2 @@ -162,7 +165,7 @@ public class MyanmarReordering implements Combiner { mCurrentEvents.remove(eventSize - 2); mCurrentEvents.add(newEvent); mCurrentEvents.add(lastEvent); - return null; + return Event.createConsumedEvent(newEvent); } // If there is already a consonant, then we are starting a new syllable. for (int i = eventSize - 2; i >= 0; --i) { @@ -174,7 +177,7 @@ public class MyanmarReordering implements Combiner { mCurrentEvents.remove(eventSize - 1); mCurrentEvents.add(newEvent); mCurrentEvents.add(lastEvent); - return null; + return Event.createConsumedEvent(newEvent); } else { // lastCodePoint is a consonant/medial. But if it's something else it's fine return clearAndGetResultingEvent(newEvent); } @@ -182,7 +185,7 @@ public class MyanmarReordering implements Combiner { final Event lastEvent = getLastEvent(); if (null == lastEvent) { mCurrentEvents.add(newEvent); - return null; + return Event.createConsumedEvent(newEvent); } else if (VOWEL_E == lastEvent.mCodePoint) { final int eventSize = mCurrentEvents.size(); // If there is already a consonant, then we are in the middle of a syllable, and we @@ -198,7 +201,7 @@ public class MyanmarReordering implements Combiner { mCurrentEvents.remove(eventSize - 1); mCurrentEvents.add(newEvent); mCurrentEvents.add(lastEvent); - return null; + return Event.createConsumedEvent(newEvent); } // Otherwise, we just commit everything. return clearAndGetResultingEvent(null); @@ -228,10 +231,10 @@ public class MyanmarReordering implements Combiner { mCurrentEvents.remove(eventSize - 1); } } - return null; + return Event.createConsumedEvent(newEvent); } else if (eventSize > 0) { mCurrentEvents.remove(eventSize - 1); - return null; + return Event.createConsumedEvent(newEvent); } } } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index cdd782244..3b6904847 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -25,6 +25,8 @@ import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Collections; +import javax.annotation.Nonnull; + /** * A place to store the currently composing word with information such as adjacent key codes as well */ @@ -175,20 +177,31 @@ public final class WordComposer { } /** - * Process an input event. + * Process an event and return an event, and return a processed event to apply. + * @param event the unprocessed event. + * @return the processed event. Never null, but may be marked as consumed. + */ + @Nonnull + public Event processEvent(final Event event) { + final Event processedEvent = mCombinerChain.processEvent(mEvents, event); + mEvents.add(event); + return processedEvent; + } + + /** + * Apply a processed input event. * * All input events should be supported, including software/hardware events, characters as well * as deletions, multiple inputs and gestures. * - * @param event the event to process. + * @param event the event to apply. Must not be null. */ - public void processEvent(final Event event) { + public void applyProcessedEvent(final Event event) { + mCombinerChain.applyProcessedEvent(event); final int primaryCode = event.mCodePoint; final int keyX = event.mX; final int keyY = event.mY; final int newIndex = size(); - mCombinerChain.processEvent(mEvents, event); - mEvents.add(event); refreshTypedWordCache(); mCursorPositionWithinWord = mCodePointSize; // We may have deleted the last one. @@ -281,7 +294,9 @@ public final class WordComposer { final int codePoint = Character.codePointAt(word, i); // We don't want to override the batch input points that are held in mInputPointers // (See {@link #add(int,int,int)}). - processEvent(Event.createEventForCodePointFromUnknownSource(codePoint)); + final Event processedEvent = + processEvent(Event.createEventForCodePointFromUnknownSource(codePoint)); + applyProcessedEvent(processedEvent); } } @@ -295,9 +310,11 @@ public final class WordComposer { reset(); final int length = codePoints.length; for (int i = 0; i < length; ++i) { - processEvent(Event.createEventForCodePointFromAlreadyTypedText(codePoints[i], + final Event processedEvent = + processEvent(Event.createEventForCodePointFromAlreadyTypedText(codePoints[i], CoordinateUtils.xFromArray(coordinates, i), CoordinateUtils.yFromArray(coordinates, i))); + applyProcessedEvent(processedEvent); } mIsResumed = true; } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 74d879919..bb2d304a6 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -762,7 +762,8 @@ public final class InputLogic { resetComposingState(false /* alsoResetLastComposedWord */); } if (isComposingWord) { - mWordComposer.processEvent(inputTransaction.mEvent); + final Event processedEvent = mWordComposer.processEvent(inputTransaction.mEvent); + mWordComposer.applyProcessedEvent(processedEvent); // If it's the first letter, make note of auto-caps state if (mWordComposer.isSingleLetter()) { mWordComposer.setCapitalizedModeAtStartComposingTime(inputTransaction.mShiftState); @@ -933,7 +934,8 @@ public final class InputLogic { mDictionaryFacilitator.removeWordFromPersonalizedDicts(rejectedSuggestion); } } else { - mWordComposer.processEvent(inputTransaction.mEvent); + final Event processedEvent = mWordComposer.processEvent(inputTransaction.mEvent); + mWordComposer.applyProcessedEvent(processedEvent); } if (mWordComposer.isComposingWord()) { mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); diff --git a/native/jni/src/suggest/core/layout/proximity_info_state.h b/native/jni/src/suggest/core/layout/proximity_info_state.h index 6b1a319aa..e6180fe17 100644 --- a/native/jni/src/suggest/core/layout/proximity_info_state.h +++ b/native/jni/src/suggest/core/layout/proximity_info_state.h @@ -215,13 +215,13 @@ class ProximityInfoState { std::vector<float> mSpeedRates; std::vector<float> mDirections; // probabilities of skipping or mapping to a key for each point. - std::vector<std::unordered_map<int, float> > mCharProbabilities; + std::vector<std::unordered_map<int, float>> mCharProbabilities; // The vector for the key code set which holds nearby keys of some trailing sampled input points // for each sampled input point. These nearby keys contain the next characters which can be in // the dictionary. Specifically, currently we are looking for keys nearby trailing sampled // inputs including the current input point. std::vector<ProximityInfoStateUtils::NearKeycodesSet> mSampledSearchKeySets; - std::vector<std::vector<int> > mSampledSearchKeyVectors; + std::vector<std::vector<int>> mSampledSearchKeyVectors; bool mTouchPositionCorrectionEnabled; int mInputProximities[MAX_PROXIMITY_CHARS_SIZE * MAX_WORD_LENGTH]; int mSampledInputSize; diff --git a/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp b/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp index ea3b02216..0aeb36aad 100644 --- a/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp +++ b/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp @@ -621,7 +621,7 @@ namespace latinime { const std::vector<int> *const sampledLengthCache, const std::vector<float> *const sampledNormalizedSquaredLengthCache, const ProximityInfo *const proximityInfo, - std::vector<std::unordered_map<int, float> > *charProbabilities) { + std::vector<std::unordered_map<int, float>> *charProbabilities) { charProbabilities->resize(sampledInputSize); // Calculates probabilities of using a point as a correlated point with the character // for each point. @@ -822,9 +822,9 @@ namespace latinime { /* static */ void ProximityInfoStateUtils::updateSampledSearchKeySets( const ProximityInfo *const proximityInfo, const int sampledInputSize, const int lastSavedInputSize, const std::vector<int> *const sampledLengthCache, - const std::vector<std::unordered_map<int, float> > *const charProbabilities, + const std::vector<std::unordered_map<int, float>> *const charProbabilities, std::vector<NearKeycodesSet> *sampledSearchKeySets, - std::vector<std::vector<int> > *sampledSearchKeyVectors) { + std::vector<std::vector<int>> *sampledSearchKeyVectors) { sampledSearchKeySets->resize(sampledInputSize); sampledSearchKeyVectors->resize(sampledInputSize); const int readForwordLength = static_cast<int>( @@ -868,7 +868,7 @@ namespace latinime { /* static */ bool ProximityInfoStateUtils::suppressCharProbabilities(const int mostCommonKeyWidth, const int sampledInputSize, const std::vector<int> *const lengthCache, const int index0, const int index1, - std::vector<std::unordered_map<int, float> > *charProbabilities) { + std::vector<std::unordered_map<int, float>> *charProbabilities) { ASSERT(0 <= index0 && index0 < sampledInputSize); ASSERT(0 <= index1 && index1 < sampledInputSize); const float keyWidthFloat = static_cast<float>(mostCommonKeyWidth); @@ -933,7 +933,7 @@ namespace latinime { // returns probability of generating the word. /* static */ float ProximityInfoStateUtils::getMostProbableString( const ProximityInfo *const proximityInfo, const int sampledInputSize, - const std::vector<std::unordered_map<int, float> > *const charProbabilities, + const std::vector<std::unordered_map<int, float>> *const charProbabilities, int *const codePointBuf) { ASSERT(sampledInputSize >= 0); memset(codePointBuf, 0, sizeof(codePointBuf[0]) * MAX_WORD_LENGTH); diff --git a/native/jni/src/suggest/core/layout/proximity_info_state_utils.h b/native/jni/src/suggest/core/layout/proximity_info_state_utils.h index 211a79737..4043334e6 100644 --- a/native/jni/src/suggest/core/layout/proximity_info_state_utils.h +++ b/native/jni/src/suggest/core/layout/proximity_info_state_utils.h @@ -72,13 +72,13 @@ class ProximityInfoStateUtils { const std::vector<int> *const sampledLengthCache, const std::vector<float> *const sampledNormalizedSquaredLengthCache, const ProximityInfo *const proximityInfo, - std::vector<std::unordered_map<int, float> > *charProbabilities); + std::vector<std::unordered_map<int, float>> *charProbabilities); static void updateSampledSearchKeySets(const ProximityInfo *const proximityInfo, const int sampledInputSize, const int lastSavedInputSize, const std::vector<int> *const sampledLengthCache, - const std::vector<std::unordered_map<int, float> > *const charProbabilities, + const std::vector<std::unordered_map<int, float>> *const charProbabilities, std::vector<NearKeycodesSet> *sampledSearchKeySets, - std::vector<std::vector<int> > *sampledSearchKeyVectors); + std::vector<std::vector<int>> *sampledSearchKeyVectors); static float getPointToKeyByIdLength(const float maxPointToKeyLength, const std::vector<float> *const sampledNormalizedSquaredLengthCache, const int keyCount, const int inputIndex, const int keyId); @@ -105,7 +105,7 @@ class ProximityInfoStateUtils { // TODO: Move to most_probable_string_utils.h static float getMostProbableString(const ProximityInfo *const proximityInfo, const int sampledInputSize, - const std::vector<std::unordered_map<int, float> > *const charProbabilities, + const std::vector<std::unordered_map<int, float>> *const charProbabilities, int *const codePointBuf); private: @@ -147,7 +147,7 @@ class ProximityInfoStateUtils { const int index2); static bool suppressCharProbabilities(const int mostCommonKeyWidth, const int sampledInputSize, const std::vector<int> *const lengthCache, const int index0, - const int index1, std::vector<std::unordered_map<int, float> > *charProbabilities); + const int index1, std::vector<std::unordered_map<int, float>> *charProbabilities); static float calculateSquaredDistanceFromSweetSpotCenter( const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs, const std::vector<int> *const sampledInputYs, const int keyIndex, diff --git a/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h b/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h index a61227626..6da390e55 100644 --- a/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h +++ b/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h @@ -30,7 +30,7 @@ namespace latinime { */ class DictionaryHeaderStructurePolicy { public: - typedef std::map<std::vector<int>, std::vector<int> > AttributeMap; + typedef std::map<std::vector<int>, std::vector<int>> AttributeMap; virtual ~DictionaryHeaderStructurePolicy() {} diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h index 3ff80aeec..9910777b8 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h @@ -84,7 +84,7 @@ class ForgettingCurveUtils { static const int STRONG_BASE_PROBABILITY; static const int AGGRESSIVE_BASE_PROBABILITY; - std::vector<std::vector<std::vector<int> > > mTables; + std::vector<std::vector<std::vector<int>>> mTables; static int getBaseProbabilityForLevel(const int tableId, const int level); }; diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk index e4de59db6..0f1f34418 100644 --- a/tools/dicttool/Android.mk +++ b/tools/dicttool/Android.mk @@ -88,6 +88,7 @@ LOCAL_SRC_FILES := $(LOCAL_TOOL_SRC_FILES) \ $(call all-java-files-under, $(DICTTOOL_ONDEVICE_TESTS_DIRECTORY)) LOCAL_JAVA_LIBRARIES := junit +LOCAL_STATIC_JAVA_LIBRARIES := jsr305lib LOCAL_REQUIRED_MODULES := $(LATINIME_HOST_NATIVE_LIBNAME) LOCAL_JAR_MANIFEST := etc/manifest.txt LOCAL_MODULE := dicttool_aosp diff --git a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java index 458f22c45..c4457a1b7 100644 --- a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java +++ b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java @@ -31,8 +31,12 @@ public class CombinerChain { mComposingWord = new StringBuilder(initialText); } - public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) { - mComposingWord.append(newEvent.getTextToCommit()); + public Event processEvent(final ArrayList<Event> previousEvents, final Event newEvent) { + return newEvent; + } + + public void applyProcessedEvent(final Event event) { + mComposingWord.append(event.getTextToCommit()); } public CharSequence getComposingWordWithCombiningFeedback() { |