diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
17 files changed, 477 insertions, 323 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java index b4382bc2c..e428b1d54 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java @@ -142,7 +142,7 @@ public final class BinaryDictionaryFileDumper { final ContentProviderClient client = context.getContentResolver(). acquireContentProviderClient(getProviderUriBuilder("").build()); if (null == client) return Collections.<WordListInfo>emptyList(); - + Cursor cursor = null; try { final Uri.Builder builder = getContentUriBuilderForType(clientId, client, QUERY_PATH_DICT_INFO, locale.toString()); @@ -154,24 +154,22 @@ public final class BinaryDictionaryFileDumper { final boolean isProtocolV2 = (QUERY_PARAMETER_PROTOCOL_VALUE.equals( queryUri.getQueryParameter(QUERY_PARAMETER_PROTOCOL))); - Cursor c = client.query(queryUri, DICTIONARY_PROJECTION, null, null, null); - if (isProtocolV2 && null == c) { + cursor = client.query(queryUri, DICTIONARY_PROJECTION, null, null, null); + if (isProtocolV2 && null == cursor) { reinitializeClientRecordInDictionaryContentProvider(context, client, clientId); - c = client.query(queryUri, DICTIONARY_PROJECTION, null, null, null); + cursor = client.query(queryUri, DICTIONARY_PROJECTION, null, null, null); } - if (null == c) return Collections.<WordListInfo>emptyList(); - if (c.getCount() <= 0 || !c.moveToFirst()) { - c.close(); + if (null == cursor) return Collections.<WordListInfo>emptyList(); + if (cursor.getCount() <= 0 || !cursor.moveToFirst()) { return Collections.<WordListInfo>emptyList(); } final ArrayList<WordListInfo> list = CollectionUtils.newArrayList(); do { - final String wordListId = c.getString(0); - final String wordListLocale = c.getString(1); + final String wordListId = cursor.getString(0); + final String wordListLocale = cursor.getString(1); if (TextUtils.isEmpty(wordListId)) continue; list.add(new WordListInfo(wordListId, wordListLocale)); - } while (c.moveToNext()); - c.close(); + } while (cursor.moveToNext()); return list; } catch (RemoteException e) { // The documentation is unclear as to in which cases this may happen, but it probably @@ -186,6 +184,9 @@ public final class BinaryDictionaryFileDumper { Log.e(TAG, "Unexpected exception communicating with the dictionary pack", e); return Collections.<WordListInfo>emptyList(); } finally { + if (null != cursor) { + cursor.close(); + } client.release(); } } diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index d6ac71fe2..d1ff714fc 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -252,6 +252,18 @@ public final class Constants { } } + public static String printableCodes(final int[] codes) { + final StringBuilder sb = new StringBuilder(); + boolean addDelimiter = false; + for (final int code : codes) { + if (code == NOT_A_CODE) break; + if (addDelimiter) sb.append(", "); + sb.append(printableCode(code)); + addDelimiter = true; + } + return "[" + sb + "]"; + } + public static final int MAX_INT_BIT_COUNT = 32; /** diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index d626ff926..11a9d1fe4 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -139,23 +139,24 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { } private void loadDictionaryAsyncForUri(final Uri uri) { + Cursor cursor = null; try { - Cursor cursor = mContext.getContentResolver() - .query(uri, PROJECTION, null, null, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - sContactCountAtLastRebuild = getContactCount(); - addWords(cursor); - } - } finally { - cursor.close(); - } + cursor = mContext.getContentResolver().query(uri, PROJECTION, null, null, null); + if (null == cursor) { + return; + } + if (cursor.moveToFirst()) { + sContactCountAtLastRebuild = getContactCount(); + addWords(cursor); } } catch (final SQLiteException e) { Log.e(TAG, "SQLiteException in the remote Contacts process.", e); } catch (final IllegalStateException e) { Log.e(TAG, "Contacts DB is having problems", e); + } finally { + if (null != cursor) { + cursor.close(); + } } } @@ -186,18 +187,20 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { private int getContactCount() { // TODO: consider switching to a rawQuery("select count(*)...") on the database if // performance is a bottleneck. + Cursor cursor = null; try { - final Cursor cursor = mContext.getContentResolver().query( - Contacts.CONTENT_URI, PROJECTION_ID_ONLY, null, null, null); - if (cursor != null) { - try { - return cursor.getCount(); - } finally { - cursor.close(); - } + cursor = mContext.getContentResolver().query(Contacts.CONTENT_URI, PROJECTION_ID_ONLY, + null, null, null); + if (null == cursor) { + return 0; } + return cursor.getCount(); } catch (final SQLiteException e) { Log.e(TAG, "SQLiteException in the remote Contacts process.", e); + } finally { + if (null != cursor) { + cursor.close(); + } } return 0; } @@ -281,26 +284,27 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { // Check all contacts since it's not possible to find out which names have changed. // This is needed because it's possible to receive extraneous onChange events even when no // name has changed. - Cursor cursor = mContext.getContentResolver().query( - Contacts.CONTENT_URI, PROJECTION, null, null, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - while (!cursor.isAfterLast()) { - String name = cursor.getString(INDEX_NAME); - if (isValidName(name) && !isNameInDictionary(name)) { - if (DEBUG) { - Log.d(TAG, "Contact name missing: " + name + " (runtime = " - + (SystemClock.uptimeMillis() - startTime) + " ms)"); - } - return true; + final Cursor cursor = mContext.getContentResolver().query(Contacts.CONTENT_URI, PROJECTION, + null, null, null); + if (null == cursor) { + return false; + } + try { + if (cursor.moveToFirst()) { + while (!cursor.isAfterLast()) { + String name = cursor.getString(INDEX_NAME); + if (isValidName(name) && !isNameInDictionary(name)) { + if (DEBUG) { + Log.d(TAG, "Contact name missing: " + name + " (runtime = " + + (SystemClock.uptimeMillis() - startTime) + " ms)"); } - cursor.moveToNext(); + return true; } + cursor.moveToNext(); } - } finally { - cursor.close(); } + } finally { + cursor.close(); } if (DEBUG) { Log.d(TAG, "No contacts changed. (runtime = " + (SystemClock.uptimeMillis() - startTime) diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java index 259c1372e..138a626a0 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java @@ -512,7 +512,6 @@ public class DictionaryFacilitatorForSuggest { } } - @UsedForTesting public void clearUserHistoryDictionary() { if (mUserHistoryDictionary == null) { return; diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java index 01c17f2f2..726b3d141 100644 --- a/java/src/com/android/inputmethod/latin/InputAttributes.java +++ b/java/src/com/android/inputmethod/latin/InputAttributes.java @@ -20,9 +20,13 @@ import android.text.InputType; import android.util.Log; import android.view.inputmethod.EditorInfo; +import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.InputTypeUtils; import com.android.inputmethod.latin.utils.StringUtils; +import java.util.ArrayList; +import java.util.Arrays; + /** * Class to hold attributes of the input field. */ @@ -62,49 +66,43 @@ public final class InputAttributes { mInputTypeNoAutoCorrect = false; mApplicationSpecifiedCompletionOn = false; mShouldInsertSpacesAutomatically = false; - } else { - final int variation = inputType & InputType.TYPE_MASK_VARIATION; - final boolean flagNoSuggestions = - 0 != (inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); - final boolean flagMultiLine = - 0 != (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE); - final boolean flagAutoCorrect = - 0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); - final boolean flagAutoComplete = - 0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); - - mIsPasswordField = InputTypeUtils.isPasswordInputType(inputType) - || InputTypeUtils.isVisiblePasswordInputType(inputType); - // TODO: Have a helper method in InputTypeUtils - // Make sure that passwords are not displayed in {@link SuggestionStripView}. - if (mIsPasswordField - || InputTypeUtils.isEmailVariation(variation) - || InputType.TYPE_TEXT_VARIATION_URI == variation - || InputType.TYPE_TEXT_VARIATION_FILTER == variation - || flagNoSuggestions - || flagAutoComplete) { - mIsSettingsSuggestionStripOn = false; - } else { - mIsSettingsSuggestionStripOn = true; - } + return; + } + // inputClass == InputType.TYPE_CLASS_TEXT + final int variation = inputType & InputType.TYPE_MASK_VARIATION; + final boolean flagNoSuggestions = + 0 != (inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); + final boolean flagMultiLine = + 0 != (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE); + final boolean flagAutoCorrect = + 0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + final boolean flagAutoComplete = + 0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); - mShouldInsertSpacesAutomatically = InputTypeUtils.isAutoSpaceFriendlyType(inputType); - - // If it's a browser edit field and auto correct is not ON explicitly, then - // disable auto correction, but keep suggestions on. - // If NO_SUGGESTIONS is set, don't do prediction. - // If it's not multiline and the autoCorrect flag is not set, then don't correct - if ((variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT - && !flagAutoCorrect) - || flagNoSuggestions - || (!flagAutoCorrect && !flagMultiLine)) { - mInputTypeNoAutoCorrect = true; - } else { - mInputTypeNoAutoCorrect = false; - } + mIsPasswordField = InputTypeUtils.isPasswordInputType(inputType) + || InputTypeUtils.isVisiblePasswordInputType(inputType); + // TODO: Have a helper method in InputTypeUtils + // Make sure that passwords are not displayed in {@link SuggestionStripView}. + final boolean noSuggestionStrip = mIsPasswordField + || InputTypeUtils.isEmailVariation(variation) + || InputType.TYPE_TEXT_VARIATION_URI == variation + || InputType.TYPE_TEXT_VARIATION_FILTER == variation + || flagNoSuggestions + || flagAutoComplete; + mIsSettingsSuggestionStripOn = !noSuggestionStrip; - mApplicationSpecifiedCompletionOn = flagAutoComplete && isFullscreenMode; - } + mShouldInsertSpacesAutomatically = InputTypeUtils.isAutoSpaceFriendlyType(inputType); + + // If it's a browser edit field and auto correct is not ON explicitly, then + // disable auto correction, but keep suggestions on. + // If NO_SUGGESTIONS is set, don't do prediction. + // If it's not multiline and the autoCorrect flag is not set, then don't correct + mInputTypeNoAutoCorrect = + (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT && !flagAutoCorrect) + || flagNoSuggestions + || (!flagAutoCorrect && !flagMultiLine); + + mApplicationSpecifiedCompletionOn = flagAutoComplete && isFullscreenMode; } public boolean isTypeNull() { @@ -117,96 +115,142 @@ public final class InputAttributes { @SuppressWarnings("unused") private void dumpFlags(final int inputType) { - Log.i(TAG, "Input class:"); final int inputClass = inputType & InputType.TYPE_MASK_CLASS; - if (inputClass == InputType.TYPE_CLASS_TEXT) - Log.i(TAG, " TYPE_CLASS_TEXT"); - if (inputClass == InputType.TYPE_CLASS_PHONE) - Log.i(TAG, " TYPE_CLASS_PHONE"); - if (inputClass == InputType.TYPE_CLASS_NUMBER) - Log.i(TAG, " TYPE_CLASS_NUMBER"); - if (inputClass == InputType.TYPE_CLASS_DATETIME) - Log.i(TAG, " TYPE_CLASS_DATETIME"); - Log.i(TAG, "Variation:"); - switch (InputType.TYPE_MASK_VARIATION & inputType) { - case InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS: - Log.i(TAG, " TYPE_TEXT_VARIATION_EMAIL_ADDRESS"); - break; - case InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT: - Log.i(TAG, " TYPE_TEXT_VARIATION_EMAIL_SUBJECT"); - break; - case InputType.TYPE_TEXT_VARIATION_FILTER: - Log.i(TAG, " TYPE_TEXT_VARIATION_FILTER"); - break; - case InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE: - Log.i(TAG, " TYPE_TEXT_VARIATION_LONG_MESSAGE"); - break; - case InputType.TYPE_TEXT_VARIATION_NORMAL: - Log.i(TAG, " TYPE_TEXT_VARIATION_NORMAL"); - break; - case InputType.TYPE_TEXT_VARIATION_PASSWORD: - Log.i(TAG, " TYPE_TEXT_VARIATION_PASSWORD"); - break; - case InputType.TYPE_TEXT_VARIATION_PERSON_NAME: - Log.i(TAG, " TYPE_TEXT_VARIATION_PERSON_NAME"); - break; - case InputType.TYPE_TEXT_VARIATION_PHONETIC: - Log.i(TAG, " TYPE_TEXT_VARIATION_PHONETIC"); - break; - case InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS: - Log.i(TAG, " TYPE_TEXT_VARIATION_POSTAL_ADDRESS"); - break; - case InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE: - Log.i(TAG, " TYPE_TEXT_VARIATION_SHORT_MESSAGE"); - break; - case InputType.TYPE_TEXT_VARIATION_URI: - Log.i(TAG, " TYPE_TEXT_VARIATION_URI"); - break; - case InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD: - Log.i(TAG, " TYPE_TEXT_VARIATION_VISIBLE_PASSWORD"); - break; - case InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT: - Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_EDIT_TEXT"); - break; - case InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS: - Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS"); - break; - case InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD: - Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_PASSWORD"); - break; - default: - Log.i(TAG, " Unknown variation"); - break; + final String inputClassString = toInputClassString(inputClass); + final String variationString = toVariationString( + inputClass, inputType & InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); + final String flagsString = toFlagsString(inputType & InputType.TYPE_MASK_FLAGS); + Log.i(TAG, "Input class: " + inputClassString); + Log.i(TAG, "Variation: " + variationString); + Log.i(TAG, "Flags: " + flagsString); + } + + private static String toInputClassString(final int inputClass) { + switch (inputClass) { + case InputType.TYPE_CLASS_TEXT: + return "TYPE_CLASS_TEXT"; + case InputType.TYPE_CLASS_PHONE: + return "TYPE_CLASS_PHONE"; + case InputType.TYPE_CLASS_NUMBER: + return "TYPE_CLASS_NUMBER"; + case InputType.TYPE_CLASS_DATETIME: + return "TYPE_CLASS_DATETIME"; + default: + return String.format("unknownInputClass<0x%08x>", inputClass); + } + } + + private static String toVariationString(final int inputClass, final int variation) { + switch (inputClass) { + case InputType.TYPE_CLASS_TEXT: + return toTextVariationString(variation); + case InputType.TYPE_CLASS_NUMBER: + return toNumberVariationString(variation); + case InputType.TYPE_CLASS_DATETIME: + return toDatetimeVariationString(variation); + default: + return ""; } - Log.i(TAG, "Flags:"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS)) - Log.i(TAG, " TYPE_TEXT_FLAG_NO_SUGGESTIONS"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE)) - Log.i(TAG, " TYPE_TEXT_FLAG_MULTI_LINE"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE)) - Log.i(TAG, " TYPE_TEXT_FLAG_IME_MULTI_LINE"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS)) - Log.i(TAG, " TYPE_TEXT_FLAG_CAP_WORDS"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)) - Log.i(TAG, " TYPE_TEXT_FLAG_CAP_SENTENCES"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS)) - Log.i(TAG, " TYPE_TEXT_FLAG_CAP_CHARACTERS"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT)) - Log.i(TAG, " TYPE_TEXT_FLAG_AUTO_CORRECT"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE)) - Log.i(TAG, " TYPE_TEXT_FLAG_AUTO_COMPLETE"); + } + + private static String toTextVariationString(final int variation) { + switch (variation) { + case InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS: + return " TYPE_TEXT_VARIATION_EMAIL_ADDRESS"; + case InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT: + return "TYPE_TEXT_VARIATION_EMAIL_SUBJECT"; + case InputType.TYPE_TEXT_VARIATION_FILTER: + return "TYPE_TEXT_VARIATION_FILTER"; + case InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE: + return "TYPE_TEXT_VARIATION_LONG_MESSAGE"; + case InputType.TYPE_TEXT_VARIATION_NORMAL: + return "TYPE_TEXT_VARIATION_NORMAL"; + case InputType.TYPE_TEXT_VARIATION_PASSWORD: + return "TYPE_TEXT_VARIATION_PASSWORD"; + case InputType.TYPE_TEXT_VARIATION_PERSON_NAME: + return "TYPE_TEXT_VARIATION_PERSON_NAME"; + case InputType.TYPE_TEXT_VARIATION_PHONETIC: + return "TYPE_TEXT_VARIATION_PHONETIC"; + case InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS: + return "TYPE_TEXT_VARIATION_POSTAL_ADDRESS"; + case InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE: + return "TYPE_TEXT_VARIATION_SHORT_MESSAGE"; + case InputType.TYPE_TEXT_VARIATION_URI: + return "TYPE_TEXT_VARIATION_URI"; + case InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD: + return "TYPE_TEXT_VARIATION_VISIBLE_PASSWORD"; + case InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT: + return "TYPE_TEXT_VARIATION_WEB_EDIT_TEXT"; + case InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS: + return "TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS"; + case InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD: + return "TYPE_TEXT_VARIATION_WEB_PASSWORD"; + default: + return String.format("unknownVariation<0x%08x>", variation); + } + } + + private static String toNumberVariationString(final int variation) { + switch (variation) { + case InputType.TYPE_NUMBER_VARIATION_NORMAL: + return "TYPE_NUMBER_VARIATION_NORMAL"; + case InputType.TYPE_NUMBER_VARIATION_PASSWORD: + return "TYPE_NUMBER_VARIATION_PASSWORD"; + default: + return String.format("unknownVariation<0x%08x>", variation); + } + } + + private static String toDatetimeVariationString(final int variation) { + switch (variation) { + case InputType.TYPE_DATETIME_VARIATION_NORMAL: + return "TYPE_DATETIME_VARIATION_NORMAL"; + case InputType.TYPE_DATETIME_VARIATION_DATE: + return "TYPE_DATETIME_VARIATION_DATE"; + case InputType.TYPE_DATETIME_VARIATION_TIME: + return "TYPE_DATETIME_VARIATION_TIME"; + default: + return String.format("unknownVariation<0x%08x>", variation); + } + } + + private static String toFlagsString(final int flags) { + final ArrayList<String> flagsArray = CollectionUtils.newArrayList(); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS)) + flagsArray.add("TYPE_TEXT_FLAG_NO_SUGGESTIONS"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_MULTI_LINE)) + flagsArray.add("TYPE_TEXT_FLAG_MULTI_LINE"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE)) + flagsArray.add("TYPE_TEXT_FLAG_IME_MULTI_LINE"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_CAP_WORDS)) + flagsArray.add("TYPE_TEXT_FLAG_CAP_WORDS"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)) + flagsArray.add("TYPE_TEXT_FLAG_CAP_SENTENCES"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS)) + flagsArray.add("TYPE_TEXT_FLAG_CAP_CHARACTERS"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT)) + flagsArray.add("TYPE_TEXT_FLAG_AUTO_CORRECT"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE)) + flagsArray.add("TYPE_TEXT_FLAG_AUTO_COMPLETE"); + return flagsArray.isEmpty() ? "" : Arrays.toString(flagsArray.toArray()); } // Pretty print @Override public String toString() { - return "\n mInputTypeNoAutoCorrect = " + mInputTypeNoAutoCorrect - + "\n mIsSettingsSuggestionStripOn = " + mIsSettingsSuggestionStripOn - + "\n mApplicationSpecifiedCompletionOn = " + mApplicationSpecifiedCompletionOn; + return String.format( + "%s: inputType=0x%08x%s%s%s%s%s targetApp=%s\n", getClass().getSimpleName(), + mInputType, + (mInputTypeNoAutoCorrect ? " noAutoCorrect" : ""), + (mIsPasswordField ? " password" : ""), + (mIsSettingsSuggestionStripOn ? " suggestionStrip" : ""), + (mApplicationSpecifiedCompletionOn ? " appSpecified" : ""), + (mShouldInsertSpacesAutomatically ? " insertSpaces" : ""), + mTargetApplicationPackageName); } - public static boolean inPrivateImeOptions(String packageName, String key, - EditorInfo editorInfo) { + public static boolean inPrivateImeOptions(final String packageName, final String key, + final EditorInfo editorInfo) { if (editorInfo == null) return false; final String findingKey = (packageName != null) ? packageName + "." + key : key; return StringUtils.containsInCommaSplittableText(findingKey, editorInfo.privateImeOptions); diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 743118eed..5d90e10a0 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -25,6 +25,9 @@ import android.app.AlertDialog; 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; @@ -171,10 +174,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onCreate() { final Resources res = getOwnerInstance().getResources(); - mDelayUpdateSuggestions = - res.getInteger(R.integer.config_delay_update_suggestions); - mDelayUpdateShiftState = - res.getInteger(R.integer.config_delay_update_shift_state); + mDelayUpdateSuggestions = res.getInteger(R.integer.config_delay_update_suggestions); + mDelayUpdateShiftState = res.getInteger(R.integer.config_delay_update_shift_state); mDoubleSpacePeriodTimeout = res.getInteger(R.integer.config_double_space_period_timeout); } @@ -339,12 +340,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void executePendingImsCallback(final LatinIME latinIme, final EditorInfo editorInfo, boolean restarting) { - if (mHasPendingFinishInputView) + if (mHasPendingFinishInputView) { latinIme.onFinishInputViewInternal(mHasPendingFinishInput); - if (mHasPendingFinishInput) + } + if (mHasPendingFinishInput) { latinIme.onFinishInputInternal(); - if (mHasPendingStartInput) + } + if (mHasPendingStartInput) { latinIme.onStartInputInternal(editorInfo, restarting); + } resetPendingImsCallback(); } @@ -530,18 +534,33 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } private void refreshPersonalizationDictionarySession() { + final Suggest suggest = mInputLogic.mSuggest; + final boolean shouldKeepUserHistoryDictionaries; + final boolean shouldKeepPersonalizationDictionaries; if (mSettings.getCurrent().mUsePersonalizedDicts) { - if (mSubtypeSwitcher.isSystemLocaleSameAsLocaleOfAllEnabledSubtypes()) { - final DictionaryFacilitatorForSuggest dictionaryFacilitator = - (mInputLogic.mSuggest == null) ? - null : mInputLogic.mSuggest.mDictionaryFacilitator; - PersonalizationDictionarySessionRegistrar.init(this, dictionaryFacilitator); - } else { - PersonalizationDictionarySessionRegistrar.close(this); - } + shouldKeepUserHistoryDictionaries = true; + // TODO: Eliminate this restriction + shouldKeepPersonalizationDictionaries = + mSubtypeSwitcher.isSystemLocaleSameAsLocaleOfAllEnabledSubtypes(); } else { - PersonalizationHelper.removeAllPersonalizedDictionaries(this); + shouldKeepUserHistoryDictionaries = false; + shouldKeepPersonalizationDictionaries = false; + } + if (!shouldKeepUserHistoryDictionaries) { + // Remove user history dictionaries. + PersonalizationHelper.removeAllUserHistoryDictionaries(this); + if (suggest != null) { + suggest.mDictionaryFacilitator.clearUserHistoryDictionary(); + } + } + if (!shouldKeepPersonalizationDictionaries) { + // Remove personalization dictionaries. + PersonalizationHelper.removeAllPersonalizationDictionaries(this); PersonalizationDictionarySessionRegistrar.resetAll(this); + } else { + final DictionaryFacilitatorForSuggest dictionaryFacilitator = + (suggest == null) ? null : suggest.mDictionaryFacilitator; + PersonalizationDictionarySessionRegistrar.init(this, dictionaryFacilitator); } } @@ -579,9 +598,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen (mInputLogic.mSuggest == null) ? null : mInputLogic.mSuggest.mDictionaryFacilitator; // Creates new dictionary facilitator for the new locale. final DictionaryFacilitatorForSuggest dictionaryFacilitator = - new DictionaryFacilitatorForSuggest(this /* context */, locale, - settingsValues, this /* DictionaryInitializationListener */, - oldDictionaryFacilitator); + new DictionaryFacilitatorForSuggest(this /* context */, locale, settingsValues, + this /* DictionaryInitializationListener */, oldDictionaryFacilitator); final Suggest newSuggest = new Suggest(locale, dictionaryFacilitator); if (settingsValues.mCorrectionEnabled) { newSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold); @@ -658,7 +676,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen .findViewById(android.R.id.extractArea); mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view); - if (mSuggestionStripView != null) { + if (hasSuggestionStripView()) { mSuggestionStripView.setListener(this, view); } if (LatinImeLogger.sVISUALDEBUG) { @@ -738,13 +756,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, prefs); } if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) { - Log.w(TAG, "Deprecated private IME option specified: " - + editorInfo.privateImeOptions); + Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead"); } if (InputAttributes.inPrivateImeOptions(getPackageName(), FORCE_ASCII, editorInfo)) { - Log.w(TAG, "Deprecated private IME option specified: " - + editorInfo.privateImeOptions); + Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); } @@ -777,14 +793,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Note: the following does a round-trip IPC on the main thread: be careful final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); - final Suggest suggest = mInputLogic.mSuggest; + Suggest suggest = mInputLogic.mSuggest; if (null != suggest && null != currentLocale && !currentLocale.equals(suggest.mLocale)) { initSuggest(); - } - if (mSuggestionStripView != null) { - // This will set the punctuation suggestions if next word suggestion is off; - // otherwise it will clear the suggestion strip. - setNeutralSuggestionStrip(); + suggest = mInputLogic.mSuggest; } // Sometimes, while rotating, for some reason the framework tells the app we are not @@ -809,6 +821,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (isDifferentTextField || !currentSettingsValues.hasSameOrientation(getResources().getConfiguration())) { loadSettings(); + suggest = mInputLogic.mSuggest; } if (isDifferentTextField) { mainKeyboardView.closing(); @@ -834,8 +847,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Space state must be updated before calling updateShiftState switcher.updateShiftState(); } - setSuggestionStripShownInternal( - isSuggestionsStripVisible(), /* needsInputViewShown */ false); + // This will set the punctuation suggestions if next word suggestion is off; + // otherwise it will clear the suggestion strip. + setNeutralSuggestionStripInternal(false /* needsInputViewShown */); mHandler.cancelUpdateSuggestionStrip(); mHandler.cancelDoubleSpacePeriodTimer(); @@ -894,12 +908,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, composingSpanEnd); if (DEBUG) { - Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart - + ", ose=" + oldSelEnd - + ", nss=" + newSelStart - + ", nse=" + newSelEnd - + ", cs=" + composingSpanStart - + ", ce=" + composingSpanEnd); + Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart + ", ose=" + oldSelEnd + + ", nss=" + newSelStart + ", nse=" + newSelEnd + + ", cs=" + composingSpanStart + ", ce=" + composingSpanEnd); } if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_onUpdateSelection(oldSelStart, oldSelEnd, @@ -983,7 +994,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } } - if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return; + if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) { + return; + } if (applicationSpecifiedCompletions == null) { setNeutralSuggestionStrip(); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { @@ -997,27 +1010,25 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = SuggestedWords.getFromApplicationSpecifiedCompletions( applicationSpecifiedCompletions); - final SuggestedWords suggestedWords = new SuggestedWords( - applicationSuggestedWords, null /* rawSuggestions */, - false /* typedWordValid */, - false /* willAutoCorrect */, - false /* isObsoleteSuggestions */, - false /* isPrediction */); - // When in fullscreen mode, show completions generated by the application - setSuggestedWords(suggestedWords, true /* shouldShow */); + final SuggestedWords suggestedWords = new SuggestedWords(applicationSuggestedWords, + null /* rawSuggestions */, false /* typedWordValid */, false /* willAutoCorrect */, + false /* isObsoleteSuggestions */, false /* isPrediction */); + // When in fullscreen mode, show completions generated by the application forcibly + setSuggestedWords(suggestedWords, true /* isSuggestionStripVisible */, + true /* needsInputViewShown */); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); } } - private void setSuggestionStripShownInternal(final boolean shown, + private void setSuggestionStripShownInternal(final boolean isSuggestionStripVisible, final boolean needsInputViewShown) { // TODO: Modify this if we support suggestions with hard keyboard - if (!onEvaluateInputViewShown() || null == mSuggestionStripView) { + if (!onEvaluateInputViewShown() || !hasSuggestionStripView()) { return; } final boolean inputViewShown = mKeyboardSwitcher.isShowingMainKeyboardOrEmojiPalettes(); - final boolean shouldShowSuggestions = shown + final boolean shouldShowSuggestions = isSuggestionStripVisible && (needsInputViewShown ? inputViewShown : true); if (shouldShowSuggestions) { mSuggestionStripView.setVisibility(View.VISIBLE); @@ -1057,7 +1068,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onComputeInsets(final InputMethodService.Insets outInsets) { super.onComputeInsets(outInsets); final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView(); - if (visibleKeyboardView == null || mSuggestionStripView == null) { + if (visibleKeyboardView == null || !hasSuggestionStripView()) { return; } final int adjustedBackingHeight = getAdjustedBackingViewHeight(); @@ -1172,31 +1183,54 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void showImportantNoticeContents() { final Context context = this; - final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { + final OnShowListener onShowListener = new OnShowListener() { @Override - public void onClick(final DialogInterface di, final int position) { - di.dismiss(); + public void onShow(final DialogInterface dialog) { ImportantNoticeUtils.updateLastImportantNoticeVersion(context); - if (position == DialogInterface.BUTTON_POSITIVE) { - setNeutralSuggestionStrip(); - return; - } + onShowImportantNoticeDialog( + ImportantNoticeUtils.getCurrentImportantNoticeVersion(context)); + } + }; + final OnClickListener onClickListener = new OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int position) { if (position == DialogInterface.BUTTON_NEGATIVE) { launchSettings(); - return; } } }; - final AlertDialog.Builder builder = - new AlertDialog.Builder(context, AlertDialog.THEME_HOLO_DARK); - builder.setMessage(R.string.important_notice_contents) - .setPositiveButton(android.R.string.ok, listener) - .setNegativeButton(R.string.go_to_settings, listener); - showOptionDialog(builder.create(), true /* cancelable */); + final OnDismissListener onDismissListener = new OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + setNeutralSuggestionStrip(); + } + }; + final String importantNoticeContents = ImportantNoticeUtils.getImportantNoticeContents( + context); + final AlertDialog.Builder builder = new AlertDialog.Builder( + context, AlertDialog.THEME_HOLO_DARK); + builder.setMessage(importantNoticeContents) + .setPositiveButton(android.R.string.ok, null /* listener */) + .setNegativeButton(R.string.go_to_settings, onClickListener); + final AlertDialog importantNoticeDialog = builder.create(); + importantNoticeDialog.setOnShowListener(onShowListener); + importantNoticeDialog.setOnDismissListener(onDismissListener); + showOptionDialog(importantNoticeDialog); + } + + private void onShowImportantNoticeDialog(final int importantNoticeVersion) { + if (importantNoticeVersion == + ImportantNoticeUtils.VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS) { + mSettings.writeUsePersonalizationDictionary(true /* enabled */); + loadSettings(); + initSuggest(); + } } public void displaySettingsDialog() { - if (isShowingOptionDialog()) return; + if (isShowingOptionDialog()) { + return; + } showSubtypeSelectorAndSettings(); } @@ -1256,8 +1290,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSubtypeSwitcher.switchToShortcutIME(this); // Still call the *#onCodeInput methods for readability. } - mInputLogic.onCodeInput(codeToSend, keyX, keyY, mSettings.getCurrent(), - mHandler, mKeyboardSwitcher); + mInputLogic.onCodeInput(codeToSend, keyX, keyY, mSettings.getCurrent(), mHandler, + mKeyboardSwitcher); mKeyboardSwitcher.onCodeInput(codePoint); } @@ -1314,27 +1348,28 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Nothing to do so far. } - // TODO: remove this, read this directly from mInputLogic or something in the tests - @UsedForTesting - public boolean isShowingPunctuationList() { - return mInputLogic.isShowingPunctuationList(mSettings.getCurrent()); - } - // TODO[IL]: Define a clear interface for this - public boolean isSuggestionsStripVisible() { - final SettingsValues currentSettings = mSettings.getCurrent(); - if (mSuggestionStripView == null) + public boolean isSuggestionStripVisible() { + if (!hasSuggestionStripView()) { return false; - if (mSuggestionStripView.isShowingAddToDictionaryHint()) + } + if (mSuggestionStripView.isShowingAddToDictionaryHint()) { return true; - if (null == currentSettings) + } + final SettingsValues currentSettings = mSettings.getCurrent(); + if (null == currentSettings) { return false; - if (ImportantNoticeUtils.shouldShowImportantNotice(this, currentSettings.mInputAttributes)) + } + if (ImportantNoticeUtils.shouldShowImportantNotice(this, + currentSettings.mInputAttributes)) { return true; - if (!currentSettings.isSuggestionStripVisible()) + } + if (!currentSettings.isSuggestionStripVisible()) { return false; - if (currentSettings.isApplicationSpecifiedCompletionsOn()) + } + if (currentSettings.isApplicationSpecifiedCompletionsOn()) { return true; + } return currentSettings.isSuggestionsRequested(); } @@ -1350,32 +1385,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void dismissAddToDictionaryHint() { - if (null != mSuggestionStripView) { - mSuggestionStripView.dismissAddToDictionaryHint(); + if (!hasSuggestionStripView()) { + return; } + mSuggestionStripView.dismissAddToDictionaryHint(); } // TODO[IL]: Define a clear interface for this - public void setSuggestedWords(final SuggestedWords suggestedWords, final boolean shouldShow) { + public void setSuggestedWords(final SuggestedWords suggestedWords, + final boolean isSuggestionStripVisible, final boolean needsInputViewShown) { mInputLogic.setSuggestedWords(suggestedWords); - if (mSuggestionStripView != null) { - final SettingsValues currentSettings = mSettings.getCurrent(); - final boolean showSuggestions; - if (SuggestedWords.EMPTY == suggestedWords - || suggestedWords.isPunctuationSuggestions() - || !currentSettings.isSuggestionsRequested()) { - showSuggestions = !mSuggestionStripView.maybeShowImportantNoticeTitle( - currentSettings.mInputAttributes); - } else { - showSuggestions = true; - } - if (showSuggestions) { - mSuggestionStripView.setSuggestions(suggestedWords, - SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype())); - } - mKeyboardSwitcher.onAutoCorrectionStateChanged(suggestedWords.mWillAutoCorrect); - setSuggestionStripShownInternal(shouldShow, true /* needsInputViewShown */); + if (!hasSuggestionStripView()) { + return; + } + final SettingsValues currentSettings = mSettings.getCurrent(); + final boolean showSuggestions; + if (SuggestedWords.EMPTY == suggestedWords + || suggestedWords.isPunctuationSuggestions() + || !currentSettings.isSuggestionsRequested()) { + showSuggestions = !mSuggestionStripView.maybeShowImportantNoticeTitle( + currentSettings.mInputAttributes); + } else { + showSuggestions = true; } + if (showSuggestions) { + mSuggestionStripView.setSuggestions(suggestedWords, + SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype())); + } + mKeyboardSwitcher.onAutoCorrectionStateChanged(suggestedWords.mWillAutoCorrect); + setSuggestionStripShownInternal(isSuggestionStripVisible, needsInputViewShown); } // TODO[IL]: Move this out of LatinIME. @@ -1414,9 +1452,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } suggest.getSuggestedWords(mInputLogic.mWordComposer, mInputLogic.mWordComposer.getPreviousWordForSuggestion(), - keyboard.getProximityInfo(), - currentSettings.mBlockPotentiallyOffensive, currentSettings.mCorrectionEnabled, - additionalFeaturesOptions, sessionId, sequenceNumber, callback); + keyboard.getProximityInfo(), currentSettings.mBlockPotentiallyOffensive, + currentSettings.mCorrectionEnabled, additionalFeaturesOptions, sessionId, + sequenceNumber, callback); } // TODO[IL]: Move this to InputLogic @@ -1430,7 +1468,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // the "add to dictionary" hint, we need to revert to suggestions - although it is unclear // how we can come here if it's displayed. if (suggestedWords.size() > 1 || typedWord.length() <= 1 - || null == mSuggestionStripView || isShowingAddToDictionaryHint()) { + || !hasSuggestionStripView() || isShowingAddToDictionaryHint()) { return suggestedWords; } else { final SuggestedWords punctuationList = @@ -1440,10 +1478,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, oldSuggestedWords); return new SuggestedWords(typedWordAndPreviousSuggestions, null /* rawSuggestions */, - false /* typedWordValid */, - false /* hasAutoCorrectionCandidate */, - true /* isObsoleteSuggestions */, - false /* isPrediction */); + false /* typedWordValid */, false /* hasAutoCorrectionCandidate */, + true /* isObsoleteSuggestions */, false /* isPrediction */); } } @@ -1463,7 +1499,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen setNeutralSuggestionStrip(); } else { mInputLogic.mWordComposer.setAutoCorrection(autoCorrection); - setSuggestedWords(suggestedWords, isSuggestionsStripVisible()); + setSuggestedWords( + suggestedWords, isSuggestionStripVisible(), true /* needsInputViewShown */); } // Cache the auto-correction in accessibility code so we can speak it if the user // touches a key that will insert it. @@ -1481,7 +1518,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void showAddToDictionaryHint(final String word) { - if (null == mSuggestionStripView) return; + if (!hasSuggestionStripView()) { + return; + } mSuggestionStripView.showAddToDictionaryHint(word); } @@ -1490,13 +1529,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // punctuation suggestions (if it's disabled). @Override public void setNeutralSuggestionStrip() { + setNeutralSuggestionStripInternal(true /* needsInputViewShown */); + } + + private void setNeutralSuggestionStripInternal(final boolean needsInputViewShown) { final SettingsValues currentSettings = mSettings.getCurrent(); - if (currentSettings.mBigramPredictionEnabled) { - setSuggestedWords(SuggestedWords.EMPTY, isSuggestionsStripVisible()); - } else { - setSuggestedWords(currentSettings.mSpacingAndPunctuations.mSuggestPuncList, - isSuggestionsStripVisible()); - } + final SuggestedWords neutralSuggestions = currentSettings.mBigramPredictionEnabled + ? SuggestedWords.EMPTY : currentSettings.mSpacingAndPunctuations.mSuggestPuncList; + setSuggestedWords(neutralSuggestions, isSuggestionStripVisible(), needsInputViewShown); } // TODO: Make this private @@ -1638,7 +1678,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen getString(R.string.language_selection_title), getString(ApplicationUtils.getActivityTitleResId(this, SettingsActivity.class)), }; - final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { + final OnClickListener listener = new OnClickListener() { @Override public void onClick(DialogInterface di, int position) { di.dismiss(); @@ -1659,18 +1699,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen }; final AlertDialog.Builder builder = new AlertDialog.Builder(this).setItems(items, listener).setTitle(title); - showOptionDialog(builder.create(), true /*cancelable */); + showOptionDialog(builder.create()); } // TODO: Move this method out of {@link LatinIME}. - private void showOptionDialog(final AlertDialog dialog, final boolean cancelable) { + private void showOptionDialog(final AlertDialog dialog) { final IBinder windowToken = mKeyboardSwitcher.getMainKeyboardView().getWindowToken(); if (windowToken == null) { return; } - dialog.setCancelable(cancelable); - dialog.setCanceledOnTouchOutside(cancelable); + dialog.setCancelable(true /* cancelable */); + dialog.setCanceledOnTouchOutside(true /* cancelable */); final Window window = dialog.getWindow(); final WindowManager.LayoutParams lp = window.getAttributes(); @@ -1685,7 +1725,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // TODO: can this be removed somehow without breaking the tests? @UsedForTesting - /* package for test */ SuggestedWords getSuggestedWords() { + /* package for test */ SuggestedWords getSuggestedWordsForTest() { // You may not use this method for anything else than debug return DEBUG ? mInputLogic.mSuggestedWords : null; } diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index eb1899ca2..ebad9bc0d 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -230,6 +230,9 @@ public final class RichInputConnection { public void finishComposingText() { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); + // TODO: this is not correct! The cursor is not necessarily after the composing text. + // In the practice right now this is only called when input ends so it will be reset so + // it works, but it's wrong and should be fixed. mCommittedTextBeforeComposingText.append(mComposingText); mComposingText.setLength(0); if (null != mIC) { @@ -244,6 +247,9 @@ public final class RichInputConnection { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); mCommittedTextBeforeComposingText.append(text); + // TODO: the following is exceedingly error-prone. Right now when the cursor is in the + // middle of the composing word mComposingText only holds the part of the composing text + // that is before the cursor, so this actually works, but it's terribly confusing. Fix this. mExpectedSelStart += text.length() - mComposingText.length(); mExpectedSelEnd = mExpectedSelStart; mComposingText.setLength(0); @@ -347,6 +353,9 @@ public final class RichInputConnection { public void deleteSurroundingText(final int beforeLength, final int afterLength) { if (DEBUG_BATCH_NESTING) checkBatchEdit(); + // TODO: the following is incorrect if the cursor is not immediately after the composition. + // Right now we never come here in this case because we reset the composing state before we + // come here in this case, but we need to fix this. final int remainingChars = mComposingText.length() - beforeLength; if (remainingChars >= 0) { mComposingText.setLength(remainingChars); @@ -447,8 +456,12 @@ public final class RichInputConnection { getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE + (end - start), 0); mCommittedTextBeforeComposingText.setLength(0); if (!TextUtils.isEmpty(textBeforeCursor)) { + // The cursor is not necessarily at the end of the composing text, but we have its + // position in mExpectedSelStart and mExpectedSelEnd. In this case we want the start + // of the text, so we should use mExpectedSelStart. In other words, the composing + // text starts (mExpectedSelStart - start) characters before the end of textBeforeCursor final int indexOfStartOfComposingText = - Math.max(textBeforeCursor.length() - (end - start), 0); + Math.max(textBeforeCursor.length() - (mExpectedSelStart - start), 0); mComposingText.append(textBeforeCursor.subSequence(indexOfStartOfComposingText, textBeforeCursor.length())); mCommittedTextBeforeComposingText.append( @@ -544,6 +557,9 @@ public final class RichInputConnection { final int checkLength = LOOKBACK_CHARACTER_NUM - 1; final String reference = prev.length() <= checkLength ? prev.toString() : prev.subSequence(prev.length() - checkLength, prev.length()).toString(); + // TODO: right now the following works because mComposingText holds the part of the + // composing text that is before the cursor, but this is very confusing. We should + // fix it. final StringBuilder internal = new StringBuilder() .append(mCommittedTextBeforeComposingText).append(mComposingText); if (internal.length() > checkLength) { diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 9bf9d1f45..3fc2cf8fd 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -198,7 +198,7 @@ public final class InputLogic { final SuggestedWords suggestedWords = mSuggestedWords; final String suggestion = suggestionInfo.mWord; // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput - if (suggestion.length() == 1 && isShowingPunctuationList(settingsValues)) { + if (suggestion.length() == 1 && suggestedWords.isPunctuationSuggestions()) { // Word separators are suggested before the user inputs something. // So, LatinImeLogger logs "" as a user's input. LatinImeLogger.logOnManualSuggestion("", suggestion, index, suggestedWords); @@ -821,7 +821,7 @@ public final class InputLogic { if (maybeDoubleSpacePeriod(settingsValues, handler)) { keyboardSwitcher.updateShiftState(); mSpaceState = SpaceState.DOUBLE; - } else if (!isShowingPunctuationList(settingsValues)) { + } else if (!mSuggestedWords.isPunctuationSuggestions()) { mSpaceState = SpaceState.WEAK; } } @@ -1456,15 +1456,6 @@ public final class InputLogic { } /** - * Find out if the punctuation list is shown in the suggestion strip. - * @return whether the current suggestions are the punctuation list. - */ - // TODO: make this private. It's used through LatinIME for tests. - public boolean isShowingPunctuationList(final SettingsValues settingsValues) { - return settingsValues.mSpacingAndPunctuations.mSuggestPuncList == mSuggestedWords; - } - - /** * Factor in auto-caps and manual caps and compute the current caps mode. * @param settingsValues the current settings values. * @param keyboardShiftMode the current shift mode of the keyboard. See diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java index 315bd8e58..71e120c5f 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java @@ -173,6 +173,9 @@ public class Ver2DictDecoder extends AbstractDictDecoder { @Override public DictionaryHeader readHeader() throws IOException, UnsupportedFormatException { final DictionaryHeader header = mBinaryDictionary.getHeader(); + if (header == null) { + throw new IOException("Cannot read the dictionary header."); + } if (header.mFormatOptions.mVersion != FormatSpec.VERSION2) { throw new UnsupportedFormatException("File header has a wrong version : " + header.mFormatOptions.mVersion); diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java index df64bcec1..5ae2fb6f8 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java @@ -93,13 +93,16 @@ public class PersonalizationHelper { } } - public static void removeAllPersonalizedDictionaries(final Context context) { - removeAllDictionaries(context, sLangUserHistoryDictCache, - UserHistoryDictionary.NAME); + public static void removeAllPersonalizationDictionaries(final Context context) { removeAllDictionaries(context, sLangPersonalizationDictCache, PersonalizationDictionary.NAME); } + public static void removeAllUserHistoryDictionaries(final Context context) { + removeAllDictionaries(context, sLangUserHistoryDictCache, + UserHistoryDictionary.NAME); + } + private static <T extends DecayingExpandableBinaryDictionaryBase> void removeAllDictionaries( final Context context, final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap, final String dictNamePrefix) { diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java index b51c765f0..6a1503fed 100644 --- a/java/src/com/android/inputmethod/latin/settings/Settings.java +++ b/java/src/com/android/inputmethod/latin/settings/Settings.java @@ -55,7 +55,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_MISC_SETTINGS = "misc_settings"; public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings"; public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; - public static final String PREF_KEY_USE_PERSONALIZED_DICTS = "pref_key_use_personalized_dicts"; + public static final String PREF_USE_PERSONALIZED_DICTS = "pref_use_personalized_dicts"; public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD = "pref_key_use_double_space_period"; public static final String PREF_BLOCK_POTENTIALLY_OFFENSIVE = @@ -421,6 +421,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return mPrefs.getStringSet(PREF_CORPUS_HANDLES_FOR_PERSONALIZATION, emptySet); } + public void writeUsePersonalizationDictionary(final boolean enabled) { + mPrefs.edit().putBoolean(PREF_USE_PERSONALIZED_DICTS, enabled).apply(); + } + public static void writeEmojiRecentKeys(final SharedPreferences prefs, String str) { prefs.edit().putString(PREF_EMOJI_RECENT_KEYS, str).apply(); } diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index 77968f79a..0f3deeaa9 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -128,7 +128,7 @@ public final class SettingsValues { Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false); mShowsLanguageSwitchKey = Settings.readShowsLanguageSwitchKey(prefs); mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); - mUsePersonalizedDicts = prefs.getBoolean(Settings.PREF_KEY_USE_PERSONALIZED_DICTS, true); + mUsePersonalizedDicts = prefs.getBoolean(Settings.PREF_USE_PERSONALIZED_DICTS, false); mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true); mBlockPotentiallyOffensive = Settings.readBlockPotentiallyOffensive(prefs, res); mAutoCorrectEnabled = Settings.readAutoCorrectEnabled(autoCorrectionThresholdRawValue, res); diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index e77c55069..8ea712835 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -504,12 +504,13 @@ final class SuggestionStripLayoutHelper { hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); } - public void layoutImportantNotice(final View importantNoticeStrip, final int stripWidth) { + public void layoutImportantNotice(final View importantNoticeStrip, final int stripWidth, + final String importantNoticeTitle) { final TextView titleView = (TextView)importantNoticeStrip.findViewById( R.id.important_notice_title); final int width = stripWidth - titleView.getPaddingLeft() - titleView.getPaddingRight(); titleView.setTextColor(mColorAutoCorrect); - final CharSequence importantNoticeTitle = titleView.getText(); + titleView.setText(importantNoticeTitle); titleView.setTextScaleX(1.0f); // Reset textScaleX. final float titleScaleX = getTextScaleX( importantNoticeTitle, width, titleView.getPaint()); diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index 90b9692c3..2966a8bba 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Color; import android.support.v4.view.ViewCompat; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; import android.view.GestureDetector; @@ -233,8 +234,15 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick return false; } final int width = getWidth(); - if (width <= 0) return false; - mLayoutHelper.layoutImportantNotice(mImportantNoticeStrip, width); + if (width <= 0) { + return false; + } + final String importantNoticeTitle = ImportantNoticeUtils.getImportantNoticeTitle( + getContext()); + if (TextUtils.isEmpty(importantNoticeTitle)) { + return false; + } + mLayoutHelper.layoutImportantNotice(mImportantNoticeStrip, width, importantNoticeTitle); mStripVisibilityGroup.showImportantNoticeStrip(); mImportantNoticeStrip.setOnClickListener(this); return true; @@ -429,9 +437,11 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { + protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { // Called by the framework when the size is known. Show the important notice if applicable. // This may be overriden by showing suggestions later, if applicable. - maybeShowImportantNoticeTitle(Settings.getInstance().getCurrent().mInputAttributes); + if (oldw <= 0 && w > 0) { + maybeShowImportantNoticeTitle(Settings.getInstance().getCurrent().mInputAttributes); + } } } diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java index 32c4950da..2f41ce9ce 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java @@ -61,12 +61,17 @@ public class UserDictionaryList extends PreferenceFragment { if (null == cursor) { // The user dictionary service is not present or disabled. Return null. return null; - } else if (cursor.moveToFirst()) { - final int columnIndex = cursor.getColumnIndex(UserDictionary.Words.LOCALE); - do { - final String locale = cursor.getString(columnIndex); - localeSet.add(null != locale ? locale : ""); - } while (cursor.moveToNext()); + } + try { + if (cursor.moveToFirst()) { + final int columnIndex = cursor.getColumnIndex(UserDictionary.Words.LOCALE); + do { + final String locale = cursor.getString(columnIndex); + localeSet.add(null != locale ? locale : ""); + } while (cursor.moveToNext()); + } + } finally { + cursor.close(); } if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) { // For ICS, we need to show "For all languages" in case that the keyboard locale diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java index 7571e87c5..220efb5d3 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java @@ -140,6 +140,8 @@ public class UserDictionarySettings extends ListFragment { } mLocale = locale; + // WARNING: The following cursor is never closed! TODO: don't put that in a member, and + // make sure all cursors are correctly closed. mCursor = createCursor(locale); TextView emptyView = (TextView) getView().findViewById(android.R.id.empty); emptyView.setText(R.string.user_dict_settings_empty_text); diff --git a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java index 50a942382..dd418b8cf 100644 --- a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java @@ -32,6 +32,7 @@ public final class ImportantNoticeUtils { // displayed to users. private static final String PREFERENCE_NAME = "important_notice"; private static final String KEY_IMPORTANT_NOTICE_VERSION = "important_notice_version"; + public static final int VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS = 2; // Copy of the hidden {@link Settings.Secure#USER_SETUP_COMPLETE} settings key. // The value is zero until each multiuser completes system setup wizard. @@ -59,7 +60,7 @@ public final class ImportantNoticeUtils { return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); } - private static int getCurrentImportantNoticeVersion(final Context context) { + public static int getCurrentImportantNoticeVersion(final Context context) { return context.getResources().getInteger(R.integer.config_important_notice_version); } @@ -83,4 +84,22 @@ public final class ImportantNoticeUtils { .putInt(KEY_IMPORTANT_NOTICE_VERSION, getCurrentImportantNoticeVersion(context)) .apply(); } + + public static String getImportantNoticeTitle(final Context context) { + switch (getCurrentImportantNoticeVersion(context)) { + case VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS: + return context.getString(R.string.important_notice_title); + default: + return null; + } + } + + public static String getImportantNoticeContents(final Context context) { + switch (getCurrentImportantNoticeVersion(context)) { + case VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS: + return context.getString(R.string.important_notice_contents); + default: + return null; + } + } } |