aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/LatinIME.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin/LatinIME.java')
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java241
1 files changed, 151 insertions, 90 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index e4f39bb18..d57db8e9a 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -46,13 +46,14 @@ import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSubtype;
+import android.widget.TextView;
import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.annotations.UsedForTesting;
@@ -86,6 +87,7 @@ import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.CapsModeUtils;
import com.android.inputmethod.latin.utils.CoordinateUtils;
+import com.android.inputmethod.latin.utils.CursorAnchorInfoUtils;
import com.android.inputmethod.latin.utils.DialogUtils;
import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatchesAndSuggestions;
import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
@@ -152,12 +154,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// TODO: Move these {@link View}s to {@link KeyboardSwitcher}.
private View mInputView;
private SuggestionStripView mSuggestionStripView;
+ private TextView mExtractEditText;
private RichInputMethodManager mRichImm;
@UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
private final SubtypeSwitcher mSubtypeSwitcher;
private final SubtypeState mSubtypeState = new SubtypeState();
private final SpecialKeyDetector mSpecialKeyDetector;
+ // Working variable for {@link #startShowingInputView()} and
+ // {@link #onEvaluateInputViewShown()}.
+ private boolean mIsExecutingStartShowingInputView;
// Object for reacting to adding/removing a dictionary pack.
private final BroadcastReceiver mDictionaryPackInstallReceiver =
@@ -182,9 +188,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED = 6;
private static final int MSG_RESET_CACHES = 7;
private static final int MSG_WAIT_FOR_DICTIONARY_LOAD = 8;
- private static final int MSG_SHOW_COMMIT_INDICATOR = 9;
// Update this when adding new messages
- private static final int MSG_LAST = MSG_SHOW_COMMIT_INDICATOR;
+ private static final int MSG_LAST = MSG_WAIT_FOR_DICTIONARY_LOAD;
private static final int ARG1_NOT_GESTURE_INPUT = 0;
private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1;
@@ -195,7 +200,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private int mDelayInMillisecondsToUpdateSuggestions;
private int mDelayInMillisecondsToUpdateShiftState;
- private int mDelayInMillisecondsToShowCommitIndicator;
public UIHandler(final LatinIME ownerInstance) {
super(ownerInstance);
@@ -211,8 +215,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
R.integer.config_delay_in_milliseconds_to_update_suggestions);
mDelayInMillisecondsToUpdateShiftState = res.getInteger(
R.integer.config_delay_in_milliseconds_to_update_shift_state);
- mDelayInMillisecondsToShowCommitIndicator = res.getInteger(
- R.integer.text_decorator_delay_in_milliseconds_to_show_commit_indicator);
}
@Override
@@ -270,14 +272,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
latinIme.getCurrentRecapitalizeState());
}
break;
- case MSG_SHOW_COMMIT_INDICATOR:
- // Protocol of MSG_SET_COMMIT_INDICATOR_ENABLED:
- // - what: MSG_SHOW_COMMIT_INDICATOR
- // - arg1: not used.
- // - arg2: not used.
- // - obj: the Runnable object to be called back.
- ((Runnable) msg.obj).run();
- break;
case MSG_WAIT_FOR_DICTIONARY_LOAD:
Log.i(TAG, "Timeout waiting for dictionary load");
break;
@@ -378,19 +372,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
obtainMessage(MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED, suggestedWords).sendToTarget();
}
- /**
- * Posts a delayed task to show the commit indicator.
- *
- * <p>Only one task can exist in the queue. When this method is called, any prior task that
- * has not yet fired will be canceled.</p>
- * @param task the runnable object that will be fired when the delayed task is dispatched.
- */
- public void postShowCommitIndicatorTask(final Runnable task) {
- removeMessages(MSG_SHOW_COMMIT_INDICATOR);
- sendMessageDelayed(obtainMessage(MSG_SHOW_COMMIT_INDICATOR, task),
- mDelayInMillisecondsToShowCommitIndicator);
- }
-
// Working variables for the following methods.
private boolean mIsOrientationChanging;
private boolean mPendingSuccessiveImsCallback;
@@ -713,11 +694,27 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onConfigurationChanged(final Configuration conf) {
- final SettingsValues settingsValues = mSettings.getCurrent();
+ SettingsValues settingsValues = mSettings.getCurrent();
if (settingsValues.mDisplayOrientation != conf.orientation) {
mHandler.startOrientationChanging();
mInputLogic.onOrientationChange(mSettings.getCurrent());
}
+ if (settingsValues.mHasHardwareKeyboard != Settings.readHasHardwareKeyboard(conf)) {
+ // If the state of having a hardware keyboard changed, then we want to reload the
+ // settings to adjust for that.
+ // TODO: we should probably do this unconditionally here, rather than only when we
+ // have a change in hardware keyboard configuration.
+ loadSettings();
+ settingsValues = mSettings.getCurrent();
+ if (settingsValues.mHasHardwareKeyboard) {
+ // We call cleanupInternalStateForFinishInput() because it's the right thing to do;
+ // however, it seems at the moment the framework is passing us a seemingly valid
+ // but actually non-functional InputConnection object. So if this bug ever gets
+ // fixed we'll be able to remove the composition, but until it is this code is
+ // actually not doing much.
+ cleanupInternalStateForFinishInput();
+ }
+ }
// TODO: Remove this test.
if (!conf.locale.equals(mPersonalizationDictionaryUpdater.getLocale())) {
refreshPersonalizationDictionarySession(settingsValues);
@@ -742,6 +739,49 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
@Override
+ public void setExtractView(final View view) {
+ final TextView prevExtractEditText = mExtractEditText;
+ super.setExtractView(view);
+ TextView nextExtractEditText = null;
+ if (view != null) {
+ final View extractEditText = view.findViewById(android.R.id.inputExtractEditText);
+ if (extractEditText instanceof TextView) {
+ nextExtractEditText = (TextView)extractEditText;
+ }
+ }
+ if (prevExtractEditText == nextExtractEditText) {
+ return;
+ }
+ if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK && prevExtractEditText != null) {
+ prevExtractEditText.getViewTreeObserver().removeOnPreDrawListener(
+ mExtractTextViewPreDrawListener);
+ }
+ mExtractEditText = nextExtractEditText;
+ if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK && mExtractEditText != null) {
+ mExtractEditText.getViewTreeObserver().addOnPreDrawListener(
+ mExtractTextViewPreDrawListener);
+ }
+ }
+
+ private final ViewTreeObserver.OnPreDrawListener mExtractTextViewPreDrawListener =
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ onExtractTextViewPreDraw();
+ return true;
+ }
+ };
+
+ private void onExtractTextViewPreDraw() {
+ if (!ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK || !isFullscreenMode()
+ || mExtractEditText == null) {
+ return;
+ }
+ final CursorAnchorInfo info = CursorAnchorInfoUtils.getCursorAnchorInfo(mExtractEditText);
+ mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info));
+ }
+
+ @Override
public void setCandidatesView(final View view) {
// To ensure that CandidatesView will never be set.
return;
@@ -843,40 +883,52 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Note: This call should be done by InputMethodService?
updateFullscreenMode();
- // The app calling setText() has the effect of clearing the composing
- // span, so we should reset our state unconditionally, even if restarting is true.
- // We also tell the input logic about the combining rules for the current subtype, so
- // it can adjust its combiners if needed.
- mInputLogic.startInput(mSubtypeSwitcher.getCombiningRulesExtraValueOfCurrentSubtype(),
- currentSettingsValues);
+ // ALERT: settings have not been reloaded and there is a chance they may be stale.
+ // In the practice, if it is, we should have gotten onConfigurationChanged so it should
+ // be fine, but this is horribly confusing and must be fixed AS SOON AS POSSIBLE.
- // Note: the following does a round-trip IPC on the main thread: be careful
- final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
+ // In some cases the input connection has not been reset yet and we can't access it. In
+ // this case we will need to call loadKeyboard() later, when it's accessible, so that we
+ // can go into the correct mode, so we need to do some housekeeping here.
+ final boolean needToCallLoadKeyboardLater;
final Suggest suggest = mInputLogic.mSuggest;
- if (null != currentLocale && !currentLocale.equals(suggest.getLocale())) {
- // TODO: Do this automatically.
- resetSuggest();
- }
+ if (!currentSettingsValues.mHasHardwareKeyboard) {
+ // The app calling setText() has the effect of clearing the composing
+ // span, so we should reset our state unconditionally, even if restarting is true.
+ // We also tell the input logic about the combining rules for the current subtype, so
+ // it can adjust its combiners if needed.
+ mInputLogic.startInput(mSubtypeSwitcher.getCombiningRulesExtraValueOfCurrentSubtype(),
+ currentSettingsValues);
+
+ // Note: the following does a round-trip IPC on the main thread: be careful
+ final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
+ if (null != currentLocale && !currentLocale.equals(suggest.getLocale())) {
+ // TODO: Do this automatically.
+ resetSuggest();
+ }
- // TODO[IL]: Can the following be moved to InputLogic#startInput?
- final boolean canReachInputConnection;
- if (!mInputLogic.mConnection.resetCachesUponCursorMoveAndReturnSuccess(
- editorInfo.initialSelStart, editorInfo.initialSelEnd,
- false /* shouldFinishComposition */)) {
- // Sometimes, while rotating, for some reason the framework tells the app we are not
- // connected to it and that means we can't refresh the cache. In this case, schedule a
- // refresh later.
- // We try resetting the caches up to 5 times before giving up.
- mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */);
- // mLastSelection{Start,End} are reset later in this method, don't need to do it here
- canReachInputConnection = false;
+ // TODO[IL]: Can the following be moved to InputLogic#startInput?
+ if (!mInputLogic.mConnection.resetCachesUponCursorMoveAndReturnSuccess(
+ editorInfo.initialSelStart, editorInfo.initialSelEnd,
+ false /* shouldFinishComposition */)) {
+ // Sometimes, while rotating, for some reason the framework tells the app we are not
+ // connected to it and that means we can't refresh the cache. In this case, schedule
+ // a refresh later.
+ // We try resetting the caches up to 5 times before giving up.
+ mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */);
+ // mLastSelection{Start,End} are reset later in this method, no need to do it here
+ needToCallLoadKeyboardLater = true;
+ } else {
+ // When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best
+ // effort to work around this bug.
+ mInputLogic.mConnection.tryFixLyingCursorPosition();
+ mHandler.postResumeSuggestions(true /* shouldIncludeResumedWordInSuggestions */,
+ true /* shouldDelay */);
+ needToCallLoadKeyboardLater = false;
+ }
} else {
- // When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best
- // effort to work around this bug.
- mInputLogic.mConnection.tryFixLyingCursorPosition();
- mHandler.postResumeSuggestions(true /* shouldIncludeResumedWordInSuggestions */,
- true /* shouldDelay */);
- canReachInputConnection = true;
+ // If we have a hardware keyboard we don't need to call loadKeyboard later anyway.
+ needToCallLoadKeyboardLater = false;
}
if (isDifferentTextField ||
@@ -894,9 +946,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
switcher.loadKeyboard(editorInfo, currentSettingsValues, getCurrentAutoCapsState(),
getCurrentRecapitalizeState());
- if (!canReachInputConnection) {
- // If we can't reach the input connection, we will call loadKeyboard again later,
- // so we need to save its state now. The call will be done in #retryResetCaches.
+ if (needToCallLoadKeyboardLater) {
+ // If we need to call loadKeyboard again later, we need to save its state now. The
+ // later call will be done in #retryResetCaches.
switcher.saveKeyboardState();
}
} else if (restarting) {
@@ -953,6 +1005,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void onFinishInputViewInternal(final boolean finishingInput) {
super.onFinishInputView(finishingInput);
+ cleanupInternalStateForFinishInput();
+ }
+
+ private void cleanupInternalStateForFinishInput() {
mKeyboardSwitcher.deallocateMemory();
// Remove pending messages related to update suggestions
mHandler.cancelUpdateSuggestionStrip();
@@ -972,13 +1028,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
+ ", cs=" + composingSpanStart + ", ce=" + composingSpanEnd);
}
- // If the keyboard is not visible, we don't need to do all the housekeeping work, as it
- // will be reset when the keyboard shows up anyway.
- // TODO: revisit this when LatinIME supports hardware keyboards.
- // NOTE: the test harness subclasses LatinIME and overrides isInputViewShown().
- // TODO: find a better way to simulate actual execution.
- if (isInputViewShown() &&
- mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd)) {
+ // This call happens when we have a hardware keyboard as well as when we don't. While we
+ // don't support hardware keyboards yet we should avoid doing the processing associated
+ // with cursor movement when we have a hardware keyboard since we are not in charge.
+ final SettingsValues settingsValues = mSettings.getCurrent();
+ if ((!settingsValues.mHasHardwareKeyboard || ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED)
+ && mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
+ settingsValues)) {
mKeyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(),
getCurrentRecapitalizeState());
}
@@ -987,9 +1043,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// We cannot mark this method as @Override until new SDK becomes publicly available.
// @Override
public void onUpdateCursorAnchorInfo(final CursorAnchorInfo info) {
- if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK) {
- mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info));
+ if (!ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK || isFullscreenMode()) {
+ return;
}
+ mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info));
}
/**
@@ -1108,22 +1165,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
outInsets.visibleTopInsets = visibleTopY;
}
- @Override
- public boolean onEvaluateInputViewShown() {
- // Always show {@link InputView}.
- return true;
+ public void startShowingInputView() {
+ mIsExecutingStartShowingInputView = true;
+ // This {@link #showWindow(boolean)} will eventually call back
+ // {@link #onEvaluateInputViewShown()}.
+ showWindow(true /* showInput */);
+ mIsExecutingStartShowingInputView = false;
+ }
+
+ public void stopShowingInputView() {
+ showWindow(false /* showInput */);
}
@Override
- public boolean onShowInputRequested(final int flags, final boolean configChange) {
- final SettingsValues settingsValues = mSettings.getCurrent();
- if ((flags & InputMethod.SHOW_EXPLICIT) == 0 && settingsValues.mHasHardwareKeyboard) {
- // Even when IME is implicitly shown and physical keyboard is connected, we should
- // show {@link InputView}.
- // See {@link InputMethodService#onShowInputRequested(int,boolean)}.
+ public boolean onEvaluateInputViewShown() {
+ if (mIsExecutingStartShowingInputView) {
return true;
}
- return super.onShowInputRequested(flags, configChange);
+ return super.onEvaluateInputViewShown();
}
@Override
@@ -1142,9 +1201,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// hack for now. Let's get rid of this once the framework gets fixed.
final EditorInfo ei = getCurrentInputEditorInfo();
return !(ei != null && ((ei.imeOptions & EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0));
- } else {
- return false;
}
+ return false;
}
@Override
@@ -1194,9 +1252,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (null == keyboard) {
return CoordinateUtils.newCoordinateArray(codePoints.length,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
- } else {
- return keyboard.getCoordinates(codePoints);
}
+ return keyboard.getCoordinates(codePoints);
}
// Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is
@@ -1432,19 +1489,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final boolean isEmptyApplicationSpecifiedCompletions =
currentSettingsValues.isApplicationSpecifiedCompletionsOn()
&& suggestedWords.isEmpty();
- final boolean noSuggestionsToShow = (SuggestedWords.EMPTY == suggestedWords)
+ final boolean noSuggestionsFromDictionaries = (SuggestedWords.EMPTY == suggestedWords)
|| suggestedWords.isPunctuationSuggestions()
|| isEmptyApplicationSpecifiedCompletions;
- if (shouldShowImportantNotice && noSuggestionsToShow) {
+ final boolean isBeginningOfSentencePrediction = (suggestedWords.mInputStyle
+ == SuggestedWords.INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION);
+ final boolean noSuggestionsToOverrideImportantNotice = noSuggestionsFromDictionaries
+ || isBeginningOfSentencePrediction;
+ if (shouldShowImportantNotice && noSuggestionsToOverrideImportantNotice) {
if (mSuggestionStripView.maybeShowImportantNoticeTitle()) {
return;
}
}
if (currentSettingsValues.isSuggestionsEnabledPerUserSettings()
- // We should clear suggestions if there is no suggestion to show.
- || noSuggestionsToShow
- || currentSettingsValues.isApplicationSpecifiedCompletionsOn()) {
+ || currentSettingsValues.isApplicationSpecifiedCompletionsOn()
+ // We should clear the contextual strip if there is no suggestion from dictionaries.
+ || noSuggestionsFromDictionaries) {
mSuggestionStripView.setSuggestions(suggestedWords,
SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype()));
}