diff options
Diffstat (limited to 'java/src')
20 files changed, 311 insertions, 165 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java index 4c53b528f..7fff46aaf 100644 --- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java +++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java @@ -25,7 +25,6 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Rect; -import android.graphics.Typeface; import android.os.Build; import android.os.CountDownTimer; import android.preference.PreferenceManager; @@ -49,6 +48,8 @@ import android.widget.TextView; import com.android.inputmethod.keyboard.internal.DynamicGridKeyboard; import com.android.inputmethod.keyboard.internal.EmojiLayoutParams; import com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView; +import com.android.inputmethod.keyboard.internal.KeyDrawParams; +import com.android.inputmethod.keyboard.internal.KeyVisualAttributes; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SubtypeSwitcher; @@ -634,20 +635,23 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange // TODO: } - // Hack: These parameters are hacky. - public void startEmojiPalettes(final String switchToAlphaLabel, final int switchToAlphaColor, - final float switchToAlphaSize, final Typeface switchToAlphaTypeface) { + private static void setupAlphabetKey(final TextView alphabetKey, final String label, + final KeyDrawParams params) { + alphabetKey.setText(label); + alphabetKey.setTextColor(params.mTextColor); + alphabetKey.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mLabelSize); + alphabetKey.setTypeface(params.mTypeface); + } + + public void startEmojiPalettes(final String switchToAlphaLabel, + final KeyVisualAttributes keyVisualAttr) { if (DEBUG_PAGER) { Log.d(TAG, "allocate emoji palettes memory " + mCurrentPagerPosition); } - mAlphabetKeyLeft.setText(switchToAlphaLabel); - mAlphabetKeyLeft.setTextColor(switchToAlphaColor); - mAlphabetKeyLeft.setTextSize(TypedValue.COMPLEX_UNIT_PX, switchToAlphaSize); - mAlphabetKeyLeft.setTypeface(switchToAlphaTypeface); - mAlphabetKeyRight.setText(switchToAlphaLabel); - mAlphabetKeyRight.setTextColor(switchToAlphaColor); - mAlphabetKeyRight.setTextSize(TypedValue.COMPLEX_UNIT_PX, switchToAlphaSize); - mAlphabetKeyRight.setTypeface(switchToAlphaTypeface); + final KeyDrawParams params = new KeyDrawParams(); + params.updateParams(mEmojiLayoutParams.getActionBarHeight(), keyVisualAttr); + setupAlphabetKey(mAlphabetKeyLeft, switchToAlphaLabel, params); + setupAlphabetKey(mAlphabetKeyRight, switchToAlphaLabel, params); mEmojiPager.setAdapter(mEmojiPalettesAdapter); mEmojiPager.setCurrentItem(mCurrentPagerPosition); } diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index ceda9ee9a..afaf2cc57 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -137,8 +137,6 @@ public class Key implements Comparable<Key> { private final OptionalAttributes mOptionalAttributes; - private static final int DEFAULT_TEXT_COLOR = 0xFFFFFFFF; - private static final class OptionalAttributes { /** Text to output when pressed. This can be multiple characters, like ".com" */ public final String mOutputText; @@ -585,22 +583,7 @@ public class Key implements Comparable<Key> { } public final int selectTextColor(final KeyDrawParams params) { - if (isShiftedLetterActivated()) { - return params.mTextInactivatedColor; - } - if (params.mTextColorStateList == null) { - return DEFAULT_TEXT_COLOR; - } - final int[] state; - // TODO: Hack!!!!!!!! Consider having a new attribute for the functional text labels. - // Currently, we distinguish "input key" from "functional key" by checking the - // length of the label( > 1) and "functional" attributes (= true). - if (mLabel != null && mLabel.length() > 1) { - state = getCurrentDrawableState(); - } else { - state = KEY_STATE_NORMAL; - } - return params.mTextColorStateList.getColorForState(state, DEFAULT_TEXT_COLOR); + return isShiftedLetterActivated() ? params.mTextInactivatedColor : params.mTextColor; } public final int selectHintTextSize(final KeyDrawParams params) { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 6215e2710..f9758634e 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -19,7 +19,6 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; -import android.graphics.Paint; import android.preference.PreferenceManager; import android.util.Log; import android.view.ContextThemeWrapper; @@ -31,7 +30,7 @@ import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.compat.InputMethodServiceCompatUtils; import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException; import com.android.inputmethod.keyboard.internal.KeyboardState; -import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.keyboard.internal.KeyboardTextsSet; import com.android.inputmethod.latin.InputView; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; @@ -81,8 +80,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { private KeyboardState mState; private KeyboardLayoutSet mKeyboardLayoutSet; + // TODO: The following {@link KeyboardTextsSet} should be in {@link KeyboardLayoutSet}. + private final KeyboardTextsSet mKeyboardTextsSet = new KeyboardTextsSet(); private SettingsValues mCurrentSettingsValues; - private Key mSwitchToAlphaKey; /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of * what user actually typed. */ @@ -163,8 +163,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { mCurrentSettingsValues = settingsValues; try { mState.onLoadKeyboard(); - final Keyboard symbols = mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS); - mSwitchToAlphaKey = symbols.getKey(Constants.CODE_SWITCH_ALPHA_SYMBOL); + mKeyboardTextsSet.setLocale(mSubtypeSwitcher.getCurrentSubtypeLocale()); } catch (KeyboardLayoutSetException e) { Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); LatinImeLogger.logOnException(e.mKeyboardId.toString(), e.getCause()); @@ -290,10 +289,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { @Override public void setEmojiKeyboard() { mMainKeyboardFrame.setVisibility(View.GONE); - final Paint paint = mKeyboardView.newLabelPaint(mSwitchToAlphaKey); mEmojiPalettesView.startEmojiPalettes( - mSwitchToAlphaKey.getLabel(), paint.getColor(), paint.getTextSize(), - paint.getTypeface()); + mKeyboardTextsSet.getText(KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL), + mKeyboardView.getKeyVisualAttribute()); mEmojiPalettesView.setVisibility(View.VISIBLE); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index dd3ab9cce..18e51d392 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -146,6 +146,10 @@ public class KeyboardView extends View { mPaint.setAntiAlias(true); } + public KeyVisualAttributes getKeyVisualAttribute() { + return mKeyVisualAttributes; + } + private static void blendAlpha(final Paint paint, final int alpha) { final int color = paint.getColor(); paint.setARGB((paint.getAlpha() * alpha) / Constants.Color.ALPHA_OPAQUE, diff --git a/java/src/com/android/inputmethod/keyboard/internal/EmojiLayoutParams.java b/java/src/com/android/inputmethod/keyboard/internal/EmojiLayoutParams.java index 12e063261..d57ea5a94 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/EmojiLayoutParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/EmojiLayoutParams.java @@ -73,9 +73,13 @@ public class EmojiLayoutParams { ll.setLayoutParams(lp); } + public int getActionBarHeight() { + return mEmojiActionBarHeight - mBottomPadding; + } + public void setActionBarProperties(final LinearLayout ll) { final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ll.getLayoutParams(); - lp.height = mEmojiActionBarHeight - mBottomPadding; + lp.height = getActionBarHeight(); ll.setLayoutParams(lp); } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java index b528b692e..1716fa049 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java @@ -16,7 +16,6 @@ package com.android.inputmethod.keyboard.internal; -import android.content.res.ColorStateList; import android.graphics.Typeface; import com.android.inputmethod.latin.utils.ResourceUtils; @@ -33,7 +32,7 @@ public final class KeyDrawParams { public int mHintLabelSize; public int mPreviewTextSize; - public ColorStateList mTextColorStateList; + public int mTextColor; public int mTextInactivatedColor; public int mTextShadowColor; public int mHintLetterColor; @@ -58,7 +57,7 @@ public final class KeyDrawParams { mHintLabelSize = copyFrom.mHintLabelSize; mPreviewTextSize = copyFrom.mPreviewTextSize; - mTextColorStateList = copyFrom.mTextColorStateList; + mTextColor = copyFrom.mTextColor; mTextInactivatedColor = copyFrom.mTextInactivatedColor; mTextShadowColor = copyFrom.mTextShadowColor; mHintLetterColor = copyFrom.mHintLetterColor; @@ -90,8 +89,8 @@ public final class KeyDrawParams { attr.mShiftedLetterHintRatio, mShiftedLetterHintSize); mHintLabelSize = selectTextSize(keyHeight, attr.mHintLabelRatio, mHintLabelSize); mPreviewTextSize = selectTextSize(keyHeight, attr.mPreviewTextRatio, mPreviewTextSize); - mTextColorStateList = - attr.mTextColorStateList != null ? attr.mTextColorStateList : mTextColorStateList; + + mTextColor = selectColor(attr.mTextColor, mTextColor); mTextInactivatedColor = selectColor(attr.mTextInactivatedColor, mTextInactivatedColor); mTextShadowColor = selectColor(attr.mTextShadowColor, mTextShadowColor); mHintLetterColor = selectColor(attr.mHintLetterColor, mHintLetterColor); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java b/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java index c3e0aa685..df386fce4 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java @@ -16,7 +16,6 @@ package com.android.inputmethod.keyboard.internal; -import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.Typeface; import android.util.SparseIntArray; @@ -38,7 +37,7 @@ public final class KeyVisualAttributes { public final float mHintLabelRatio; public final float mPreviewTextRatio; - public final ColorStateList mTextColorStateList; + public final int mTextColor; public final int mTextInactivatedColor; public final int mTextShadowColor; public final int mHintLetterColor; @@ -119,7 +118,7 @@ public final class KeyVisualAttributes { mPreviewTextRatio = ResourceUtils.getFraction(keyAttr, R.styleable.Keyboard_Key_keyPreviewTextRatio); - mTextColorStateList = keyAttr.getColorStateList(R.styleable.Keyboard_Key_keyTextColor); + mTextColor = keyAttr.getColor(R.styleable.Keyboard_Key_keyTextColor, 0); mTextInactivatedColor = keyAttr.getColor( R.styleable.Keyboard_Key_keyTextInactivatedColor, 0); mTextShadowColor = keyAttr.getColor(R.styleable.Keyboard_Key_keyTextShadowColor, 0); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index 89221ba24..976038c10 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -29,6 +29,8 @@ import java.util.Locale; public final class KeyboardTextsSet { public static final String PREFIX_TEXT = "!text/"; + public static final String SWITCH_TO_ALPHA_KEY_LABEL = "label_to_alpha_key"; + private static final char BACKSLASH = Constants.CODE_BACKSLASH; private static final int MAX_STRING_REFERENCE_INDIRECTION = 10; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java index 93d80c909..96acb1551 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java @@ -24,7 +24,8 @@ import java.util.HashMap; * !!!!! DO NOT EDIT THIS FILE !!!!! * * This file is generated by tools/make-keyboard-text. The base template file is - * tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl + * tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/ + * KeyboardTextsTable.tmpl * * This file must be updated when any text resources in keyboard layout files have been changed. * These text resources are referred as "!text/<resource_name>" in keyboard XML definitions, @@ -34,7 +35,7 @@ import java.util.HashMap; * To update this file, please run the following commands. * $ cd $ANDROID_BUILD_TOP * $ mmm packages/inputmethods/LatinIME/tools/make-keyboard-text - * $ make-keyboard-text -java packages/inputmethods/LatinIME/java/src + * $ make-keyboard-text -java packages/inputmethods/LatinIME/java * * The updated source file will be generated to the following path (this file). * packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/internal/ diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 013f9220a..c450a1d4f 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -17,6 +17,7 @@ package com.android.inputmethod.latin; import android.text.TextUtils; +import android.util.Log; import android.util.SparseArray; import com.android.inputmethod.annotations.UsedForTesting; @@ -29,6 +30,7 @@ import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.settings.NativeSuggestOptions; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.JniUtils; import com.android.inputmethod.latin.utils.LanguageModelParam; import com.android.inputmethod.latin.utils.StringUtils; @@ -84,6 +86,7 @@ public final class BinaryDictionary extends Dictionary { private final Locale mLocale; private final long mDictSize; private final String mDictFilePath; + private final boolean mIsUpdatable; private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH]; private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS]; private final int[] mSpaceIndices = new int[MAX_RESULTS]; @@ -130,6 +133,7 @@ public final class BinaryDictionary extends Dictionary { mLocale = locale; mDictSize = length; mDictFilePath = filename; + mIsUpdatable = isUpdatable; mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance); loadDictionary(filename, offset, length, isUpdatable); } @@ -177,6 +181,7 @@ public final class BinaryDictionary extends Dictionary { int bigramProbability); private static native int setCurrentTimeForTestNative(int currentTime); private static native String getPropertyNative(long dict, String query); + private static native boolean isCorruptedNative(long dict); public static boolean createEmptyDictFile(final String filePath, final long dictVersion, final Locale locale, final Map<String, String> attributeMap) { @@ -198,6 +203,22 @@ public final class BinaryDictionary extends Dictionary { mNativeDict = openNative(path, startOffset, length, isUpdatable); } + // TODO: Check isCorrupted() for main dictionaries. + public boolean isCorrupted() { + if (!isValidDictionary()) { + return false; + } + if (!isCorruptedNative(mNativeDict)) { + return false; + } + // TODO: Record the corruption. + Log.e(TAG, "BinaryDictionary (" + mDictFilePath + ") is corrupted."); + Log.e(TAG, "locale: " + mLocale); + Log.e(TAG, "dict size: " + mDictSize); + Log.e(TAG, "updatable: " + mIsUpdatable); + return true; + } + @UsedForTesting public DictionaryHeader getHeader() throws UnsupportedFormatException { if (mNativeDict == 0) { @@ -444,7 +465,7 @@ public final class BinaryDictionary extends Dictionary { // only be called for actual files. Right now it's only called by the flush() family of // functions, which require an updatable dictionary, so it's okay. But beware. loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */, - dictFile.length(), true /* isUpdatable */); + dictFile.length(), mIsUpdatable); } public void flush() { diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java index 138a626a0..e767e4be9 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java @@ -232,11 +232,35 @@ public class DictionaryFacilitatorForSuggest { return null != mPersonalizationDictionary; } + public void flushPersonalizationDictionary() { + if (hasPersonalizationDictionary()) { + mPersonalizationDictionary.flush(); + } + } + public void waitForLoadingMainDictionary(final long timeout, final TimeUnit unit) throws InterruptedException { mLatchForWaitingLoadingMainDictionary.await(timeout, unit); } + @UsedForTesting + public void waitForLoadingDictionariesForTesting(final long timeout, final TimeUnit unit) + throws InterruptedException { + waitForLoadingMainDictionary(timeout, unit); + if (mContactsDictionary != null) { + mContactsDictionary.waitAllTasksForTests(); + } + if (mUserDictionary != null) { + mUserDictionary.waitAllTasksForTests(); + } + if (mUserHistoryDictionary != null) { + mUserHistoryDictionary.waitAllTasksForTests(); + } + if (mPersonalizationDictionary != null) { + mPersonalizationDictionary.waitAllTasksForTests(); + } + } + private void setMainDictionary(final Dictionary mainDictionary) { mMainDictionary = mainDictionary; addOrReplaceDictionary(Dictionary.TYPE_MAIN, mainDictionary); diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 230739d6f..f9ab9419b 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -276,22 +276,26 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return attributeMap; } + private void removeBinaryDictionaryLocked() { + if (mBinaryDictionary != null) { + mBinaryDictionary.close(); + } + if (mDictFile.exists() && !FileUtils.deleteRecursively(mDictFile)) { + Log.e(TAG, "Can't remove a file: " + mDictFile.getName()); + } + mBinaryDictionary = null; + } + protected void clear() { - final File dictFile = mDictFile; getExecutor(mDictName).execute(new Runnable() { @Override public void run() { if (mDictionaryWriter == null) { - if (mBinaryDictionary != null) { - mBinaryDictionary.close(); - } - if (dictFile.exists() && !FileUtils.deleteRecursively(dictFile)) { - Log.e(TAG, "Can't remove a file: " + dictFile.getName()); - } - BinaryDictionary.createEmptyDictFile(dictFile.getAbsolutePath(), + removeBinaryDictionaryLocked(); + BinaryDictionary.createEmptyDictFile(mDictFile.getAbsolutePath(), DICTIONARY_FORMAT_VERSION, mLocale, getHeaderAttributeMap()); mBinaryDictionary = new BinaryDictionary( - dictFile.getAbsolutePath(), 0 /* offset */, dictFile.length(), + mDictFile.getAbsolutePath(), 0 /* offset */, mDictFile.length(), true /* useFullEditDistance */, mLocale, mDictType, mIsUpdatable); } else { mDictionaryWriter.clear(); @@ -469,6 +473,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { proximityInfo, blockOffensiveWords, additionalFeaturesOptions, sessionId); holder.set(binarySuggestion); + if (mBinaryDictionary.isCorrupted()) { + removeBinaryDictionaryLocked(); + } } }); return holder.get(null, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS); 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 346ba8523..44282a492 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; @@ -751,6 +750,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen + ", word caps = " + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0)); } + Log.i(TAG, "Starting input. Cursor position = " + + editorInfo.initialSelStart + "," + editorInfo.initialSelEnd); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, prefs); @@ -799,19 +800,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 +1181,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() { @@ -1717,9 +1705,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME. @UsedForTesting - /* package for test */ void waitForMainDictionary(final long timeout, final TimeUnit unit) + /* package for test */ void waitForLoadingDictionaries(final long timeout, final TimeUnit unit) throws InterruptedException { - mInputLogic.mSuggest.mDictionaryFacilitator.waitForLoadingMainDictionary(timeout, unit); + mInputLogic.mSuggest.mDictionaryFacilitator.waitForLoadingDictionariesForTesting( + timeout, unit); } // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly. @@ -1733,6 +1722,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen resetSuggest(new Suggest(locale, dictionaryFacilitator)); } + // DO NOT USE THIS for any other purpose than testing. + @UsedForTesting + /* package for test */ void clearPersonalizedDictionariesForTest() { + mInputLogic.mSuggest.mDictionaryFacilitator.clearUserHistoryDictionary(); + mInputLogic.mSuggest.mDictionaryFacilitator.clearPersonalizationDictionary(); + } + public void dumpDictionaryForDebug(final String dictName) { if (mInputLogic.mSuggest == null) { initSuggest(); diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index cc2db4c93..323256d1c 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) { @@ -497,12 +483,16 @@ public final class RichInputConnection { * * @param start the character index where the selection should start. * @param end the character index where the selection should end. - * @return Returns true on success, false if the input connection is no longer valid either when - * setting the selection or when retrieving the text cache at that point. + * @return Returns true on success, false on failure: either the input connection is no longer + * valid when setting the selection or when retrieving the text cache at that point, or + * invalid arguments were passed. */ public boolean setSelection(final int start, final int end) { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); + if (start < 0 || end < 0) { + return false; + } mExpectedSelStart = start; mExpectedSelEnd = end; if (null != mIC) { @@ -861,9 +851,9 @@ public final class RichInputConnection { mExpectedSelStart = mExpectedSelEnd = Constants.NOT_A_CURSOR_POSITION; } else { final int textLength = textBeforeCursor.length(); - if (textLength > mExpectedSelStart - || (textLength < Constants.EDITOR_CONTENTS_CACHE_SIZE - && mExpectedSelStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) { + if (textLength < Constants.EDITOR_CONTENTS_CACHE_SIZE + && (textLength > mExpectedSelStart + || mExpectedSelStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) { // It should not be possible to have only one of those variables be // NOT_A_CURSOR_POSITION, so if they are equal, either the selection is zero-sized // (simple cursor, no selection) or there is no cursor/we don't know its pos diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 52a6f5f08..045d06f0e 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 @@ -484,6 +490,7 @@ public final class InputLogic { handler.showGesturePreviewAndSuggestionStrip( SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */); handler.cancelUpdateSuggestionStrip(); + ++mAutoCommitSequenceNumber; mConnection.beginBatchEdit(); if (mWordComposer.isComposingWord()) { if (settingsValues.mIsInternal) { @@ -498,7 +505,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 @@ -581,6 +588,7 @@ public final class InputLogic { public void onEndBatchInput(final SettingsValues settingValues, final InputPointers batchPointers) { mInputLogicHandler.onEndBatchInput(batchPointers, mAutoCommitSequenceNumber); + ++mAutoCommitSequenceNumber; } // TODO: remove this argument @@ -651,7 +659,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 +701,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 +783,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 +889,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 +1260,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 +1624,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/makedict/Ver2DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java index 71e120c5f..bf776cfc5 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java @@ -120,16 +120,10 @@ public class Ver2DictDecoder extends AbstractDictDecoder { // used only for testing. private final DictionaryBufferFactory mBufferFactory; protected DictBuffer mDictBuffer; - private final BinaryDictionary mBinaryDictionary; /* package */ Ver2DictDecoder(final File file, final int factoryFlag) { mDictionaryBinaryFile = file; mDictBuffer = null; - // dictType is not being used in dicttool. Passing an empty string. - mBinaryDictionary = new BinaryDictionary(file.getAbsolutePath(), - 0 /* offset */, file.length() /* length */, true /* useFullEditDistance */, - null /* locale */, "" /* dictType */, false /* isUpdatable */); - if ((factoryFlag & MASK_DICTBUFFER) == USE_READONLY_BYTEBUFFER) { mBufferFactory = new DictionaryBufferFromReadOnlyByteBufferFactory(); } else if ((factoryFlag & MASK_DICTBUFFER) == USE_BYTEARRAY) { @@ -144,10 +138,6 @@ public class Ver2DictDecoder extends AbstractDictDecoder { /* package */ Ver2DictDecoder(final File file, final DictionaryBufferFactory factory) { mDictionaryBinaryFile = file; mBufferFactory = factory; - // dictType is not being used in dicttool. Passing an empty string. - mBinaryDictionary = new BinaryDictionary(file.getAbsolutePath(), - 0 /* offset */, file.length() /* length */, true /* useFullEditDistance */, - null /* locale */, "" /* dictType */, false /* isUpdatable */); } @Override @@ -172,7 +162,13 @@ public class Ver2DictDecoder extends AbstractDictDecoder { @Override public DictionaryHeader readHeader() throws IOException, UnsupportedFormatException { - final DictionaryHeader header = mBinaryDictionary.getHeader(); + // dictType is not being used in dicttool. Passing an empty string. + final BinaryDictionary binaryDictionary = new BinaryDictionary( + mDictionaryBinaryFile.getAbsolutePath(), 0 /* offset */, + mDictionaryBinaryFile.length() /* length */, true /* useFullEditDistance */, + null /* locale */, "" /* dictType */, false /* isUpdatable */); + final DictionaryHeader header = binaryDictionary.getHeader(); + binaryDictionary.close(); if (header == null) { throw new IOException("Cannot read the dictionary header."); } @@ -254,6 +250,11 @@ public class Ver2DictDecoder extends AbstractDictDecoder { @Override public FusionDictionary readDictionaryBinary(final boolean deleteDictIfBroken) throws FileNotFoundException, IOException, UnsupportedFormatException { + // dictType is not being used in dicttool. Passing an empty string. + final BinaryDictionary binaryDictionary = new BinaryDictionary( + mDictionaryBinaryFile.getAbsolutePath(), 0 /* offset */, + mDictionaryBinaryFile.length() /* length */, true /* useFullEditDistance */, + null /* locale */, "" /* dictType */, false /* isUpdatable */); final DictionaryHeader header = readHeader(); final FusionDictionary fusionDict = new FusionDictionary(new FusionDictionary.PtNodeArray(), header.mDictionaryOptions); @@ -261,11 +262,11 @@ public class Ver2DictDecoder extends AbstractDictDecoder { final ArrayList<WordProperty> wordProperties = CollectionUtils.newArrayList(); do { final BinaryDictionary.GetNextWordPropertyResult result = - mBinaryDictionary.getNextWordProperty(token); + binaryDictionary.getNextWordProperty(token); final WordProperty wordProperty = result.mWordProperty; if (wordProperty == null) { + binaryDictionary.close(); if (deleteDictIfBroken) { - mBinaryDictionary.close(); mDictionaryBinaryFile.delete(); } return null; @@ -294,6 +295,7 @@ public class Ver2DictDecoder extends AbstractDictDecoder { fusionDict.setBigram(word0, bigram.mWord, bigram.mProbabilityInfo); } } + binaryDictionary.close(); return fusionDict; } diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java index 88fff38f2..afe82317e 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java @@ -35,7 +35,6 @@ public class Ver4DictDecoder extends AbstractDictDecoder { private static final String TAG = Ver4DictDecoder.class.getSimpleName(); final File mDictDirectory; - final BinaryDictionary mBinaryDictionary; @UsedForTesting /* package */ Ver4DictDecoder(final File dictDirectory, final int factoryFlag) { @@ -45,24 +44,32 @@ public class Ver4DictDecoder extends AbstractDictDecoder { @UsedForTesting /* package */ Ver4DictDecoder(final File dictDirectory, final DictionaryBufferFactory factory) { mDictDirectory = dictDirectory; - // dictType is not being used in dicttool. Passing an empty string. - mBinaryDictionary = new BinaryDictionary(dictDirectory.getAbsolutePath(), - 0 /* offset */, 0 /* length */, true /* useFullEditDistance */, null /* locale */, - "" /* dictType */, true /* isUpdatable */); + } @Override public DictionaryHeader readHeader() throws IOException, UnsupportedFormatException { - final DictionaryHeader header = mBinaryDictionary.getHeader(); + // dictType is not being used in dicttool. Passing an empty string. + final BinaryDictionary binaryDictionary= new BinaryDictionary( + mDictDirectory.getAbsolutePath(), 0 /* offset */, 0 /* length */, + true /* useFullEditDistance */, null /* locale */, + "" /* dictType */, true /* isUpdatable */); + final DictionaryHeader header = binaryDictionary.getHeader(); + binaryDictionary.close(); if (header == null) { throw new IOException("Cannot read the dictionary header."); } - return mBinaryDictionary.getHeader(); + return header; } @Override public FusionDictionary readDictionaryBinary(final boolean deleteDictIfBroken) throws FileNotFoundException, IOException, UnsupportedFormatException { + // dictType is not being used in dicttool. Passing an empty string. + final BinaryDictionary binaryDictionary = new BinaryDictionary( + mDictDirectory.getAbsolutePath(), 0 /* offset */, 0 /* length */, + true /* useFullEditDistance */, null /* locale */, + "" /* dictType */, true /* isUpdatable */); final DictionaryHeader header = readHeader(); final FusionDictionary fusionDict = new FusionDictionary(new FusionDictionary.PtNodeArray(), header.mDictionaryOptions); @@ -70,11 +77,11 @@ public class Ver4DictDecoder extends AbstractDictDecoder { final ArrayList<WordProperty> wordProperties = CollectionUtils.newArrayList(); do { final BinaryDictionary.GetNextWordPropertyResult result = - mBinaryDictionary.getNextWordProperty(token); + binaryDictionary.getNextWordProperty(token); final WordProperty wordProperty = result.mWordProperty; if (wordProperty == null) { + binaryDictionary.close(); if (deleteDictIfBroken) { - mBinaryDictionary.close(); FileUtils.deleteRecursively(mDictDirectory); } return null; @@ -103,6 +110,7 @@ public class Ver4DictDecoder extends AbstractDictDecoder { fusionDict.setBigram(word0, bigram.mWord, bigram.mProbabilityInfo); } } + binaryDictionary.close(); return fusionDict; } } diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java index 8f7378c58..d3734d693 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java +++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java @@ -68,6 +68,11 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB dumpAllWordsForDebug(); } // Flush pending writes. + flush(); + // TODO: Quit depending on finalize() and really close the dictionary file. + } + + public void flush() { asyncFlushBinaryDictionary(); } 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; } } |