diff options
Diffstat (limited to 'java/src')
5 files changed, 146 insertions, 77 deletions
diff --git a/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java b/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java new file mode 100644 index 000000000..9870faa98 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 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; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.DialogInterface.OnDismissListener; +import android.content.DialogInterface.OnShowListener; + +import com.android.inputmethod.latin.utils.ImportantNoticeUtils; + +/** + * The dialog box that shows the important notice contents. + */ +public final class ImportantNoticeDialog extends AlertDialog implements OnShowListener, + OnClickListener, OnDismissListener { + public interface ImportantNoticeDialogListener { + public void onClickSettingsOfImportantNoticeDialog(final int nextVersion); + public void onDismissImportantNoticeDialog(final int nextVersion); + } + + private final ImportantNoticeDialogListener mListener; + private final int mNextImportantNoticeVersion; + + public ImportantNoticeDialog( + final Context context, final ImportantNoticeDialogListener listener) { + super(context, THEME_HOLO_DARK); + mListener = listener; + mNextImportantNoticeVersion = ImportantNoticeUtils.getNextImportantNoticeVersion(context); + setMessage(ImportantNoticeUtils.getNextImportantNoticeContents(context)); + // Create buttons and set listeners. + setButton(BUTTON_POSITIVE, context.getString(android.R.string.ok), this); + if (shouldHaveSettingsButton()) { + setButton(BUTTON_NEGATIVE, context.getString(R.string.go_to_settings), this); + } + // Set listeners. + setOnShowListener(this); + setOnDismissListener(this); + } + + private boolean shouldHaveSettingsButton() { + return mNextImportantNoticeVersion + == ImportantNoticeUtils.VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS; + } + + @Override + public void onShow(final DialogInterface dialog) { + ImportantNoticeUtils.updateLastImportantNoticeVersion(getContext()); + } + + @Override + public void onClick(final DialogInterface dialog, final int which) { + if (shouldHaveSettingsButton() && which == BUTTON_NEGATIVE) { + mListener.onClickSettingsOfImportantNoticeDialog(mNextImportantNoticeVersion); + } + } + + @Override + public void onDismiss(final DialogInterface dialog) { + mListener.onDismissImportantNoticeDialog(mNextImportantNoticeVersion); + } +} diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 47a3e9469..9ded5a85e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -26,8 +26,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; -import android.content.DialogInterface.OnDismissListener; -import android.content.DialogInterface.OnShowListener; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; @@ -100,7 +98,8 @@ import java.util.concurrent.TimeUnit; */ public class LatinIME extends InputMethodService implements KeyboardActionListener, SuggestionStripView.Listener, SuggestionStripViewAccessor, - DictionaryFacilitatorForSuggest.DictionaryInitializationListener { + DictionaryFacilitatorForSuggest.DictionaryInitializationListener, + ImportantNoticeDialog.ImportantNoticeDialogListener { private static final String TAG = LatinIME.class.getSimpleName(); private static final boolean TRACE = false; private static boolean DEBUG = false; @@ -799,19 +798,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen suggest = mInputLogic.mSuggest; } - // 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. // 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; } else { + // When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best + // effort to work around this bug. + mInputLogic.mConnection.tryFixLyingCursorPosition(); if (isDifferentTextField) { mHandler.postResumeSuggestions(); } @@ -1177,39 +1179,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mInputLogic.mSuggest.mDictionaryFacilitator.addWordToUserDictionary(wordToEdit); } - // TODO: Move this method out of {@link LatinIME}. // Callback for the {@link SuggestionStripView}, to call when the important notice strip is // pressed. @Override public void showImportantNoticeContents() { - final Context context = this; - final AlertDialog.Builder builder = - new AlertDialog.Builder(context, AlertDialog.THEME_HOLO_DARK); - builder.setMessage(ImportantNoticeUtils.getNextImportantNoticeContents(context)); - builder.setPositiveButton(android.R.string.ok, null /* listener */); - final OnClickListener onClickListener = new OnClickListener() { - @Override - public void onClick(final DialogInterface dialog, final int position) { - if (position == DialogInterface.BUTTON_NEGATIVE) { - launchSettings(); - } - } - }; - builder.setNegativeButton(R.string.go_to_settings, onClickListener); - final AlertDialog importantNoticeDialog = builder.create(); - importantNoticeDialog.setOnShowListener(new OnShowListener() { - @Override - public void onShow(final DialogInterface dialog) { - ImportantNoticeUtils.updateLastImportantNoticeVersion(context); - } - }); - importantNoticeDialog.setOnDismissListener(new OnDismissListener() { - @Override - public void onDismiss(final DialogInterface dialog) { - setNeutralSuggestionStrip(); - } - }); - showOptionDialog(importantNoticeDialog); + showOptionDialog(new ImportantNoticeDialog(this /* context */, this /* listener */)); + } + + // Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener} + @Override + public void onClickSettingsOfImportantNoticeDialog(final int nextVersion) { + launchSettings(); + } + + // Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener} + @Override + public void onDismissImportantNoticeDialog(final int nextVersion) { + setNeutralSuggestionStrip(); } public void displaySettingsDialog() { diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index cc2db4c93..0e85b3c77 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -172,20 +172,6 @@ public final class RichInputConnection { Log.d(TAG, "Will try to retrieve text later."); return false; } - final int lengthOfTextBeforeCursor = mCommittedTextBeforeComposingText.length(); - if (lengthOfTextBeforeCursor > newSelStart - || (newSelStart != lengthOfTextBeforeCursor - && lengthOfTextBeforeCursor < Constants.EDITOR_CONTENTS_CACHE_SIZE - && newSelStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) { - // newSelStart and newSelEnd may be lying -- when rotating the device (probably a - // framework bug). If the values don't agree and we have less chars than we asked - // for, then we know how many chars we have. If we got more than newSelStart says, then - // we also know it was lying. In both cases the length is more reliable. Note that we - // only have to check newSelStart (not newSelEnd) since if newSelEnd is wrong, then - // newSelStart will be wrong as well. - mExpectedSelStart = lengthOfTextBeforeCursor; - mExpectedSelEnd = lengthOfTextBeforeCursor; - } if (null != mIC && shouldFinishComposition) { mIC.finishComposingText(); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 52a6f5f08..eeb5bf536 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -330,7 +330,13 @@ public final class InputLogic { // Another option would be to send suggestions each time we set the composing // text, but that is probably too expensive to do, so we decided to leave things // as is. - resetEntireInputState(settingsValues, newSelStart, newSelEnd); + // Also, we're posting a resume suggestions message, and this will update the + // suggestions strip in a few milliseconds, so if we cleared the suggestion strip here + // we'd have the suggestion strip noticeably janky. To avoid that, we don't clear + // it here, which means we'll keep outdated suggestions for a split second but the + // visual result is better. + resetEntireInputState(settingsValues, newSelStart, newSelEnd, + false /* clearSuggestionStrip */); } else { // resetEntireInputState calls resetCachesUponCursorMove, but forcing the // composition to end. But in all cases where we don't reset the entire input @@ -498,7 +504,7 @@ public final class InputLogic { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the batch input at the current cursor position. resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), - mConnection.getExpectedSelectionEnd()); + mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); } else if (wordComposerSize <= 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 @@ -651,7 +657,7 @@ public final class InputLogic { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the character at the current cursor position. resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), - mConnection.getExpectedSelectionEnd()); + mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); } else { commitTyped(settingsValues, LastComposedWord.NOT_A_SEPARATOR); } @@ -693,7 +699,7 @@ public final class InputLogic { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the character at the current cursor position. resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), - mConnection.getExpectedSelectionEnd()); + mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); isComposingWord = false; } // We want to find out whether to start composing a new word with this character. If so, @@ -775,7 +781,7 @@ public final class InputLogic { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the separator at the current cursor position. resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), - mConnection.getExpectedSelectionEnd()); + mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); } // isComposingWord() may have changed since we stored wasComposing if (mWordComposer.isComposingWord()) { @@ -881,7 +887,7 @@ public final class InputLogic { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can remove the character at the current cursor position. resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), - mConnection.getExpectedSelectionEnd()); + mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); // When we exit this if-clause, mWordComposer.isComposingWord() will return false. } if (mWordComposer.isComposingWord()) { @@ -1252,18 +1258,28 @@ public final class InputLogic { // HACK: We may want to special-case some apps that exhibit bad behavior in case of // recorrection. This is a temporary, stopgap measure that will be removed later. // TODO: remove this. - if (settingsValues.isBrokenByRecorrection()) return; + if (settingsValues.isBrokenByRecorrection() // Recorrection is not supported in languages without spaces because we don't know // how to segment them yet. - if (!settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) return; + || !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces // If no suggestions are requested, don't try restarting suggestions. - if (!settingsValues.isSuggestionsRequested()) return; + || !settingsValues.isSuggestionsRequested() // If the cursor is not touching a word, or if there is a selection, return right away. - if (mConnection.hasSelection()) return; + || mConnection.hasSelection() // If we don't know the cursor location, return. - if (mConnection.getExpectedSelectionStart() < 0) return; + || mConnection.getExpectedSelectionStart() < 0) { + mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); + return; + } final int expectedCursorPosition = mConnection.getExpectedSelectionStart(); - if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) return; + if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) { + // Show predictions. + mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( + WordComposer.CAPS_MODE_OFF, + getNthPreviousWordForSuggestion(settingsValues.mSpacingAndPunctuations, 1)); + mLatinIME.mHandler.postUpdateSuggestionStrip(); + return; + } final TextRange range = mConnection.getWordRangeAtCursor( settingsValues.mSpacingAndPunctuations.mSortedWordSeparators, 0 /* additionalPrecedingWordsCount */); @@ -1606,14 +1622,17 @@ public final class InputLogic { * @param settingsValues the current values of the settings. * @param newSelStart the new selection start, in java characters. * @param newSelEnd the new selection end, in java characters. + * @param clearSuggestionStrip whether this method should clear the suggestion strip. */ // TODO: how is this different from startInput ?! // TODO: remove all references to this in LatinIME and make this private public void resetEntireInputState(final SettingsValues settingsValues, - final int newSelStart, final int newSelEnd) { + final int newSelStart, final int newSelEnd, final boolean clearSuggestionStrip) { final boolean shouldFinishComposition = mWordComposer.isComposingWord(); resetComposingState(true /* alsoResetLastComposedWord */); - mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); + if (clearSuggestionStrip) { + mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); + } mConnection.resetCachesUponCursorMoveAndReturnSuccess(newSelStart, newSelEnd, shouldFinishComposition); } diff --git a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java index 6b0bb86ac..ca8bef397 100644 --- a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java @@ -60,7 +60,7 @@ public final class ImportantNoticeUtils { return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); } - public static int getCurrentImportantNoticeVersion(final Context context) { + private static int getCurrentImportantNoticeVersion(final Context context) { return context.getResources().getInteger(R.integer.config_important_notice_version); } @@ -68,7 +68,7 @@ public final class ImportantNoticeUtils { return getImportantNoticePreferences(context).getInt(KEY_IMPORTANT_NOTICE_VERSION, 0); } - private static int getNextImportantNoticeVersion(final Context context) { + public static int getNextImportantNoticeVersion(final Context context) { return getLastImportantNoticeVersion(context) + 1; } @@ -92,23 +92,23 @@ public final class ImportantNoticeUtils { .apply(); } - // TODO: Make title resource to string array indexed by version. public static String getNextImportantNoticeTitle(final Context context) { - switch (getNextImportantNoticeVersion(context)) { - case VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS: - return context.getString(R.string.important_notice_title); - default: - return null; + final int nextVersion = getCurrentImportantNoticeVersion(context); + final String[] importantNoticeTitleArray = context.getResources().getStringArray( + R.array.important_notice_title_array); + if (nextVersion > 0 && nextVersion < importantNoticeTitleArray.length) { + return importantNoticeTitleArray[nextVersion]; } + return null; } - // TODO: Make content resource to string array indexed by version. public static String getNextImportantNoticeContents(final Context context) { - switch (getNextImportantNoticeVersion(context)) { - case VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS: - return context.getString(R.string.important_notice_contents); - default: - return null; + final int nextVersion = getNextImportantNoticeVersion(context); + final String[] importantNoticeContentsArray = context.getResources().getStringArray( + R.array.important_notice_contents_array); + if (nextVersion > 0 && nextVersion < importantNoticeContentsArray.length) { + return importantNoticeContentsArray[nextVersion]; } + return null; } } |