diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 2fe9be203..22e2f266c 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -60,7 +60,6 @@ import helium314.keyboard.keyboard.KeyboardId; import helium314.keyboard.keyboard.KeyboardLayoutSet; import helium314.keyboard.keyboard.KeyboardSwitcher; import helium314.keyboard.keyboard.MainKeyboardView; -import helium314.keyboard.latin.Suggest.OnGetSuggestedWordsCallback; import helium314.keyboard.latin.SuggestedWords.SuggestedWordInfo; import helium314.keyboard.latin.common.ColorType; import helium314.keyboard.latin.common.Constants; @@ -129,6 +128,9 @@ public class LatinIME extends InputMethodService implements public final KeyboardActionListener mKeyboardActionListener; private int mOriginalNavBarColor = 0; private int mOriginalNavBarFlags = 0; + + // UIHandler is needed when creating InputLogic + public final UIHandler mHandler = new UIHandler(this); private final DictionaryFacilitator mDictionaryFacilitator = DictionaryFacilitatorProvider.getDictionaryFacilitator(false); final InputLogic mInputLogic = new InputLogic(this, this, mDictionaryFacilitator); @@ -187,8 +189,6 @@ public class LatinIME extends InputMethodService implements private final ClipboardHistoryManager mClipboardHistoryManager = new ClipboardHistoryManager(this); - public final UIHandler mHandler = new UIHandler(this); - public static final class UIHandler extends LeakGuardHandlerWrapper { private static final int MSG_UPDATE_SHIFT_STATE = 0; private static final int MSG_PENDING_IMS_CALLBACK = 1; @@ -796,14 +796,6 @@ public class LatinIME extends InputMethodService implements deallocateMemory(); } - public void recycle() { - unregisterReceiver(mDictionaryPackInstallReceiver); - unregisterReceiver(mDictionaryDumpBroadcastReceiver); - unregisterReceiver(mRingerModeChangeReceiver); - unregisterReceiver(mRestartAfterDeviceUnlockReceiver); - mInputLogic.recycle(); - } - private boolean isImeSuppressedByHardwareKeyboard() { final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance(); return !onEvaluateInputViewShown() && switcher.isImeSuppressedByHardwareKeyboard( @@ -1683,18 +1675,6 @@ public class LatinIME extends InputMethodService implements } } - // TODO[IL]: Move this out of LatinIME. - public void getSuggestedWords(final int inputStyle, final int sequenceNumber, - final OnGetSuggestedWordsCallback callback) { - final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); - if (keyboard == null) { - callback.onGetSuggestedWords(SuggestedWords.getEmptyInstance()); - return; - } - mInputLogic.getSuggestedWords(mSettings.getCurrent(), keyboard, - mKeyboardSwitcher.getKeyboardShiftMode(), inputStyle, sequenceNumber, callback); - } - @Override public void showSuggestionStrip(final SuggestedWords suggestedWords) { if (suggestedWords.isEmpty()) { diff --git a/app/src/main/java/helium314/keyboard/latin/Suggest.kt b/app/src/main/java/helium314/keyboard/latin/Suggest.kt index 3172acc6a..7e95cf6e2 100644 --- a/app/src/main/java/helium314/keyboard/latin/Suggest.kt +++ b/app/src/main/java/helium314/keyboard/latin/Suggest.kt @@ -45,19 +45,20 @@ class Suggest(private val mDictionaryFacilitator: DictionaryFacilitator) { mAutoCorrectionThreshold = threshold } + // todo: remove when InputLogic is ready interface OnGetSuggestedWordsCallback { fun onGetSuggestedWords(suggestedWords: SuggestedWords?) } fun getSuggestedWords(wordComposer: WordComposer, ngramContext: NgramContext, keyboard: Keyboard, settingsValuesForSuggestion: SettingsValuesForSuggestion, isCorrectionEnabled: Boolean, - inputStyle: Int, sequenceNumber: Int, callback: OnGetSuggestedWordsCallback) { - if (wordComposer.isBatchMode) { + inputStyle: Int, sequenceNumber: Int): SuggestedWords { + return if (wordComposer.isBatchMode) { getSuggestedWordsForBatchInput(wordComposer, ngramContext, keyboard, settingsValuesForSuggestion, - inputStyle, sequenceNumber, callback) + inputStyle, sequenceNumber) } else { getSuggestedWordsForNonBatchInput(wordComposer, ngramContext, keyboard, settingsValuesForSuggestion, - inputStyle, isCorrectionEnabled, sequenceNumber, callback) + inputStyle, isCorrectionEnabled, sequenceNumber) } } @@ -65,7 +66,7 @@ class Suggest(private val mDictionaryFacilitator: DictionaryFacilitator) { // and calls the callback function with the suggestions. private fun getSuggestedWordsForNonBatchInput(wordComposer: WordComposer, ngramContext: NgramContext, keyboard: Keyboard, settingsValuesForSuggestion: SettingsValuesForSuggestion, inputStyleIfNotPrediction: Int, - isCorrectionEnabled: Boolean, sequenceNumber: Int, callback: OnGetSuggestedWordsCallback) { + isCorrectionEnabled: Boolean, sequenceNumber: Int): SuggestedWords { val typedWordString = wordComposer.typedWord val resultsArePredictions = !wordComposer.isComposingWord val suggestionResults = if (typedWordString.isEmpty()) @@ -131,8 +132,8 @@ class Suggest(private val mDictionaryFacilitator: DictionaryFacilitator) { } } val isTypedWordValid = firstOccurrenceOfTypedWordInSuggestions > -1 || (!resultsArePredictions && !allowsToBeAutoCorrected) - callback.onGetSuggestedWords(SuggestedWords(suggestionsList, suggestionResults.mRawSuggestions, - typedWordInfo, isTypedWordValid, hasAutoCorrection, false, inputStyle, sequenceNumber)) + return SuggestedWords(suggestionsList, suggestionResults.mRawSuggestions, + typedWordInfo, isTypedWordValid, hasAutoCorrection, false, inputStyle, sequenceNumber) } // returns [allowsToBeAutoCorrected, hasAutoCorrection] @@ -252,9 +253,8 @@ class Suggest(private val mDictionaryFacilitator: DictionaryFacilitator) { wordComposer: WordComposer, ngramContext: NgramContext, keyboard: Keyboard, settingsValuesForSuggestion: SettingsValuesForSuggestion, - inputStyle: Int, sequenceNumber: Int, - callback: OnGetSuggestedWordsCallback - ) { + inputStyle: Int, sequenceNumber: Int + ): SuggestedWords { val suggestionResults = mDictionaryFacilitator.getSuggestionResults( wordComposer.composedDataSnapshot, ngramContext, keyboard, settingsValuesForSuggestion, SESSION_ID_GESTURE, inputStyle @@ -312,10 +312,8 @@ class Suggest(private val mDictionaryFacilitator: DictionaryFacilitator) { } else { suggestionsContainer } - callback.onGetSuggestedWords( - SuggestedWords(suggestionsList, suggestionResults.mRawSuggestions, pseudoTypedWordInfo, true, - false, false, inputStyle, sequenceNumber) - ) + return SuggestedWords(suggestionsList, suggestionResults.mRawSuggestions, pseudoTypedWordInfo, true, + false, false, inputStyle, sequenceNumber) } /** reduces score of the first suggestion if next one is close and has more than a single letter */ diff --git a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java index bb13d49a3..43958a5b7 100644 --- a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java +++ b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java @@ -44,6 +44,7 @@ import helium314.keyboard.latin.common.StringUtils; import helium314.keyboard.latin.common.StringUtilsKt; import helium314.keyboard.latin.common.SuggestionSpanUtilsKt; import helium314.keyboard.latin.define.DebugFlags; +import helium314.keyboard.latin.settings.Settings; import helium314.keyboard.latin.settings.SettingsValues; import helium314.keyboard.latin.settings.SpacingAndPunctuations; import helium314.keyboard.latin.suggestions.SuggestionStripViewAccessor; @@ -71,7 +72,7 @@ public final class InputLogic { final LatinIME mLatinIME; private final SuggestionStripViewAccessor mSuggestionStripViewAccessor; - @NonNull private InputLogicHandler mInputLogicHandler; + @NonNull private final InputLogicHandler mInputLogicHandler; // TODO : make all these fields private as soon as possible. // Current space state of the input method. This can be any of the above constants. @@ -119,7 +120,7 @@ public final class InputLogic { mSuggestionStripViewAccessor = suggestionStripViewAccessor; mWordComposer = new WordComposer(); mConnection = new RichInputConnection(latinIME); - mInputLogicHandler = InputLogicHandler.NULL_HANDLER; + mInputLogicHandler = new InputLogicHandler(mLatinIME.mHandler, this); mSuggest = new Suggest(dictionaryFacilitator); mDictionaryFacilitator = dictionaryFacilitator; } @@ -153,11 +154,7 @@ public final class InputLogic { // editorInfo.initialSelStart is not the actual cursor position, so we try using some heuristics to find the correct position. mConnection.tryFixIncorrectCursorPosition(); cancelDoubleSpacePeriodCountdown(); - if (InputLogicHandler.NULL_HANDLER == mInputLogicHandler) { - mInputLogicHandler = new InputLogicHandler(mLatinIME, this); - } else { - mInputLogicHandler.reset(); - } + mInputLogicHandler.reset(); mConnection.requestCursorUpdates(true, true); } @@ -200,17 +197,6 @@ public final class InputLogic { mInputLogicHandler.reset(); } - // Normally this class just gets out of scope after the process ends, but in unit tests, we - // create several instances of LatinIME in the same process, which results in several - // instances of InputLogic. This cleans up the associated handler so that tests don't leak - // handlers. - public void recycle() { - final InputLogicHandler inputLogicHandler = mInputLogicHandler; - mInputLogicHandler = InputLogicHandler.NULL_HANDLER; - inputLogicHandler.destroy(); - mDictionaryFacilitator.closeDictionaries(); - } - /** * React to a string input. *

@@ -1680,26 +1666,24 @@ public final class InputLogic { } final AsyncResultHolder holder = new AsyncResultHolder<>("Suggest"); - mInputLogicHandler.getSuggestedWords(inputStyle, SuggestedWords.NOT_A_SEQUENCE_NUMBER, - suggestedWords -> { - final String typedWordString = mWordComposer.getTypedWord(); - final SuggestedWordInfo typedWordInfo = new SuggestedWordInfo( - typedWordString, "" /* prevWordsContext */, - SuggestedWordInfo.MAX_SCORE, - SuggestedWordInfo.KIND_TYPED, Dictionary.DICTIONARY_USER_TYPED, - SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, - SuggestedWordInfo.NOT_A_CONFIDENCE); - // Show new suggestions if we have at least one. Otherwise keep the old - // suggestions with the new typed word. Exception: if the length of the - // typed word is <= 1 (after a deletion typically) we clear old suggestions. - if (suggestedWords.size() > 1 || typedWordString.length() <= 1) { - holder.set(suggestedWords); - } else { - holder.set(retrieveOlderSuggestions(typedWordInfo, mSuggestedWords)); - } + mInputLogicHandler.getSuggestedWords(() -> getSuggestedWords( + inputStyle, SuggestedWords.NOT_A_SEQUENCE_NUMBER, + suggestedWords -> { + final String typedWordString = mWordComposer.getTypedWord(); + final SuggestedWordInfo typedWordInfo = new SuggestedWordInfo( + typedWordString, "", SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_TYPED, + Dictionary.DICTIONARY_USER_TYPED, SuggestedWordInfo.NOT_AN_INDEX, SuggestedWordInfo.NOT_A_CONFIDENCE + ); + // Show new suggestions if we have at least one. Otherwise keep the old + // suggestions with the new typed word. Exception: if the length of the + // typed word is <= 1 (after a deletion typically) we clear old suggestions. + if (suggestedWords.size() > 1 || typedWordString.length() <= 1) { + holder.set(suggestedWords); + } else { + holder.set(retrieveOlderSuggestions(typedWordInfo, mSuggestedWords)); } - ); - + } + )); // This line may cause the current thread to wait. final SuggestedWords suggestedWords = holder.get(null, Constants.GET_SUGGESTED_WORDS_TIMEOUT); @@ -1809,8 +1793,8 @@ public final class InputLogic { // If there weren't any suggestion spans on this word, suggestions#size() will be 1 // if shouldIncludeResumedWordInSuggestions is true, 0 otherwise. In this case, we // have no useful suggestions, so we will try to compute some for it instead. - mInputLogicHandler.getSuggestedWords(Suggest.SESSION_ID_TYPING, - SuggestedWords.NOT_A_SEQUENCE_NUMBER, this::doShowSuggestionsAndClearAutoCorrectionIndicator); + mInputLogicHandler.getSuggestedWords(() -> getSuggestedWords(Suggest.SESSION_ID_TYPING, + SuggestedWords.NOT_A_SEQUENCE_NUMBER, this::doShowSuggestionsAndClearAutoCorrectionIndicator)); } else { // We found suggestion spans in the word. We'll create the SuggestedWords out of // them, and make willAutoCorrect false. We make typedWordValid false, because the @@ -2434,12 +2418,17 @@ public final class InputLogic { return true; } - public void getSuggestedWords(final SettingsValues settingsValues, - final Keyboard keyboard, final int keyboardShiftMode, final int inputStyle, - final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { + // we used to provide keyboard, settingsValues and keyboardShiftMode, but every time read it from current instance anyway + public void getSuggestedWords(final int inputStyle, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { + final Keyboard keyboard = KeyboardSwitcher.getInstance().getKeyboard(); + if (keyboard == null) { + callback.onGetSuggestedWords(SuggestedWords.getEmptyInstance()); + return; + } + final SettingsValues settingsValues = Settings.getValues(); mWordComposer.adviseCapitalizedModeBeforeFetchingSuggestions( - getActualCapsMode(settingsValues, keyboardShiftMode)); - mSuggest.getSuggestedWords(mWordComposer, + getActualCapsMode(settingsValues, KeyboardSwitcher.getInstance().getKeyboardShiftMode())); + final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, getNgramContextFromNthPreviousWordForSuggestion( settingsValues.mSpacingAndPunctuations, // Get the word on which we should search the bigrams. If we are composing @@ -2449,7 +2438,8 @@ public final class InputLogic { keyboard, settingsValues.mSettingsValuesForSuggestion, settingsValues.mAutoCorrectEnabled, - inputStyle, sequenceNumber, callback); + inputStyle, sequenceNumber); + callback.onGetSuggestedWords(suggestedWords); } /** diff --git a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogicHandler.java b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogicHandler.java index 99b77fa3e..6e728a5a7 100644 --- a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogicHandler.java +++ b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogicHandler.java @@ -11,7 +11,6 @@ import android.os.HandlerThread; import android.os.Message; import helium314.keyboard.latin.LatinIME; -import helium314.keyboard.latin.Suggest.OnGetSuggestedWordsCallback; import helium314.keyboard.latin.SuggestedWords; import helium314.keyboard.latin.common.InputPointers; @@ -20,48 +19,19 @@ import helium314.keyboard.latin.common.InputPointers; */ class InputLogicHandler implements Handler.Callback { final Handler mNonUIThreadHandler; - // TODO: remove this reference. - final LatinIME mLatinIME; + final LatinIME.UIHandler mLatinIMEHandler; final InputLogic mInputLogic; private final Object mLock = new Object(); private boolean mInBatchInput; // synchronized using {@link #mLock}. private static final int MSG_GET_SUGGESTED_WORDS = 1; - // A handler that never does anything. This is used for cases where events come before anything - // is initialized, though probably only the monkey can actually do this. - public static final InputLogicHandler NULL_HANDLER = new InputLogicHandler() { - @Override - public void reset() {} - @Override - public boolean handleMessage(final Message msg) { return true; } - @Override - public void onStartBatchInput() {} - @Override - public void onUpdateBatchInput(final InputPointers batchPointers, - final int sequenceNumber) {} - @Override - public void onCancelBatchInput() {} - @Override - public void updateTailBatchInput(final InputPointers batchPointers, - final int sequenceNumber) {} - @Override - public void getSuggestedWords(final int sessionId, final int sequenceNumber, - final OnGetSuggestedWordsCallback callback) {} - }; - - InputLogicHandler() { - mNonUIThreadHandler = null; - mLatinIME = null; - mInputLogic = null; - } - - public InputLogicHandler(final LatinIME latinIME, final InputLogic inputLogic) { + public InputLogicHandler(final LatinIME.UIHandler latinIMEHandler, final InputLogic inputLogic) { final HandlerThread handlerThread = new HandlerThread( InputLogicHandler.class.getSimpleName()); handlerThread.start(); mNonUIThreadHandler = new Handler(handlerThread.getLooper(), this); - mLatinIME = latinIME; + mLatinIMEHandler = latinIMEHandler; mInputLogic = inputLogic; } @@ -69,12 +39,6 @@ class InputLogicHandler implements Handler.Callback { mNonUIThreadHandler.removeCallbacksAndMessages(null); } - // In unit tests, we create several instances of LatinIME, which results in several instances - // of InputLogicHandler. To avoid these handlers lingering, we call this. - public void destroy() { - mNonUIThreadHandler.getLooper().quitSafely(); - } - /** * Handle a message. * @see android.os.Handler.Callback#handleMessage(android.os.Message) @@ -83,7 +47,7 @@ class InputLogicHandler implements Handler.Callback { @Override public boolean handleMessage(final Message msg) { if (msg.what == MSG_GET_SUGGESTED_WORDS) - mLatinIME.getSuggestedWords(msg.arg1, msg.arg2, (OnGetSuggestedWordsCallback) msg.obj); + ((Runnable)msg.obj).run(); return true; } @@ -118,13 +82,14 @@ class InputLogicHandler implements Handler.Callback { return; } mInputLogic.mWordComposer.setBatchInputPointers(batchPointers); - final OnGetSuggestedWordsCallback callback = suggestedWords -> showGestureSuggestionsWithPreviewVisuals(suggestedWords, isTailBatchInput); - getSuggestedWords(isTailBatchInput ? SuggestedWords.INPUT_STYLE_TAIL_BATCH - : SuggestedWords.INPUT_STYLE_UPDATE_BATCH, sequenceNumber, callback); + getSuggestedWords(() -> mInputLogic.getSuggestedWords( + isTailBatchInput ? SuggestedWords.INPUT_STYLE_TAIL_BATCH : SuggestedWords.INPUT_STYLE_UPDATE_BATCH, sequenceNumber, + suggestedWords -> showGestureSuggestionsWithPreviewVisuals(suggestedWords, isTailBatchInput)) + ); } } - void showGestureSuggestionsWithPreviewVisuals(final SuggestedWords suggestedWordsForBatchInput, + private void showGestureSuggestionsWithPreviewVisuals(final SuggestedWords suggestedWordsForBatchInput, final boolean isTailBatchInput) { final SuggestedWords suggestedWordsToShowSuggestions; // We're now inside the callback. This always runs on the Non-UI thread, @@ -138,13 +103,12 @@ class InputLogicHandler implements Handler.Callback { } else { suggestedWordsToShowSuggestions = suggestedWordsForBatchInput; } - mLatinIME.mHandler.showGesturePreviewAndSuggestionStrip(suggestedWordsToShowSuggestions, - isTailBatchInput /* dismissGestureFloatingPreviewText */); + mLatinIMEHandler.showGesturePreviewAndSuggestionStrip(suggestedWordsToShowSuggestions, isTailBatchInput); if (isTailBatchInput) { mInBatchInput = false; // The following call schedules onEndBatchInputInternal // to be called on the UI thread. - mLatinIME.mHandler.showTailBatchInputResult(suggestedWordsToShowSuggestions); + mLatinIMEHandler.showTailBatchInputResult(suggestedWordsToShowSuggestions); } } @@ -193,9 +157,7 @@ class InputLogicHandler implements Handler.Callback { updateBatchInput(batchPointers, sequenceNumber, true); } - public void getSuggestedWords(final int inputStyle, final int sequenceNumber, - final OnGetSuggestedWordsCallback callback) { - mNonUIThreadHandler.obtainMessage( - MSG_GET_SUGGESTED_WORDS, inputStyle, sequenceNumber, callback).sendToTarget(); + public void getSuggestedWords(final Runnable callback) { + mNonUIThreadHandler.obtainMessage(MSG_GET_SUGGESTED_WORDS, callback).sendToTarget(); } }